diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.99-pre6/linux/Documentation/Changes	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/Changes	Tue May  2 12:59:39 2000
@@ -787,9 +787,9 @@
 Powertweak
 ==========
 
-The 0.1.2 release:
-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
+The 0.1.13 release:
+http://linux.powertweak.com/files/powertweak-0.1.13.tgz
+ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.13.tgz
 
 Xosview
 =======
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.99-pre6/linux/Documentation/Configure.help	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/Configure.help	Mon May  8 22:21:58 2000
@@ -1830,7 +1830,7 @@
 CONFIG_IP_NF_MATCH_LIMIT
   limit matching allows you to control the rate at which a rule can be
   matched: mainly useful in combination with the LOG target ("LOG
-  target support", below).
+  target support", below) and to avoid some Denial of Service attacks.
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
@@ -6686,6 +6686,14 @@
   Note that the BSD compression code will always be compiled as a
   module; it is called bsd_comp.o and will show up in the directory
   modules once you have said "make modules". If unsure, say N.
+
+PPP over Ethernet (EXPERIMENTAL)
+CONFIG_PPPOE
+  Support for PPP over Ethernet.
+
+  This driver requires a specially patched pppd daemon.  The patch to
+  pppd, along with binaries of a patched pppd package can be found at:
+  http://www.math.uwaterloo.ca/~mostrows
  
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
@@ -9850,7 +9858,7 @@
   Say Y here if you want to connect this type of still camera to
   your computer's USB port. This driver can be used with gphoto 0.4.3
   and higher (look at http://www.gphoto.org ).
-  To use it create a device node with "mknod /dev/mustek c 10 171" and
+  To use it create a device node with "mknod /dev/mustek c 180 32" and
   configure it in your software.
 
   This code is also available as a module ( = code which can be
@@ -10314,6 +10322,15 @@
 
   If unsure, say N.
 
+Enable automatic mounting at boot
+CONFIG_DEVFS_MOUNT
+  This option appears if you have CONFIG_DEVFS_FS enabled. Setting
+  this to 'Y' will make the kernel automatically mount devfs onto /dev
+  when the system is booted, before the init thread is started.
+  You can override this with the "devfs=nomount" boot option.
+
+  If unsure, say N.
+
 Debug devfs
 CONFIG_DEVFS_DEBUG
   If you say Y here, then the /dev file system code will generate
@@ -10444,6 +10461,8 @@
   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.
+  Please note that write support is limited to Windows NT4 and
+  earlier versions.
 
   If unsure, say N.
 
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/IO-APIC.txt linux/Documentation/IO-APIC.txt
--- v2.3.99-pre6/linux/Documentation/IO-APIC.txt	Sun Jul 25 10:26:01 1999
+++ linux/Documentation/IO-APIC.txt	Wed Dec 31 16:00:00 1969
@@ -1,117 +0,0 @@
-Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC',
-which is an enhanced interrupt controller, it enables us to route
-hardware interrupts to multiple CPUs, or to CPU groups.
-
-Linux supports all variants of compliant SMP boards, including ones with
-multiple IO-APICs. (multiple IO-APICs are used in high-end servers to
-distribute IRQ load further).
-
-There are (a few) known breakages in certain older boards, which bugs are
-usually worked around by the kernel. If your MP-compliant SMP board does
-not boot Linux, then consult the linux-smp mailing list archives first.
-
-If your box boots fine with enabled IO-APIC IRQs, then your
-/proc/interrupts will look like this one:
-
-   ---------------------------->
-  hell:~> cat /proc/interrupts
-             CPU0
-    0:    1360293    IO-APIC-edge  timer
-    1:          4    IO-APIC-edge  keyboard
-    2:          0          XT-PIC  cascade
-   13:          1          XT-PIC  fpu
-   14:       1448    IO-APIC-edge  ide0
-   16:      28232   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
-   17:      51304   IO-APIC-level  eth0
-  NMI:          0
-  ERR:          0
-  hell:~>
-  <----------------------------
-
-some interrupts are still listed as 'XT PIC', but this is not a problem,
-none of those IRQ sources is performance-critical.
-
-
-in the unlikely case that your board does not create a working mp-table,
-you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This
-is nontrivial though and cannot be automated. One sample /etc/lilo.conf
-entry:
-
-	append="pirq=15,11,10"
-
-the actual numbers depend on your system, on your PCI cards and on their
-PCI slot position. Usually PCI slots are 'daisy chained' before they are
-connected to the PCI chipset IRQ routing facility (the incoming PIRQ1-4
-lines):
-
-               ,-.        ,-.        ,-.        ,-.        ,-.
-     PIRQ4 ----| |-.    ,-| |-.    ,-| |-.    ,-| |--------| |
-               |S|  \  /  |S|  \  /  |S|  \  /  |S|        |S|
-     PIRQ3 ----|l|-. `/---|l|-. `/---|l|-. `/---|l|--------|l|
-               |o|  \/    |o|  \/    |o|  \/    |o|        |o|
-     PIRQ2 ----|t|-./`----|t|-./`----|t|-./`----|t|--------|t|
-               |1| /\     |2| /\     |3| /\     |4|        |5|
-     PIRQ1 ----| |-  `----| |-  `----| |-  `----| |--------| |
-               `-'        `-'        `-'        `-'        `-'
-
-every PCI card emits a PCI IRQ, which can be INTA,INTB,INTC,INTD:
-
-                               ,-.
-                         INTD--| |
-                               |S|
-                         INTC--|l|
-                               |o|
-                         INTB--|t|
-                               |x|
-                         INTA--| |
-                               `-'
-
-These INTA-D PCI IRQs are always 'local to the card', their real meaning
-depends on which slot they are in. If you look at the daisy chaining diagram,
-a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ2 of
-the PCI chipset. Most cards issue INTA, this creates optimal distribution
-between the PIRQ lines. (distributing IRQ sources properly is not a
-necessity, PCI IRQs can be shared at will, but it's a good for performance
-to have non shared interrupts). Slot5 should be used for videocards, they
-do not use interrupts normally, thus they are not daisy chained either.
-
-so if you have your SCSI card (IRQ11) in Slot1, Tulip card (IRQ9) in
-Slot2, then you'll have to specify this pirq= line:
-
-	append="pirq=11,9"
-
-the following script tries to figure out such a default pirq= line from
-your PCI configuration:
-
-	echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g'
-
-note that this script wont work if you have skipped a few slots or if your
-board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins
-connected in some strange way). E.g. if in the above case you have your SCSI
-card (IRQ11) in Slot3, and have Slot1 empty:
-
-	append="pirq=0,9,11"
-
-[value '0' is a generic 'placeholder', reserved for empty (or non-IRQ emitting)
-slots.]
-
-generally, it's always possible to find out the correct pirq= settings, just
-permute all IRQ numbers properly ... it will take some time though. An
-'incorrect' pirq line will cause the booting process to hang, or a device
-won't function properly (if it's inserted as eg. a module).
-
-If you have 2 PCI buses, then you can use up to 8 pirq values. Although such
-boards tend to have a good configuration.
-
-Be prepared that it might happen that you need some strange pirq line:
-
-	append="pirq=0,0,0,0,0,0,9,11"
-
-use smart try-and-err techniques to find out the correct pirq line ...
-
-good luck and mail to linux-smp@vger.rutgers.edu or
-linux-kernel@vger.rutgers.edu if you have any problems that are not covered
-by this document.
-
--- mingo
-
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.3.99-pre6/linux/Documentation/filesystems/devfs/ChangeLog	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/filesystems/devfs/ChangeLog	Mon May  8 22:00:41 2000
@@ -1496,3 +1496,40 @@
 - Don't kill existing block ops in <devfs_read_inode>
 
 - Restore auto-ownership for /dev/pty/m*
+===============================================================================
+Changes for patch v163
+
+Work sponsored by SGI
+
+- Don't create missing directories in <devfs_find_handle>
+
+- Removed Documentation/filesystems/devfs/mk-devlinks
+
+- Updated Documentation/filesystems/devfs/README
+===============================================================================
+Changes for patch v164
+
+Work sponsored by SGI
+
+- Fixed CONFIG_DEVFS breakage in drivers/char/serial.c introduced in
+  linux-2.3.99-pre6-7
+===============================================================================
+Changes for patch v165
+
+Work sponsored by SGI
+
+- Ported to kernel 2.3.99-pre6
+===============================================================================
+Changes for patch v166
+
+Work sponsored by SGI
+
+- Added CONFIG_DEVFS_MOUNT
+===============================================================================
+Changes for patch v167
+
+Work sponsored by SGI
+
+- Updated Documentation/filesystems/devfs/README
+
+- Updated sample modules.conf
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.3.99-pre6/linux/Documentation/filesystems/devfs/README	Tue Mar  7 14:32:25 2000
+++ linux/Documentation/filesystems/devfs/README	Mon May  8 22:00:41 2000
@@ -1,50 +1,97 @@
-/* -*- auto-fill -*-                                                         */
+Devfs (Device File System) FAQ
 
-		Device File System (devfs) Overview
 
-		Richard Gooch <rgooch@atnf.csiro.au>
+Linux Devfs (Device File System) FAQ
+Richard Gooch
+1-MAY-2000
 
-			      3-MAR-2000
+-----------------------------------------------------------------------------
 
+NOTE: the master copy of this document is available online at:
 
-Conventions used in this document                                     <section>
-=================================
-
-Each section in this document will have the string "<section>" at the
-right-hand side of the section title. Each subsection will have
-"<subsection>" at the right-hand side. These strings are meant to make
-it easier to search through the document.
-
-NOTE that the master copy of this document is available online at:
-http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.txt
+http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
+and looks much better than the text version distributed with the
+kernel sources.
 
 There is also an optional daemon that may be used with devfs. You can
 find out more about it at:
+
 http://www.atnf.csiro.au/~rgooch/linux/
 
-NEWFLASH: The official 2.3.46 kernel has included the devfs
-patch. Future patches will be released which build on this.
+NEWFLASH: The official 2.3.46 kernel has
+included the devfs patch. Future patches will be released which
+build on this.
+
+A mailing list is available which you may subscribe to. Send
+email
+to majordomo@oss.sgi.com with the following line in the
+body of the message:
+subscribe devfs
+The list is archived at
+
+http://oss.sgi.com/projects/devfs/archive/.
+
+-----------------------------------------------------------------------------
+
+Contents
+
+
+What is it?
+
+Why do it?
+
+Who else does it?
+
+How it works
+
+Operational issues (essential reading)
+
+Instructions for the impatient
+Permissions persistence accross reboots
+Dealing with drivers without devfs support
+All the way with Devfs
+Other Issues
+Kernel Naming Scheme
+Devfsd Naming Scheme
+SCSI Host Probing Issues
+
+
+
+Device drivers currently ported
+
+Allocation of Device Numbers
+
+Questions and Answers
+
+Making things work
+Alternatives to devfs
+
+
+Other resources
 
 
-What is it?                                                           <section>
-===========
+-----------------------------------------------------------------------------
+
+
+What is it?
 
 Devfs is an alternative to "real" character and block special devices
 on your root filesystem. Kernel device drivers can register devices by
 name rather than major and minor numbers. These devices will appear in
-the devfs automatically, with whatever default ownership and
-protection the driver specified.
-
-NOTE that devfs is entirely optional. If you prefer the old disc-based
-device nodes, then simply leave CONFIG_DEVFS_FS=n (the default). In
-this case, nothing will change.
-ALSO NOTE that if you do enable devfs, the defaults are such that full
-compatibility is maintained with the old devices names.
+devfs automatically, with whatever default ownership and
+protection the driver specified. A daemon (devfsd) can be used to
+override these defaults.
+
+NOTE that devfs is entirely optional. If you prefer the old
+disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the
+default). In this case, nothing will change.  ALSO NOTE that if you do
+enable devfs, the defaults are such that full compatibility is
+maintained with the old devices names.
 
 There are two aspects to devfs: one is the underlying device
 namespace, which is a namespace just like any mounted filesystem. The
 other aspect is the filesystem code which provides a view of the
-device namespace. The reason I make a distinction is because the devfs
+device namespace. The reason I make a distinction is because devfs
 can be mounted many times, with each mount showing the same device
 namespace. Changes made are global to all mounted devfs filesystems.
 Also, because the devfs namespace exists without any devfs mounts, you
@@ -52,13 +99,20 @@
 devfs namespace.
 
 The cost of devfs is a small increase in kernel code size and memory
-usage. On a typical machine, the cost is under 0.2 percent. On a
-modest system with 64 MBytes of RAM, the cost is under 0.1 percent.
-The accusations of "bloatware" levelled at devfs are not justified.
+usage. About 7 pages of code (some of that in __init sections) and 49
+bytes for each entry in the namespace (93 bytes if you access the
+inode). A modest system has only a couple of hundred device entries,
+so this costs a few more pages. Compare this with the suggestion to
+put /dev on a ramdisc.
 
+On a typical machine, the cost is under 0.2 percent. On a modest
+system with 64 MBytes of RAM, the cost is under 0.1 percent.  The
+accusations of "bloatware" levelled at devfs are not justified.
 
-Why do it?                                                            <section>
-==========
+-----------------------------------------------------------------------------
+
+
+Why do it?
 
 There are several problems that devfs addresses. Some of these
 problems are more serious than others (depending on your point of
@@ -69,8 +123,21 @@
 are complex and likely to be fragile, or to use a simple and efficient
 devfs which is robust.
 
-Major&minor allocation                                             <subsection>
-----------------------
+There have been many counter-proposals to devfs, all seeking to
+provide some of the benefits without actually implementing devfs. So
+far there has been an absence of code and no proposed alternative has
+been able to provide all the features that devfs does. Further,
+alternative proposals require far more complexity in user-space (and
+still deliver less functionality than devfs). Some people have the
+mantra of reducing "kernel bloat", but don't consider the effects on
+user-space.
+
+A good solution limits the total complexity of kernel-space and
+user-space.
+
+
+Major&minor allocation
+
 The existing scheme requires the allocation of major and minor device
 numbers for each and every device. This means that a central
 co-ordinating authority is required to issue these device numbers
@@ -81,8 +148,8 @@
 of the device, there is far less potential for namespace conflict.
 Solving this requires a kernel change.
 
-/dev management                                                    <subsection>
----------------
+/dev management
+
 Because you currently access devices through device nodes, these must
 be created by the system administrator. For standard devices you can
 usually find a MAKEDEV programme which creates all these (hundreds!)
@@ -95,20 +162,24 @@
 duplication of information, which is not good practice.
 Solving this requires a kernel change.
 
-/dev growth                                                        <subsection>
------------
+/dev growth
+
 A typical /dev has over 1200 nodes! Most of these devices simply don't
 exist because the hardware is not available. A huge /dev increases the
 time to access devices (I'm just referring to the dentry lookup times
 and the time taken to read inodes off disc: the next subsection shows
 some more horrors).
+
 An example of how big /dev can grow is if we consider SCSI devices:
+
 host           6  bits  (say up to 64 hosts on a really big machine)
 channel        4  bits  (say up to 16 SCSI buses per host)
 id             4  bits
 lun            3  bits
 partition      6  bits
 TOTAL          23 bits
+
+
 This requires 8 Mega (1024*1024) inodes if we want to store all
 possible device nodes. Even if we scrap everything but id,partition
 and assume a single host adapter with a single SCSI bus and only one
@@ -128,6 +199,7 @@
 available and created them when they were available. This programme
 would need to be run every time a new module was loaded, which would
 slow things down a lot.
+
 There is an existing programme called scsidev which will automatically
 create device nodes for SCSI devices. It can do this by scanning files
 in /proc/scsi. Unfortunately, to extend this idea to other device
@@ -138,14 +210,16 @@
 also provides this information).  Furthermore, such a system would
 likely be implemented in an ad-hoc fashion, as different drivers will
 provide their information in different ways.
+
 Devfs is much cleaner, because it (natually) has a uniform mechanism
 to provide this information: the device nodes themselves!
 
-Node to driver file_operations translation                         <subsection>
-------------------------------------------
-There is an important difference between the way disc-based c&b nodes
-and devfs entries make the connection between an entry in /dev and the
-actual device driver.
+
+Node to driver file_operations translation
+
+There is an important difference between the way disc-based character
+and block nodes and devfs entries make the connection between an entry
+in /dev and the actual device driver.
 
 With the current 8 bit major and minor numbers the connection between
 disc-based c&b nodes and per-major drivers is done through a
@@ -178,7 +252,7 @@
 But why do that search at all if you don't have to? Once again, it
 seems pointless.
 
-Note that the devfs doesn't use the major&minor system. For devfs
+Note thate devfs doesn't use the major&minor system. For devfs
 entries, the connection is done when you lookup the /dev entry. When
 devfs_register() is called, an internal table is appended which has
 the entry name and the file_operations. If the dentry cache doesn't
@@ -192,18 +266,19 @@
 unnecessary entries in a disc-based /dev, the number of conceivable
 entries remains the same: you just limit yourself in order to save
 space.
+
 Devfs provides a fast connection between a VFS node and the device
 driver, in a scalable way.
 
-/dev as a system administration tool                               <subsection>
-------------------------------------
+/dev as a system administration tool
+
 Right now /dev contains a list of conceivable devices, most of which I
 don't have. A devfs would only show those devices available on my
 system. This means that listing /dev would be a handy way of checking
 what devices were available.
 
-Major&minor size                                                   <subsection>
-----------------
+Major&minor size
+
 Existing major and minor numbers are limited to 8 bits each. This is
 now a limiting factor for some drivers, particularly the SCSI disc
 driver, which consumes a single major number. Only 16 discs are
@@ -216,27 +291,42 @@
 compatibility which you would have with increasing major and minor
 number sizes. See the section on "Allocation of Device Numbers" for
 details on maintaining compatibility with userspace.
+
 Solving this requires a kernel change.
 
-Read-only root filesystem                                          <subsection>
-------------------------
+Since writing this, the kernel has been modified so that the SCSI disc
+driver has more major numbers allocated to it and now supports up to
+128 discs. Since these major numbers are non-contiguous (a result of
+unplanned expansion), the implementation is a little more cumbersome
+than originally.
+
+Just like the changes to IPv4 to fix impending limitations in the
+address space, people find ways around the limitations. In the long
+run, however, solutions like IPv6 or devfs can't be put off forever.
+
+Read-only root filesystem
+
 Having your device nodes on the root filesystem means that you can't
 operate properly with a read-only root filesystem. This is because you
 want to change ownerships and protections of tty devices. Existing
 practice prevents you using a CD-ROM as your root filesystem for a
 *real* system. Sure, you can boot off a CD-ROM, but you can't change
 tty ownerships, so it's only good for installing.
+
 Also, you can't use a shared NFS root filesystem for a cluster of
 discless Linux machines (having tty ownerships changed on a common
 /dev is not good). Nor can you embed your root filesystem in a
 ROM-FS.
+
 You can get around this by creating a RAMDISC at boot time, making
 an ext2 filesystem in it, mounting it somewhere and copying the
 contents of /dev into it, then unmounting it and mounting it over
-/dev. A devfs is a cleaner way of solving this.
+/dev.
+
+A devfs is a cleaner way of solving this.
+
+Non-Unix root filesystem
 
-Non-Unix root filesystem                                           <subsection>
-------------------------
 Non-Unix filesystems (such as NTFS) can't be used for a root
 filesystem because they variously don't support character and block
 special files or symbolic links. You can't have a separate disc-based
@@ -248,20 +338,24 @@
 nodes), and then construct a new /dev in another RAMDISC, and finally
 switch to your non-Unix root filesystem. This requires clever boot
 scripts and a fragile and conceptually complex boot procedure.
+
 Devfs solves this in a robust and conceptually simple way.
 
-PTY security                                                       <subsection>
-------------
+PTY security
+
 Current pseudo-tty (pty) devices are owned by root and read-writable
 by everyone. The user of a pty-pair cannot change
 ownership/protections without being suid-root.
+
 This could be solved with a secure user-space daemon which runs as
 root and does the actual creation of pty-pairs. Such a daemon would
 require modification to *every* programme that wants to use this new
 mechanism. It also slows down creation of pty-pairs.
+
 An alternative is to create a new open_pty() syscall which does much
 the same thing as the user-space daemon. Once again, this requires
 modifications to pty-handling programmes.
+
 The devfs solution allows a device driver to "tag" certain device
 files so that when an unopened device is opened, the ownerships are
 changed to the current euid and egid of the opening process, and the
@@ -272,8 +366,8 @@
 ptys. It doesn't support old-style pty devices, nor does it have all
 the other features of devfs.
 
-Intelligent device management                                      <subsection>
------------------------------
+Intelligent device management
+
 Devfs implements a simple yet powerful protocol for communication with
 a device management daemon (devfsd) which runs in user space. It is
 possible to send a message (either synchronously or asynchronously) to
@@ -281,7 +375,9 @@
 entries, opening and closing devices, looking up inodes, scanning
 directories and more. This has many possibilities. Some of these are
 already implemented.
-See: http://www.atnf.csiro.au/~rgooch/linux/
+
+See: 
+http://www.atnf.csiro.au/~rgooch/linux/
 
 Device entry registration events can be used by devfsd to change
 permissions of newly-created device nodes. This is one mechanism to
@@ -314,15 +410,15 @@
 system conditions instead of just the UID and GID.
 
 Inode lookup events can be used to authenticate module autoload
-requests. Instead of using kmod directly, the event can be sent to
+requests. Instead of using kmod directly, the event is sent to
 devfsd which can implement an arbitrary authentication before loading
 the module itself.
 Inode lookup events can also be used to construct arbitrary
 namespaces, without having to resort to populating devfs with symlinks
 to devices that don't exist.
 
-Speculative Device Scanning                                        <subsection>
----------------------------
+Speculative Device Scanning
+
 Consider an application (like cdparanoia) that wants to find all
 CD-ROM devices on the system (SCSI, IDE and other types), whether or
 not their respective modules are loaded. The application must
@@ -340,31 +436,33 @@
 solution like scsidev could reduce the number of /dev/sr* entries (but
 of course that also requires all that inefficient directory scanning).
 
-With devfs, the application can open the /dev/sr directory (which
-triggers the module autoloading if required), and proceed to read
-/dev/sr. Since only the available devices will have entries, there are
-no inefficencies in directory scanning or device openings.
-
-
-Who else does it?                                                     <section>
-=================
-
-FreeBSD-current now has a devfs implementation. Solaris 2 has a
-pseudo-devfs (something akin to scsidev but for all devices, with some
-unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's
-IRIX 6.4 and above also have a device filesystem.
+With devfs, the application can open the /dev/sr directory
+(which triggers the module autoloading if required), and proceed to
+read /dev/sr. Since only the available devices will have
+entries, there are no inefficencies in directory scanning or device
+openings.
+
+-----------------------------------------------------------------------------
+
+Who else does it?
+
+FreeBSD has a devfs implementation. Solaris 2 has a pseudo-devfs
+(something akin to scsidev but for all devices, with some unspecified
+kernel support). BeOS, Plan9 and QNX also have it. SGI's IRIX 6.4 and
+above also have a device filesystem.
 
 While we shouldn't just automatically do something because others do
 it, we should not ignore the work of others either. FreeBSD has a lot
 of competent people working on it, so their opinion should not be
 blithely ignored.
 
+-----------------------------------------------------------------------------
+
+
+How it works
 
-How it works                                                          <section>
-============
+Registering device entries
 
-Registering device entries                                         <subsection>
---------------------------
 For every entry (device node) in a devfs-based /dev a driver must call
 devfs_register(). This adds the name of the device entry, the
 file_operations structure pointer and a few other things to an
@@ -372,18 +470,18 @@
 time. When a device entry is registered, it automagically appears in
 any mounted devfs'.
 
-Inode lookup                                                       <subsection>
-------------
+Inode lookup
+
 When a lookup operation on an entry is performed and if there is no
-driver information for that entry devfs will attempt to call devfsd or
-kmod. If still no driver information can be found then a negative
+driver information for that entry devfs will attempt to call
+devfsd. If still no driver information can be found then a negative
 dentry is yielded and the next stage operation will be called by the
 VFS (such as create() or mknod() inode methods). If driver information
 can be found, an inode is created (if one does not exist already) and
 all is well.
 
-Manually creating device nodes                                     <subsection>
-------------------------------
+Manually creating device nodes
+
 The mknod() method allows you to create an ordinary named pipe in the
 devfs, or you can create a character or block special inode if one
 does not already exist. You may wish to create a character or block
@@ -393,72 +491,214 @@
 the protections on a device even before the driver is loaded. Once you
 create an inode it appears in the directory listing.
 
-Unregistering device entries                                       <subsection>
-----------------------------
+Unregistering device entries
+
 A device driver calls devfs_unregister() to unregister an entry.
 
-Chroot() gaols                                                     <subsection>
---------------
-The semantics of inode creation are different when the devfs is
-mounted with the "explicit" option. Now, when a device entry is
-registered, it will not appear until you use mknod() to create the
-device. It doesn't matter if you mknod() before or after the device is
-registered with devfs_register(). The purpose of this behaviour is to
-support chroot(2) gaols, where you want to mount a minimal devfs
-inside the gaol. Only the devices you specifically want to be
-available (through your mknod() setup) will be accessible.
+Chroot() gaols
+
+The semantics of inode creation are different when devfs is mounted
+with the "explicit" option. Now, when a device entry is registered, it
+will not appear until you use mknod() to create the device. It doesn't
+matter if you mknod() before or after the device is registered with
+devfs_register(). The purpose of this behaviour is to support
+chroot(2) gaols, where you want to mount a minimal devfs inside the
+gaol. Only the devices you specifically want to be available (through
+your mknod() setup) will be accessible.
+
+-----------------------------------------------------------------------------
+
+
+Operational issues
+
+
+Instructions for the impatient
+
+Nobody likes reading documentation. People just want to get in there
+and play. So this section tells you quickly the steps you need to take
+to run with devfs mounted over /dev. Skip these steps and you will end
+up with a nearly unbootable system. Subsequent sections describe the
+issues in more detail, and discuss non-essential configuration
+options.
+
+Devfsd
+OK, if you're reading this, I assume you want to play with
+devfs. First you need to compile devfsd, the device management daemon,
+available at 
+http://www.atnf.csiro.au/~rgooch/linux/.
+Because the kernel has a naming scheme
+which is quite different from the old naming scheme, you need to
+install devfsd so that software and configuration files that use the
+old naming scheme will not break.
+
+Compile and install devfsd. You will be provided with a default
+configuration file /etc/devfsd.conf which will provide
+compatibility symlinks for the old naming scheme. Don't change this
+config file unless you know what you're doing. Even if you think you
+do know what you're doing, don't change it until you've followed all
+the steps below and booted a devfs-enabled system and verified that it
+works.
+
+Now edit your main system boot script so that devfsd is started at the
+very beginning (before any filesystem
+checks). /etc/rc.d/rc.sysinit is often the main boot script
+on systems with SysV-style boot scripts. On systems with BSD-style
+boot scripts it is often /etc/rc. Also check
+/sbin/rc.
+
+NOTE that the line you put into the boot
+script should be exactly:
+
+/sbin/devfsd /dev
+
+DO NOT use some special daemon-launching
+programme, otherwise the boot script may not wait for devfsd to finish
+initialising.
+
+System Libraries
+There may still be some problems because of broken software making
+assumptions about device names. In particular, some software does not
+handle devices which are symbolic links. If you are running a libc 5
+based system, install libc 5.4.44 (if you have libc 5.4.46, go back to
+libc 5.4.44, which is actually correct). If you are running a glibc
+based system, make sure you have glibc 2.1.3 or later.
+
+/etc/securetty
+PAM (Pluggable Authentication Modules) is supposed to be a flexible
+mechanism for providing better user authentication and access to
+services. Unfortunately, it's also fragile, complex and undocumented
+(check out RedHat 6.1, and probably other distributions as well). PAM
+has problems with symbolic links. Append the following lines to your
+/etc/securetty file:
+
+1
+2
+3
+4
+5
+6
+7
+8
+
+This may potentially weaken security by allowing root logins over the
+network (a password is still required, though). However, since there
+are problems with dealing with symlinks, I'm suspicious of the level
+of security offered in any case.
+
+XFree86
+While not essential, it's probably a good idea to upgrade to XFree86
+4.0, as patches went in to make it more devfs-friendly. If you don't,
+you'll probably need to apply the following patch to
+/etc/security/console.perms so that ordinary users can run
+startx.
+
+--- /etc/security/console.perms.orig    Sat Apr 17 16:26:47 1999 
++++ /etc/security/console.perms Fri Feb 25 23:53:55 2000 
+@@ -14,7 +14,7 @@ 
+ # man 5 console.perms 
+
+ # file classes -- these are regular expressions 
+-=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
++=tty[0-9][0-9]* [0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
+
+ # device classes -- these are shell-style globs 
+ =/dev/fd[0-1]* 
+
+
+Disable devpts
+I've had a report of devpts mounted on /dev/pts not working
+correctly. Since devfs will also manage /dev/pts, there is no
+need to mount devpts as well. You should either edit your
+/etc/fstab so devpts is not mounted, or disable devfs from
+your kernel configuration.
+
+Unsupported drivers
+Not all drivers have devfs support. If you depend on one of these
+drivers, you will need to create a script or tarfile that you can use
+at boot time to create device nodes as appropriate. There is a
+section which describes this. Another
+section lists the drivers which have
+devfs support.
+
+/dev/mouse
+
+Many disributions configure /dev/mouse to be the mouse device
+for XFree86 and GPM. I actually think this is a bad idea, because it
+adds another level of indirection. When looking at a config file, if
+you see /dev/mouse you're left wondering which mouse
+is being referred to. Hence I recommend putting the actual mouse
+device (for example /dev/psaux) into your
+/etc/X11/XF86Config file (and similarly for the GPM
+configuration file).
+
+Alternatively, use the same technique used for unsupported drivers
+described above.
+
+The Kernel
+Finally, you need to make sure devfs is compiled into your
+kernel. Set CONFIG_DEVFS_FS=y and recompile your kernel. Next, you
+need to make sure devfs is mounted. The best solution is to pass
+devfs=mount at the kernel boot command line. You can edit
+/etc/lilo.conf and add the line:
+
+append = "devfs=mount"
+
+
+This will make the kernel mount devfs at boot time onto /dev.
+
+Now you've finished all the steps required. You're now ready to boot
+your shiny new kernel. Enjoy.
+
+Changing the configuration
+
+OK, you've now booted a devfs-enabled system, and everything works.
+Now you may feel like changing the configuration (common targets are
+/etc/fstab and /etc/devfsd.conf). Since you have a
+system that works, if you make any changes and it doesn't work, you
+now know that you only have to restore your configuration files to the
+default and it will work again.
 
 
-Persistence of ownership/permissions across reboots                   <section>
-===================================================
+Permissions persistence across reboots
 
 If you don't use mknod(2) to create a device file, nor use chmod(2) or
 chown(2) to change the ownerships/permissions, the inode ctime will
 remain at 0 (the epoch, 12 am, 1-JAN-1970, GMT). Anything with a ctime
 later than this has had it's ownership/permissions changed. Hence, a
 simple script or programme may be used to tar up all changed inodes,
-prior to shutdown.
+prior to shutdown. Although effective, many consider this approach a
+kludge.
 
-Upon bootup, simply untar the previously created tarfile, and all your
-ownerships/permissions will be retained. For the paranoid, you can
-save your permissions periodically using a cron job.
-
-NOTE: tar will first unlink(2) an inode before creating a new device
-node. The unlink(2) has the effect of breaking the connection between
-a devfs entry and the device driver. If you use the "devfs=only" boot
-option, you lose access to the device driver, requiring you to reload
-the module. I consider this a bug in tar (there is no real need to
+A much better approach is to use devfsd to save and restore
+permissions. It may be configured to record changes in permissions and
+will save them in a database (in fact a directory tree), and restore
+these upon boot. This is an efficient method and results in immediate
+saving of current permissions (unlike the tar approach, which save
+permissions at some unspecified future time).
+
+The default configuration file supplied with devfsd has config entries
+which you may uncomment to enable persistence management.
+
+If you decide to use the tar approach anyway, be aware that tar will
+first unlink(2) an inode before creating a new device node. The
+unlink(2) has the effect of breaking the connection between a devfs
+entry and the device driver. If you use the "devfs=only" boot option,
+you lose access to the device driver, requiring you to reload the
+module. I consider this a bug in tar (there is no real need to
 unlink(2) the inode first).
 
-I've provided a script called "rc.devfs" in this directory which you
-can use to save and restore permissions.
-
-Alternatively, you can use the device management daemon (devfsd) to
-control the permissions of device nodes. This has the advantage of
-being able to store permissions for whole groups of devices with a
-single configuration entry, rather than one (tar) entry per device
-node. Devfsd also receives inode change events, so you could easily
-implement a simple permissions database.
+Alternatively, you can use devfsd to provide more sophisticated
+management of device permissions. You can use devfsd to store
+permissions for whole groups of devices with a single configuration
+entry, rather than the conventional single entry per device entry.
 
 
-Installation during the transition phase                              <section>
-========================================
+Dealing with drivers without devfs support
 
 Currently, not all device drivers in the kernel have been modified to
-use devfs. If you want to boot between kernels with and without devfs
-support, this section discusses some options. Either way is safe,
-although some people will have different preferences.
-
-Note that your old-style (i.e. node-based) chroot /gaol/dev
-directories which you manually created will still work, unless you
-pass the "devfs=only" boot option.
-
-Fail-safe Approach with devfs mounted on /dev                      <subsection>
----------------------------------------------
-The default is for devfs to be mounted onto /dev at boot time.
-Device drivers which do not yet have devfs support will not
-automagically appear in the devfs. The simplest way to create device
-nodes for these drivers is to unpack a tarfile containing the required
+use devfs. Device drivers which do not yet have devfs support will not
+automagically appear in devfs. The simplest way to create device nodes
+for these drivers is to unpack a tarfile containing the required
 device nodes. You can do this in your boot scripts. All your drivers
 will now work as before.
 
@@ -466,7 +706,7 @@
 can mount devfs directly over /dev without loosing most functionality
 (i.e. loosing access to various devices). As of 22-JAN-1998 (devfs
 patch version 10) I am now running this way. All the devices I have
-are available in the devfs, so I don't lose anything.
+are available in devfs, so I don't lose anything.
 
 WARNING: if your configuration requires the old-style device names
 (i.e. /dev/hda1 or /dev/sda1), you must install devfsd and configure
@@ -478,7 +718,7 @@
 as devfs can manage /dev/pts itself. This saves you some RAM, as you
 don't need to compile and install devpts. Note that some versions of
 glibc have a bug with Unix98 pty handling on devfs systems. Contact
-the glibc maintainers for a fix.
+the glibc maintainers for a fix. Glibc 2.1.3 should have the fix.
 
 Note also that apart from editing /etc/fstab, other things will need
 to be changed if you *don't* install devfsd. Some software (like the X
@@ -487,6 +727,7 @@
 You can then slowly migrate your system to using the new device names
 (for example, by starting with /etc/fstab), and then limiting the
 compatibility entries that devfsd creates.
+
 MAKE SURE YOU INSTALL DEVFSD BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
 
 Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of
@@ -497,30 +738,8 @@
 bugs/false assumptions in other code (i.e. glibc, X server) and submit
 that to the respective maintainers, that would be great.
 
-Fail-safe Approach with real /dev inodes                           <subsection>
-----------------------------------------
-This method involves more work, and is no longer recommended now that
-a large number of drivers have devfs support. You will need to use the
-"devfs=nomount" boot option.
-
-Copy the contents of /dev to /devfs. Then remove entries in /dev
-which are now available in devfs and make them symbolic links to the
-entries in /devfs.  Finally, edit your /etc/fstab or boot scripts so
-that devfs is mounted over /devfs on bootup. If devfs is supported,
-accessing devices supported by devfs will follow the symlinks to
-devfs. If devfs is not supported, accessing those same devices will
-follow the symlinks to /devfs which contains only old-style device
-nodes.  Devices not supported by devfs will be found directly on /dev.
-Simple! You can also follow this principle for chroot gaols.
-
-I've provided a demonstration script called "mk-devlinks" in this
-directory which you can use to create symlinks in /dev and
-/devfs. Note that this script is out of date and should not be run
-without modification.
-
 
-All the way with Devfs                                                <section>
-======================
+All the way with Devfs
 
 The devfs kernel patch creates a rationalised device tree. As stated
 above, if you want to keep using the old /dev naming scheme, you just
@@ -542,24 +761,49 @@
 library or use Unix98 ptys instead). It's just a matter of putting in
 the correct regular expression into /dev/devfsd.conf.
 
+There are other choices of naming schemes that you may prefer. For
+example, I don't use the kernel-supplied
+names, because they are too verbose. A common misconception is
+that the kernel-supplied names are meant to be used directly in
+configuration files. This is not the case. They are designed to
+reflect the layout of the devices attached and to provide easy
+classification.
+
+If you like the kernel-supplied names, that's fine. If you don't then
+you should be using devfsd to construct a namespace more to your
+liking. Devfsd has built-in code to construct a
+namespace that is both logical and easy to
+manage. In essence, it creates a convenient abbreviation of the
+kernel-supplied namespace.
+
+You are of course free to build your own namespace. Devfsd has all the
+infrastructure required to make this easy for you. All you need do is
+write a script. You can even write some C code and devfsd can load the
+shared object as a callable extension.
+
+
+Other Issues
+
+The init programme
+Another thing to take note of is whether your init programme
+creates a Unix socket /dev/telinit. Some versions of init
+create /dev/telinit so that the telinit programme can
+communicate with the init process. If you have such a system you need
+to make sure that devfs is mounted over /dev *before* init
+starts. In other words, you can't leave the mounting of devfs to
+/etc/rc, since this is executed after init. Other
+versions of init require a named pipe /dev/initctl
+which must exist *before* init starts. Once again, you need to
+mount devfs and then create the named pipe *before* init
+starts.
+
+The default behaviour now is not to mount devfs onto /dev at boot time.
+You can correct this with the "devfs=mount" boot option. This solves
+any problems with init, and also prevents the dreaded:
 
-Other Issues                                                          <section>
-============
+Cannot open initial console
 
-Another thing to take note of is whether your init programme creates a
-Unix socket /dev/telinit. Some versions of init create /dev/telinit so
-that the <telinit> programme can communicate with the init process. If
-you have such a system you need to make sure that devfs is mounted
-over /dev *before* init starts. In other words, you can't leave the
-mounting of devfs to /etc/rc, since this is executed after init.
-Other versions of init require a named pipe /dev/initctl which must
-exist *before* init starts. Once again, you need to mount devfs and
-then create the named pipe *before* init starts.
-
-The default behaviour now is to mount devfs onto /dev at boot time.
-You can disable this with the "devfs=nomount" boot option, but you can
-then get harmless but annoying messages about not being able to open
-an initial console.
+message.
 
 If you have automatic mounting of devfs onto /dev then you may need to
 create /dev/initctl in your boot scripts. The following lines should
@@ -582,30 +826,39 @@
 [control-D]
 # chmod a+x init
 
-Note that newer versions of init create /dev/initctl automatically, so
-you don't have to worry about this.
+Note that newer versions of init create /dev/initctl
+automatically, so you don't have to worry about this.
+
+Module autoloading
+Another thing to note is that if you want to support module
+autoloading then you need to edit your /etc/modules.conf so
+that things work properly. You should include the sample
+modules.conf file in the
+Documentation/filesystems/devfs directory into your
+/etc/modules.conf to ensure correct operation.
 
-Using kmod (module autoloading)                                    <subsection>
--------------------------------
-Another thing to note is that if you are using kmod then you need to
-edit your /etc/modules.conf so that things work properly. You should
-include the sample modules.conf file in the
-Documentation/filesystems/devfs directory into your /etc/modules.conf
-to ensure correct operation.
+You will also need to configure devfsd to enable module
+autoloading. The following lines should be placed in your
+/etc/devfsd.conf:
 
-Mounting root off a devfs device                                   <subsection>
---------------------------------
+LOOKUP	.*		MODLOAD
+
+
+Mounting root off a devfs device
 If you wish to mount root off a devfs device when you pass the
-"devfs=only" boot option, then you need to pass in the "root=<device>"
+"devfs=only" boot option, then you need to pass in the "root="
 option to the kernel when booting. If you use LILO, then you must have
 this in lilo.conf:
-append = "root=<device>"
+
+append = "root="
 
 Surprised? Yep, so was I. It turns out if you have (as most people
 do):
-root = <device>
 
-then LILO will determine the device number of <device> and will write
+root = 
+
+
+then LILO will determine the device number of  and will write
 that device number into a special place in the kernel image before
 starting the kernel, and the kernel will use that device number to
 mount the root filesystem. So, using the "append" variety ensures that
@@ -614,104 +867,64 @@
 
 Note that this isn't an issue if you don't pass "devfs=only".
 
-TTY issues                                                         <subsection>
-----------
-You may replace your tty devices in /dev with symbolic links to /devfs
-however you will then find that programmes which depend on ttyname(3)
-will no longer work properly. The <tty> programme is a good
-example. I've written a patch to libc 5.4.43 which fixes this. This
-has been included in libc 5.4.44 and glibc 2.1.?
+TTY issues
+The ttyname(3) function in some versions of the C library makes
+false assumptions about device entries which are symbolic links.  The
+tty(1) programme is one that depends on this function.  I've
+written a patch to libc 5.4.43 which fixes this. This has been
+included in libc 5.4.44 and a similar fix is in glibc 2.1.3.
+
+
+Kernel Naming Scheme
+
+The kernel provides a default naming scheme. This scheme is designed
+to make it easy to search for specific devices or device types, and to
+view the available devices. Some device types (such as hard discs),
+have a directory of entries, making it easy to see what devices of
+that class are available. Often, the entries are symbolic links into a
+directory tree that reflects the topology of available devices. The
+topological tree is useful for finding how your devices are arranged.
 
-
-Device drivers currently ported                                       <section>
-===============================
-
-- All miscellaneous character devices support devfs (this is done
-  transparently through misc_register())
-
-- SCSI discs and generic hard discs
-
-- Character memory devices (null, zero, full and so on)
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- Loop devices (/dev/loop?)
- 
-- TTY devices (console, serial ports, terminals and pseudo-terminals)
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- SCSI tapes (/dev/scsi and /dev/tapes)
-
-- SCSI CD-ROMs (/dev/scsi and /dev/cdroms)
-
-- SCSI generic devices (/dev/scsi)
-
-- RAMDISCS (/dev/ram?)
-
-- Meta Devices (/dev/md*)
-
-- Floppy discs (/dev/floppy)
-
-- Parallel port printers (/dev/printers)
-
-- Sound devices (/dev/sound)
-  Thanks to Eric Dumas <dumas@linux.eu.org> and
-  C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- Joysticks (/dev/joysticks)
-
-- Sparc keyboard (/dev/kbd)
-
-- DSP56001 digital signal processor (/dev/dsp56k)
-
-- Apple Desktop Bus (/dev/adb)
-
-- Coda network file system (/dev/cfs*)
-
-- Virtual console capture devices (/dev/vcc)
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Frame buffer devices (/dev/fb)
-
-- Video capture devices (/dev/v4l)
-
-
-Naming Scheme                                                         <section>
-=============
-
-Disc Devices                                                       <subsection>
-------------
+Disc Devices
 
 All discs, whether SCSI, IDE or whatever, are placed under the
 /dev/discs hierarchy:
+
 	/dev/discs/disc0	first disc
 	/dev/discs/disc1	second disc
 
+
 Each of these entries is a symbolic link to the directory for that
 device. The device directory contains:
+
 	disc	for the whole disc
 	part*	for individual partitions
 
-CD-ROM Devices                                                     <subsection>
---------------
+
+CD-ROM Devices
 
 All CD-ROMs, whether SCSI, IDE or whatever, are placed under the
 /dev/cdroms hierarchy:
+
 	/dev/cdroms/cdrom0	first CD-ROM
 	/dev/cdroms/cdrom1	second CD-ROM
 
+
 Each of these entries is a symbolic link to the real device entry for
 that device.
 
-Tape Devices                                                       <subsection>
-------------
+Tape Devices
 
 All tapes, whether SCSI, IDE or whatever, are placed under the
 /dev/tapes hierarchy:
+
 	/dev/tapes/tape0	first tape
 	/dev/tapes/tape1	second tape
 
+
 Each of these entries is a symbolic link to the directory for that
 device. The device directory contains:
+
 	mt			for mode 0
 	mtl			for mode 1
 	mtm			for mode 2
@@ -721,20 +934,25 @@
 	mtmn			for mode 2, no rewind
 	mtan			for mode 3, no rewind
 
-SCSI Devices                                                       <subsection>
-------------
+
+SCSI Devices
+
 To uniquely identify any SCSI device requires the following
 information:
+
   controller	(host adapter)
   bus		(SCSI channel)
   target	(SCSI ID)
   unit		(Logical Unit Number)
 
-All SCSI devices are placed under /dev/scsi (assuming devfs is mounted
-on /dev). Hence, a SCSI device with the following parameters:
-c=1,b=2,t=3,u=4 would appear as:
+
+All SCSI devices are placed under /dev/scsi (assuming devfs
+is mounted on /dev). Hence, a SCSI device with the following
+parameters: c=1,b=2,t=3,u=4 would appear as:
+
 	/dev/scsi/host1/bus2/target3/lun4	device directory
 
+
 Inside this directory, a number of device entries may be created,
 depending on which SCSI device-type drivers were installed.
 
@@ -745,32 +963,38 @@
 tape driver creates.
 
 The SCSI CD-ROM driver creates:
+
 	cd
 
+
 The SCSI generic driver creates:
+
 	generic
 
-IDE Devices                                                        <subsection>
------------
+
+IDE Devices
+
 To uniquely identify any IDE device requires the following
 information:
+
   controller
   bus		(aka. primary/secondary)
   target	(aka. master/slave)
   unit
 
-All IDE devices are placed under /dev/ide (assuming devfs is mounted
-on /dev), and uses a similar naming scheme to the SCSI subsystem.
 
+All IDE devices are placed under /dev/ide, and uses a similar
+naming scheme to the SCSI subsystem.
+
+XT Hard Discs
+
+All XT discs are placed under /dev/xd. The first XT disc has
+the directory /dev/xd/disc0.
 
-XT Hard Discs                                                      <subsection>
--------------
-All XT discs are placed under /dev/xd (assuming devfs is mounted on
-/dev). The first XT disc has the directory /dev/xd/disc0
+TTY devices
 
-TTY devices                                                        <subsection>
------------
 The tty devices now appear as:
+
   New name                   Old-name                   Device Type
   --------                   --------                   -----------
   /dev/tts/{0,1,...}         /dev/ttyS{0,1,...}         Serial ports
@@ -780,33 +1004,133 @@
   /dev/pty/m{0,1,...}        /dev/ptyp??                PTY masters
   /dev/pty/s{0,1,...}        /dev/ttyp??                PTY slaves
 
-RAMDISCS                                                           <subsection>
---------
+
+RAMDISCS
+
 The RAMDISCS are placed in their own directory, and are named thus:
+
   /dev/rd/{0,1,2,...}
 
-Meta Devices                                                       <subsection>
-------------
+
+Meta Devices
+
 The meta devices are placed in their own directory, and are named
 thus:
+
   /dev/md/{0,1,2,...}
 
-Floppy discs                                                       <subsection>
-------------
+
+Floppy discs
+
 Floppy discs are placed in the /dev/floppy directory.
 
-Loop devices                                                       <subsection>
-------------
+Loop devices
+
 Loop devices are placed in the /dev/loop directory.
 
-Sound devices                                                      <subsection>
--------------
-Sound devices are placed in the /dev/sound directory (audio,
-sequencer, ...).
+Sound devices
+
+Sound devices are placed in the /dev/sound directory
+(audio, sequencer, ...).
+
+
+Devfsd Naming Scheme
+
+Devfsd provides a naming scheme which is a convenient abbreviation of
+the kernel-supplied namespace. In some
+cases, the kernel-supplied naming scheme is quite convenient, so
+devfsd does not provide another naming scheme. The convenience names
+that devfsd creates are in fact the same names as the original devfs
+kernel patch created (before Linus mandated the Big Name Change).
+
+In order to configure devfsd to create these convenience names, the
+following lines should be placed in your /etc/devfsd.conf:
+
+REGISTER	.*		MKNEWCOMPAT
+UNREGISTER	.*		RMNEWCOMPAT
+
+This will cause devfsd to create (and destroy) symbolic links which
+point to the kernel-supplied names.
+
+SCSI Hard Discs
+
+All SCSI discs are placed under /dev/sd (assuming devfs is
+mounted on /dev). Hence, a SCSI disc with the following
+parameters: c=1,b=2,t=3,u=4 would appear as:
+
+	/dev/sd/c1b2t3u4	for the whole disc
+	/dev/sd/c1b2t3u4p5	for the 5th partition
+	/dev/sd/c1b2t3u4p5s6	for the 6th slice in the 5th partition
+
+
+SCSI Tapes
+
+All SCSI tapes are placed under /dev/st. A similar naming
+scheme is used as for SCSI discs. A SCSI tape with the
+parameters:c=1,b=2,t=3,u=4 would appear as:
 
+	/dev/st/c1b2t3u4m0	for mode 0
+	/dev/st/c1b2t3u4m1	for mode 1
+	/dev/st/c1b2t3u4m2	for mode 2
+	/dev/st/c1b2t3u4m3	for mode 3
+	/dev/st/c1b2t3u4m0n	for mode 0, no rewind
+	/dev/st/c1b2t3u4m1n	for mode 1, no rewind
+	/dev/st/c1b2t3u4m2n	for mode 2, no rewind
+	/dev/st/c1b2t3u4m3n	for mode 3, no rewind
 
-SCSI Host Probing Issues                                              <section>
-========================
+
+SCSI CD-ROMs
+
+All SCSI CD-ROMs are placed under /dev/sr. A similar naming
+scheme is used as for SCSI discs. A SCSI CD-ROM with the
+parameters:c=1,b=2,t=3,u=4 would appear as:
+
+	/dev/sr/c1b2t3u4
+
+
+SCSI Generic Devices
+
+All SCSI CD-ROMs are placed under /dev/sg. A similar naming
+scheme is used as for SCSI discs. A SCSI generic device with the
+parameters:c=1,b=2,t=3,u=4 would appear as:
+
+	/dev/sg/c1b2t3u4
+
+
+IDE Hard Discs
+
+All IDE discs are placed under /dev/ide/hd, using a similar
+convention to SCSI discs. The following mappings exist between the new
+and the old names:
+
+	/dev/hda	/dev/ide/hd/c0b0t0u0
+	/dev/hdb	/dev/ide/hd/c0b0t1u0
+	/dev/hdc	/dev/ide/hd/c0b1t0u0
+	/dev/hdd	/dev/ide/hd/c0b1t1u0
+
+
+IDE Tapes
+
+A similar naming scheme is used as for IDE discs. The entries will
+appear in the /dev/ide/mt directory.
+
+IDE CD-ROM
+
+A similar naming scheme is used as for IDE discs. The entries will
+appear in the /dev/ide/cd directory.
+
+IDE Floppies
+
+A similar naming scheme is used as for IDE discs. The entries will
+appear in the /dev/ide/fd directory.
+
+XT Hard Discs
+
+All XT discs are placed under /dev/xd. The first XT disc
+would appear as /dev/xd/c0t0.
+
+
+SCSI Host Probing Issues
 
 Devfs allows you to identify SCSI discs based in part on SCSI host
 numbers. If you have only one SCSI host (card) in your computer, then
@@ -818,14 +1142,16 @@
 you to specify the probe order for different types of SCSI hosts. The
 syntax of this parameter is:
 
-scsihosts=<name_1>:<name_2>:<name_3>:...:<name_n>
+scsihosts=:::...:
 
-where <name_1>,<name_2>,...,<name_n> are the names of drivers used in
+where ,,..., are the names of drivers used in
 /proc filesystem. For example:
 
     scsihosts=aha1542:ppa:aha1542::ncr53c7xx
 
+
 means that devices connected to
+
 - first aha1542 controller   - will be c0b#t#u#
 - first parallel port ZIP    - will be c1b#t#u#
 - second aha1542 controller  - will be c2b#t#u#
@@ -835,23 +1161,80 @@
   not be used by any other device.
 - c3b#t#u# names will never be used
 
+
 You can use ',' instead of ':' as the separator character if you
-wish.
+wish. I have used the devfsd naming scheme
+here.
 
 Note that this scheme does not address the SCSI host order if you have
 multiple cards of the same type (such as NCR53c8xx). In this case you
 need to use the driver-specific boot parameters to control this.
 
+-----------------------------------------------------------------------------
+
+
+Device drivers currently ported
+
+- All miscellaneous character devices support devfs (this is done
+  transparently through misc_register())
+
+- SCSI discs and generic hard discs
+
+- Character memory devices (null, zero, full and so on)
+  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
+
+- Loop devices (/dev/loop?)
+ 
+- TTY devices (console, serial ports, terminals and pseudo-terminals)
+  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
+
+- SCSI tapes (/dev/scsi and /dev/tapes)
+
+- SCSI CD-ROMs (/dev/scsi and /dev/cdroms)
+
+- SCSI generic devices (/dev/scsi)
+
+- RAMDISCS (/dev/ram?)
+
+- Meta Devices (/dev/md*)
+
+- Floppy discs (/dev/floppy)
+
+- Parallel port printers (/dev/printers)
+
+- Sound devices (/dev/sound)
+  Thanks to Eric Dumas <dumas@linux.eu.org> and
+  C. Scott Ananian <cananian@alumni.princeton.edu>
+
+- Joysticks (/dev/joysticks)
+
+- Sparc keyboard (/dev/kbd)
+
+- DSP56001 digital signal processor (/dev/dsp56k)
+
+- Apple Desktop Bus (/dev/adb)
+
+- Coda network file system (/dev/cfs*)
+
+- Virtual console capture devices (/dev/vcc)
+  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
+
+- Frame buffer devices (/dev/fb)
+
+- Video capture devices (/dev/v4l)
+
+
+-----------------------------------------------------------------------------
 
-Allocation of Device Numbers                                          <section>
-============================
+
+Allocation of Device Numbers
 
 Devfs allows you to write a driver which doesn't need to allocate a
 device number (major&minor numbers) for the internal operation of the
 kernel. However, there are a number of userspace programmes that use
 the device number as a unique handle for a device. An example is the
-<find> programme, which uses device numbers to determine whether an
-inode is on a different filesystem than another inode. The device
+find programme, which uses device numbers to determine whether
+an inode is on a different filesystem than another inode. The device
 number used is the one for the block device which a filesystem is
 using. To preserve compatibility with userspace programmes, block
 devices using devfs need to have unique device numbers allocated to
@@ -864,9 +1247,11 @@
 
 Alternatively, you can have devfs choose unique device numbers for
 you. When you register a character or block device using
-<devfs_register> you can provide the optional DEVFS_FL_AUTO_DEVNUM
-flag, which will then automatically allocate a unique device number
-(the allocation is separated for the character and block devices).
+devfs_register you can provide the optional
+DEVFS_FL_AUTO_DEVNUM flag, which will then automatically allocate a
+unique device number (the allocation is separated for the character
+and block devices).
+
 This device number is a 16 bit number, so this leaves plenty of space
 for large numbers of discs and partitions. This scheme can also be
 used for character devices, in particular the tty devices, which are
@@ -881,3 +1266,203 @@
 
 A final note on this scheme: since it doesn't increase the size of
 device numbers, there are no compatibility issues with userspace.
+
+-----------------------------------------------------------------------------
+
+
+Questions and Answers
+
+
+Making things work
+Alternatives to devfs
+
+
+
+Making things work
+
+Here are some common questions and answers.
+
+
+
+Devfsd is not managing all my permissions
+
+Make sure you are capturing the appropriate events. For example,
+device entries created by the kernel generate REGISTER events,
+but those created by devfsd generate CREATE events.
+
+
+Devfsd is not capturing all REGISTER events
+
+See the previous entry: you may need to capture CREATE events.
+
+
+X will not start
+
+Make sure you followed the steps 
+outlined above.
+
+
+Why don't my network devices appear in devfs?
+
+This is not a bug. Network devices have their own, completely separate
+namespace. They are accessed via socket(2) and
+setsockopt(2) calls, and thus require no device nodes. I have
+raised the possibilty of moving network devices in the device
+namespace, but have had no response.
+
+
+
+
+
+Alternatives to devfs
+
+I've attempted to collate all the anti-devfs proposals and explain
+their limitations. Under construction.
+
+
+Why not just pass device create/remove events to a daemon?
+
+Here the suggestion is to develop an API in the kernel so that devices
+can register create and remove events, and a daemon listens for those
+events. The daemon would then populate/depopulate /dev (which
+resides on disc).
+
+This has several limitations:
+
+
+it only works for modules loaded and unloaded (or devices inserted
+and removed) after the kernel has finished booting. Without a database
+of events, there is no way the daemon could fully populate
+/dev
+
+
+if you add a database to this scheme, the question is then how to
+present that database to user-space. If you make it a list of strings
+with embedded event codes which are passed through a pipe to the
+daemon, then this is only of use to the daemon. I would argue that the
+natural way to present this data is via a filesystem (since many of
+the events will be of a hierarchical nature), such as devfs.
+Presenting the data as a filesystem makes it easy for the user to see
+what is available and also makes it easy to write scripts to scan the
+"database"
+
+
+the tight binding between device nodes and drivers is no longer
+possible (requiring the otherwise perfectly avoidable
+table lookups)
+
+
+you cannot catch inode lookup events on /dev which means
+that module autoloading requires device nodes to be created. This is a
+problem, particularly for drivers where only a few inodes are created
+from a potentially large set
+
+
+this technique can't be used when the root FS is mounted
+read-only
+
+
+
+
+Just implement a better scsidev
+
+This suggestion involves taking the scsidev programme and
+extending it to scan for all devices, not just SCSI devices. The
+scsidev programme works by scanning /proc/scsi
+
+Problems:
+
+
+the kernel does not currently provide a list of all devices
+available. Not all drivers register entries in /proc or
+generate kernel messages
+
+
+there is no uniform mechanism to register devices other than the
+devfs API
+
+
+implementing such an API is then the same as the
+proposal above
+
+
+
+
+Put /dev on a ramdisc
+
+This suggestion involves creating a ramdisc and populating it with
+device nodes and then mounting it over /dev.
+
+Problems:
+
+
+
+this doesn't help when mounting the root filesystem, since you
+still need a device node to do that
+
+
+if you want to use this technique for the root device node as
+well, you need to use initrd. This complicates the booting sequence
+and makes it significantly harder to administer and configure. The
+initrd is essentially opaque, robbing the system administrator of easy
+configuration
+
+
+insufficient information is available to correctly populate the
+ramdisc. So we come back to the
+proposal above to "solve" this
+
+
+a ramdisc-based solution would take more kernel memory, since the
+backing store would be (at best) normal VFS inodes and dentries, which
+take 284 bytes and 112 bytes, respectively, for each entry. Compare
+that to 49 or 93 bytes for devfs
+
+
+
+
+Do nothing: there's no problem
+
+Sometimes people can be heard to claim that the existing scheme is
+fine. This is what they're ignoring:
+
+
+device number size (8 bits each for major and minor) is a real
+limitation, and must be fixed somehow. Systems with large numbers of
+SCSI devices, for example, will continue to consume the remaining
+unallocated major numbers. USB will also need to push beyond the 8 bit
+minor limitation
+
+
+simplying increasing the device number size is insufficient. Apart
+from causing a lot of pain, it doesn't solve the management issues
+with a /dev with thousands or more device nodes
+
+
+ignoring the problem of a huge /dev will not make it go
+away, and dismisses the legitimacy of a large number of people who
+want a dynamic /dev
+
+
+the standard response then becomes: "write a device management
+daemon", which brings us back to the
+proposal above
+
+
+
+-----------------------------------------------------------------------------
+
+
+Other resources
+
+
+
+Douglas Gilbert has written a useful document at
+
+http://www.torque.net/sg/devfs_scsi.html which
+explores the SCSI subsystem and how it interacts with devfs.
+
+
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/devfs/boot-options linux/Documentation/filesystems/devfs/boot-options
--- v2.3.99-pre6/linux/Documentation/filesystems/devfs/boot-options	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/boot-options	Mon May  8 22:00:41 2000
@@ -4,14 +4,13 @@
 
 		Richard Gooch <rgooch@atnf.csiro.au>
 
-			      14-DEC-1999
+			      30-APR-2000
 
 
-When either CONFIG_DEVFS_DEBUG or CONFIG_DEVFS_BOOT_OPTIONS are
-enabled, you can pass several boot options to the kernel to control
-devfs behaviour. The boot options are prefixed by "devfs=", and are
-separated by commas. Spaces are not allowed. The syntax looks like
-this:
+When CONFIG_DEVFS_DEBUG is enabled, you can pass several boot options
+to the kernel to debug devfs. The boot options are prefixed by
+"devfs=", and are separated by commas. Spaces are not allowed. The
+syntax looks like this:
 
 devfs=<option1>,<option2>,<option3>
 
@@ -60,6 +59,8 @@
 These control the default behaviour of devfs. The options are:
 
 show		show unregistered devices by default
+
+mount		mount devfs onto /dev at boot time
 
 nomount		do not mount devfs onto /dev at boot time
 
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/devfs/mk-devlinks linux/Documentation/filesystems/devfs/mk-devlinks
--- v2.3.99-pre6/linux/Documentation/filesystems/devfs/mk-devlinks	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/mk-devlinks	Wed Dec 31 16:00:00 1969
@@ -1,123 +0,0 @@
-#! /bin/csh -f
-
-# WARNING: make sure /devfs is not a mounted devfs
-
-cd /devfs
-if (-e .devfsd) then
-    echo "/devfs must not be a mounted devfs"
-    exit 1
-endif
-if ( ! -e null ) then
-    echo "Cannot find null device"
-    exit 1
-endif
-
-
-# Make SCSI disc links.
-# WARNING: this assumes your SCSI discs are numbered ID=0, ID=1, ID=2 and so on
-set discs = (a b c d e f)
-if ( ! -d sd ) mkdir sd
-ln -sf /devfs/sd /dev
-
-@ scsi_id = 0
-while ($scsi_id < $#discs)
-    @ discnum = $scsi_id + 1
-    ls -lF sd${discs[$discnum]}
-    rm /dev/sd${discs[$discnum]}
-    ln -s /devfs/sd${discs[$discnum]} /dev
-    ln -s ../sd${discs[$discnum]} sd/c0b0t${scsi_id}u0
-    @ partition = 1
-    while ($partition < 16)
-	ls -lF sd${discs[$discnum]}${partition}
-	rm /dev/sd${discs[$discnum]}${partition}
-	ln -s /devfs/sd${discs[$discnum]}${partition} /dev
-	ln -s ../sd${discs[$discnum]}${partition} sd/c0b0t${scsi_id}u0p$partition
-	@ partition ++
-    end
-    @ scsi_id ++
-end
-
-
-# Make IDE disc links
-foreach i (hd*)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make miscellaneous character devices links (character, major=10)
-foreach i (`ls -l * | grep '^c' | fgrep '10,' | awk '{print $10}'`)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make memory devices links (character, major=1)
-foreach i (`ls -l * | grep '^c' | fgrep ' 1,' | awk '{print $10}'`)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make loop device links
-foreach i (loop*)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make various tty device links
-foreach i (tty* pty* cua* console)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make SCSI CD-ROM, tapes and generic links
-ln -s /devfs/sr /dev
-ln -s /devfs/st /dev
-ln -s /devfs/sg /dev
-foreach i (sr* st* nst* sg*)
-    if ("$i" == "stderr") continue
-    if ("$i" == "stdin") continue
-    if ("$i" == "stdout") continue
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make RAMDISC device links
-ln -s /devfs/rd /dev
-foreach i (ram*)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make floppy device links
-ln -s /devfs/floppy /dev
-foreach i (fd?*)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-
-# Make line printer device links
-foreach i (lp*)
-    rm /dev/$i
-    ln -s /devfs/$i /dev
-end
-
-# Make sound devices links
-if ( ! -d sound ) mkdir sound
-ln -sf /devfs/sound /dev
-foreach i (mixer sequencer midi dsp audio sequencer2 mixer1 patmgr0 midi1\
-    dsp1 audio1 patmgr1 midi2 midi3)
- 
-    if ( -f /dev/$i ) then
-	rm /dev/$i
-	ln -s /devfs/$i /dev
-    endif
-end
-
-
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/devfs/modules.conf linux/Documentation/filesystems/devfs/modules.conf
--- v2.3.99-pre6/linux/Documentation/filesystems/devfs/modules.conf	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/filesystems/devfs/modules.conf	Mon May  8 22:00:41 2000
@@ -84,6 +84,9 @@
 alias		/dev/inportbm	msbusmouse
 alias		/dev/logibm	busmouse
 
+# PPP devices
+alias		/dev/ppp*	ppp_generic
+
 # Video capture devices
 alias		/dev/video*	/dev/v4l
 alias		/dev/vbi*	/dev/v4l
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt
--- v2.3.99-pre6/linux/Documentation/filesystems/ntfs.txt	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/filesystems/ntfs.txt	Tue May  2 13:46:53 2000
@@ -12,6 +12,9 @@
 sets should work as well - if the md driver can be talked into 
 using the same layout as Windows NT.
 
+Please note that the experimental write support is limited to
+Windows NT4 and earlier versions.
+
 The ntfs driver supports the following mount options:
 iocharset=name      Character set to use when returning file names.
                     Unlike VFAT, NTFS suppresses names that contain
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/i386/IO-APIC.txt linux/Documentation/i386/IO-APIC.txt
--- v2.3.99-pre6/linux/Documentation/i386/IO-APIC.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/i386/IO-APIC.txt	Fri May  5 12:37:52 2000
@@ -0,0 +1,117 @@
+Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC',
+which is an enhanced interrupt controller, it enables us to route
+hardware interrupts to multiple CPUs, or to CPU groups.
+
+Linux supports all variants of compliant SMP boards, including ones with
+multiple IO-APICs. (multiple IO-APICs are used in high-end servers to
+distribute IRQ load further).
+
+There are (a few) known breakages in certain older boards, which bugs are
+usually worked around by the kernel. If your MP-compliant SMP board does
+not boot Linux, then consult the linux-smp mailing list archives first.
+
+If your box boots fine with enabled IO-APIC IRQs, then your
+/proc/interrupts will look like this one:
+
+   ---------------------------->
+  hell:~> cat /proc/interrupts
+             CPU0
+    0:    1360293    IO-APIC-edge  timer
+    1:          4    IO-APIC-edge  keyboard
+    2:          0          XT-PIC  cascade
+   13:          1          XT-PIC  fpu
+   14:       1448    IO-APIC-edge  ide0
+   16:      28232   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
+   17:      51304   IO-APIC-level  eth0
+  NMI:          0
+  ERR:          0
+  hell:~>
+  <----------------------------
+
+some interrupts are still listed as 'XT PIC', but this is not a problem,
+none of those IRQ sources is performance-critical.
+
+
+in the unlikely case that your board does not create a working mp-table,
+you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This
+is nontrivial though and cannot be automated. One sample /etc/lilo.conf
+entry:
+
+	append="pirq=15,11,10"
+
+the actual numbers depend on your system, on your PCI cards and on their
+PCI slot position. Usually PCI slots are 'daisy chained' before they are
+connected to the PCI chipset IRQ routing facility (the incoming PIRQ1-4
+lines):
+
+               ,-.        ,-.        ,-.        ,-.        ,-.
+     PIRQ4 ----| |-.    ,-| |-.    ,-| |-.    ,-| |--------| |
+               |S|  \  /  |S|  \  /  |S|  \  /  |S|        |S|
+     PIRQ3 ----|l|-. `/---|l|-. `/---|l|-. `/---|l|--------|l|
+               |o|  \/    |o|  \/    |o|  \/    |o|        |o|
+     PIRQ2 ----|t|-./`----|t|-./`----|t|-./`----|t|--------|t|
+               |1| /\     |2| /\     |3| /\     |4|        |5|
+     PIRQ1 ----| |-  `----| |-  `----| |-  `----| |--------| |
+               `-'        `-'        `-'        `-'        `-'
+
+every PCI card emits a PCI IRQ, which can be INTA,INTB,INTC,INTD:
+
+                               ,-.
+                         INTD--| |
+                               |S|
+                         INTC--|l|
+                               |o|
+                         INTB--|t|
+                               |x|
+                         INTA--| |
+                               `-'
+
+These INTA-D PCI IRQs are always 'local to the card', their real meaning
+depends on which slot they are in. If you look at the daisy chaining diagram,
+a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ2 of
+the PCI chipset. Most cards issue INTA, this creates optimal distribution
+between the PIRQ lines. (distributing IRQ sources properly is not a
+necessity, PCI IRQs can be shared at will, but it's a good for performance
+to have non shared interrupts). Slot5 should be used for videocards, they
+do not use interrupts normally, thus they are not daisy chained either.
+
+so if you have your SCSI card (IRQ11) in Slot1, Tulip card (IRQ9) in
+Slot2, then you'll have to specify this pirq= line:
+
+	append="pirq=11,9"
+
+the following script tries to figure out such a default pirq= line from
+your PCI configuration:
+
+	echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g'
+
+note that this script wont work if you have skipped a few slots or if your
+board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins
+connected in some strange way). E.g. if in the above case you have your SCSI
+card (IRQ11) in Slot3, and have Slot1 empty:
+
+	append="pirq=0,9,11"
+
+[value '0' is a generic 'placeholder', reserved for empty (or non-IRQ emitting)
+slots.]
+
+generally, it's always possible to find out the correct pirq= settings, just
+permute all IRQ numbers properly ... it will take some time though. An
+'incorrect' pirq line will cause the booting process to hang, or a device
+won't function properly (if it's inserted as eg. a module).
+
+If you have 2 PCI buses, then you can use up to 8 pirq values. Although such
+boards tend to have a good configuration.
+
+Be prepared that it might happen that you need some strange pirq line:
+
+	append="pirq=0,0,0,0,0,0,9,11"
+
+use smart try-and-err techniques to find out the correct pirq line ...
+
+good luck and mail to linux-smp@vger.rutgers.edu or
+linux-kernel@vger.rutgers.edu if you have any problems that are not covered
+by this document.
+
+-- mingo
+
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.3.99-pre6/linux/Documentation/ioctl-number.txt	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/ioctl-number.txt	Mon May  8 22:21:58 2000
@@ -179,5 +179,6 @@
 					<mailto:rusty@rustcorp.com.au>	
 0xB0	all	RATIO devices		in development:
 					<mailto:vgo@ratio.de>
+0xB1	00-1F	PPPoX			<mailto:mostrows@styx.uwaterloo.ca>
 0xCB	00-1F	CBM serial IEC bus	in development:
 					<mailto:michael.klein@puffin.lb.shuttle.de>
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt
--- v2.3.99-pre6/linux/Documentation/kbuild/config-language.txt	Sun Feb 20 21:12:38 2000
+++ linux/Documentation/kbuild/config-language.txt	Mon May  8 15:55:52 2000
@@ -465,7 +465,7 @@
 
 Known bugs:
 - Xconfig does not write "# foo is not set" to .config (as well as
-  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
+  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
 
 
 === dep_mbool /prompt/ /symbol/ /dep/ ...
@@ -497,7 +497,7 @@
 
 Known bugs:
 - Xconfig does not write "# foo is not set" to .config (as well as
-  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
+  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
 
 
 === dep_hex /prompt/ /symbol/ /word/ /dep/ ...
@@ -540,7 +540,7 @@
 
 Known bugs:
 - Xconfig does not write "# foo is not set" to .config (as well as
-  "#unset foo" to autoconf.h) if command is disabled by its dependencies.
+  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
 
 
 === unset /symbol/ ...
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- v2.3.99-pre6/linux/Documentation/networking/8139too.txt	Sat Feb 26 22:31:37 2000
+++ linux/Documentation/networking/8139too.txt	Thu Apr 27 15:43:22 2000
@@ -169,6 +169,33 @@
 
 Change History
 --------------
+Version 0.9.4.1 - April 27, 2000 - third public beta release
+
+* Replace several "magic numbers" with symbolic constants
+* Differentiate between board-specific info and chip-specific info
+  (allows for easier support of specific boards or chips)
+* Move some of the transmit side outside of the spinlock
+  by using atomic variables.  Use spin_lock_irq instead of
+  spin_lock_irq{save,restore} in select places, for better performance.
+* New module option "media" for forcing media selection.  Functions the
+  same as "options" in other drivers, and will soon be renamed
+  'options' to be homogeneous.
+* New power management wake-up code
+* Slightly more verbose chip id messages in kernel log
+* Add/correct chip register constant list
+* New chipset wake up (open) logic
+* No longer locks CONFIGx updates
+* Do not set Interfame Gap (IFG) bits in TxConfig
+* Better Rx reset logic in case of Rx FIFO Overflow
+* For chips which support it, enable bit to automatically clear Rx
+  FIFO overflow
+* No longer enable and disable interrupts in interrupt handler
+  (technique borrowed from BSD driver, appears to have problems
+   with some chips)
+* H/W spinlock now protects ioctl
+* Chipset-dependent RxConfig settings
+
+
 Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release
 
 * Begin integration of Daniel Kobras' MMIO flush patch (disabled for now)
@@ -187,8 +214,9 @@
 * Reset NWay registers to sane defaults on rtl8139_open/hw_start
 * Miscellaneous code cleanup
 
-Version 0.7.0 - Feb 7, 2000 - first public beta release
 
+Version 0.7.0 - Feb 7, 2000 - first public beta release
+* Initial public version, derived from Donald Becker's rtl8139.c v1.08r
 
 [EOF]
 
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt
--- v2.3.99-pre6/linux/Documentation/networking/vortex.txt	Wed Apr 26 16:34:06 2000
+++ linux/Documentation/networking/vortex.txt	Tue May  2 12:47:16 2000
@@ -1,5 +1,10 @@
+Documentation/networking/vortex.txt
+Andrew Morton <andrewm@uow.edu.au>
+30 April 2000
+
+
 This document describes the usage and errata of the 3Com "Vortex" device
-driver for Linux.
+driver for Linux, 3c59x.c.
 
 The driver was written by Donald Becker <becker@cesdis.gsfc.nasa.gov>
 
@@ -8,7 +13,14 @@
 
   Andrew Morton <andrewm@uow.edu.au>
   Netdev mailing list <netdev@oss.sgi.com>
+  Linux kernel mailing list <linux-kernel@vger.rutgers.edu>
+
+Please note the 'Reporting and Diagnosing Problems' section at the end
+of this file.
+
 
+Since kernel 2.3.99-pre6, this driver incorporates the support for the
+3c575-series Cardbus cards which used to be handled by 3c575_cb.c.
 
 This driver supports the following hardware:
 
@@ -42,55 +54,133 @@
    3c450 Cyclone/unknown
    3Com Boomerang (unknown version)
 
-When loaded as a module the following variables may be set:
- name	 type	description
- debug	 int	The debug message level, 0 (no messages) to 6 (wordy).
- options int[]	The media type override and card operation settings
-		(See list below.)
-
-An example of loading the vortex module is
-	insmod 3c59x.o debug=1 options=0,,12
-This sets the debug message level to minimal messages, sets the first card to
-the 10baseT transceiver, the second to the EEPROM-set transceiver, and the
-third card to operate in full-duplex mode using its 100baseTx transceiver.
-(Note: card ordering is set by the PCI BIOS.)
 
-Possible media type settings
+Module parameters
+=================
+
+There are several parameters which may be provided to the driver when
+its module is loaded.  These are usually placed in /etc/modules.conf
+(used to be conf.modules).  Example:
+
+options 3c59x debug=3 rx_copybreak=300
+
+If you are using the PCMCIA tools (cardmgr) then theoptions may be
+placed in /etc/pcmcia/config.opts:
+
+module "3c59x" opts "debug=3 extra_reset=1"
+
+
+The supported parameters are:
+
+debug=N
+
+  Where N is a number from 0 to 7.  Anything above 3 produces a lot
+  of output in your system logs.  debug=1 is default.
+
+options=N1,N2,N3,...
+
+  Each number in the list provides an option to the corresponding
+  network card.  So if you have two 3c905's and you wish to provide
+  them with option 0x204 you would use:
+
+    options=0x204,0x204
+
+  The individual options are composed of a number of bitfields which
+  have the following meanings:
+
+  ssible media type settings
 	0	10baseT
 	1	10Mbs AUI
 	2	undefined
 	3	10base2 (BNC)
 	4	100base-TX
 	5	100base-FX
-	6	MII (not yet available)
-	7	<Use default setting>
-	
-	8	Full-duplex bit
-		8 10baseT full-duplex
-		12 100baseTx full-duplex 
-	16	Bus-master enable bit (experimental use only!)
+	6	MII (Media Independent Interface)
+	7	Use default setting from EEPROM
+	8       Autonegotiate
+	9       External MII
+	10      Use default setting from EEPROM
 
-Details of the device driver implementation are at the top of the source file.
+  When generating a value for the 'options' setting, the above media
+  selection values may be OR'ed (or added to) the following:
 
-Additional documentation is available at Don Becker's Linux Drivers site:
+  512 (0x200)	Force full-duplex
+  16  (0x10)	Bus-master enable bit (Old Vortex cards only)
+
+  For example:
+
+    insmod 3c59x options=0x204
+
+  will force full-duplex 100base-TX, rather than allowing the usual
+  autonegotiation.
+
+full_duplex=N1,N2,N3...
+
+  Similar to bit 9 of 'options'.  Forces the corresponding card into
+  full-duplex mode.
+
+rx_copybreak=M
+
+  The driver preallocates 32 full-sized (1536 byte) network buffers
+  for receiving.  When a packet arrives, the driver has to decide
+  whether to leave the packet in its full-sized buffer, or to allocate
+  a smaller buffer and copy the packet across into it.
+
+  This is a speed/space tradeoff.
+
+  The value of rx_copybreak is used to decide when to make the copy. 
+  If the packet size is less than rx_copybreak, the packet is copied. 
+  The default value for rx_copybreak is 200 bytes.
+
+max_interrupt_work=N
+
+  The driver's interrupt service routine can handle many receive and
+  transmit packets in a single invokation.  It does this in a loop. 
+  The value of max_interrupt_work governs how mnay times the interrupt
+  service routine will loop.  The default value is 32 loops.  If this
+  is exceeded the interrupt service routine gives up and generates a
+  warning message "eth0: Too much work in interrupt".
+
+extra_reset=N
+
+  Where N is 0 or 1 (default 0).
+
+  Some network cards (notably 3CCFE575CT Cardbus) do not initialise
+  correctly and need an extra transmitter reset.  If you find that the
+  card comes up receiving but not transmitting, try giving the module
+  the 'extra_reset=1' option.
+
+compaq_ioaddr=N
+compaq_irq=N
+compaq_device_id=N
+
+  "Variables to work-around the Compaq PCI BIOS32 problem"....
 
-  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html
 
 
 Additional resources
 --------------------
 
+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
+
 Donald Becker's driver development site:
 
+     http://www.scyld.com
      http://cesdis.gsfc.nasa.gov/linux/
 
 Don's vortex-diag program is useful for inspecting the NIC's state:
 
+     http://www.scyld.com/diag/#pci-diags
      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://www.scyld.com/diag/#mii-diag
      http://cesdis.gsfc.nasa.gov/linux/diag/#mii-diag
 
 3Com's documentation for many NICs, including the ones supported by
@@ -104,13 +194,50 @@
      http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3
 
 
+Autonegotiation notes
+---------------------
+
+  The driver uses a one-minute heartbeat for adapting to changes in
+  the external LAN environment.  This means that when, for example, a
+  machine is unplugged from a hubbed 10baseT LAN plugged into a
+  switched 100baseT LAN, the throughput will be quite dreadful for up
+  to sixty seconds.  Be patient.
 
-Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
+  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.
+
+
+Reporting and diagnosing problems
+---------------------------------
+
+If the driver plays up, there are a number of things you can do analyse
+the problem and to help others do this:
+
+- Turn on debugging in the driver
+	Add 'debug=7' to /etc/modules.conf (/etc/conf.modules)
+	Change 'vortex_debug' to 7 in the source code.
+
+- Send all kernel logs, starting with the first probe of the card.
+
+- Run 'mii-diag -v' to show the state of the Media Independent
+  Interface.  If the card sometimes works and sometimes doesn't, run
+  'mii-diag -v' in both states.
+
+- Please run 'vortex-diag -aaee' in both good and bad states.  This
+  show the NIC's registers and EEPROM contents.
+
+- Describe your setup: 10baseT, 100baseT, full/half duplex, etc.
+
+- Note any additional module insertion commands you're using.
+
+- Try different media type settings (see above).
+
+- Try inserting the module with 'extra_reset=1' (or compile this into
+  the driver).
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/pci.txt linux/Documentation/pci.txt
--- v2.3.99-pre6/linux/Documentation/pci.txt	Sat Feb 26 22:31:37 2000
+++ linux/Documentation/pci.txt	Fri May  5 12:37:52 2000
@@ -43,7 +43,10 @@
 
 	name		Name of the driver
 	id_table	Pointer to table of device ID's the driver is
-			interested in
+			interested in.  Most drivers should export this
+			table using MODULE_DEVICE_TABLE(pci,...).
+			Set to NULL to call probe() function for every
+			PCI device known to the system.
 	probe		Pointer to a probing function which gets called (during
 			execution of pci_register_driver for already existing
 			devices or later if a new device gets inserted) for all
@@ -59,9 +62,8 @@
 			deregistration of the driver or when it's manually pulled
 			out of a hot-pluggable slot). This function can be called
 			from interrupt context.
-	suspend,	Power management hooks (currently used only for CardBus
-	resume		cards) -- called when the device goes to sleep or is
-			resumed.
+	suspend,	Power management hooks -- called when the device goes to
+	resume		sleep or is resumed.
 
 The ID table is an array of struct pci_device_id ending with a all-zero entry.
 Each entry consists of:
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/sound/Maestro linux/Documentation/sound/Maestro
--- v2.3.99-pre6/linux/Documentation/sound/Maestro	Tue Mar 14 19:10:38 2000
+++ linux/Documentation/sound/Maestro	Wed May 10 16:56:41 2000
@@ -30,7 +30,8 @@
 --------------------
 
 This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.
+mostly adhere to the OSS spec.   This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
 
 The /dev/dsp device exported behaves almost as expected.  Playback is
 supported in all the various lovely formats.  8/16bit stereo/mono from
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/sound/via82cxxx.txt linux/Documentation/sound/via82cxxx.txt
--- v2.3.99-pre6/linux/Documentation/sound/via82cxxx.txt	Fri Mar 10 16:40:38 2000
+++ linux/Documentation/sound/via82cxxx.txt	Thu May 11 13:45:35 2000
@@ -13,12 +13,11 @@
 of the kernel source tree is a PCI audio driver for audio chips
 found on Via-based motherboards, such as the MVP4.
 
-Currently the driver provides audio via SoundBlaster Pro compatibility,
-and MIDI via MPU-401 compatibility.  An AC97 mixing device is also
-supported, and is generally preferred over the SoundBlaster mixer.
+Currently the driver exports the following features:
 
-IMPORTANT NOTE:  Some users report that the SoundBlaster mixer does
-not work at all -- use the AC97 mixer if possible.
+	* /dev/dsp and /dev/audio support
+	* 16-bit stereo PCM output channel
+	* AC97 mixer
 
 Please send bug reports to the mailing list linux-via@gtf.org.
 To subscribe, e-mail majordomo@gtf.org with "subscribe linux-via" in the
@@ -27,7 +26,7 @@
 
 Thanks
 ------------------------------------------------------------------------
-Via for providing e-mail support, specs, and NDA's source code.
+Via for providing e-mail support, specs, and NDA'd source code.
 
 MandrakeSoft for providing hacking time.
 
@@ -40,15 +39,10 @@
 If the driver is being statically compiled into the kernel, no
 configuration should be necessary.
 
-If the driver is being compiled as a module, generally two lines must
+If the driver is being compiled as a module, generally one line must
 be added to your /etc/conf.modules (or /etc/modules.conf) file:
 
-	alias sound via82cxxx
-	options sb support=1
-
-The second line is very important:  it tells the required 'sb' module
-not to load SoundBlaster support, but to instead let the Via driver
-do so at a later time.
+	alias sound via82cxxx_audio
 
 
 
@@ -63,8 +57,8 @@
 a patch to clean some of that up.  Ideally, 
 
 No consideration for SMP, this chipset is not known to be found on
-any SMP motherboards.  However, this will change when we start handling
-our own interrupts in "native mode."
+any SMP motherboards.  However, spin_locks must be used anyway in order
+to handle interrupts correctly.
 
 GNU indent formatting options:  -kr -i8 -pcs
 
@@ -76,29 +70,17 @@
 audio driver.  If your motherboard (or notebook) is not listed here,
 please e-mail the maintainer with details.
 
-	AOpen MX59 Pro (Apollo MVP4)
+	AOpen MX59 Pro
+	Compaq Presario 1247
 
 
 
-The Future
+Random Developer Notes / Comments
 ------------------------------------------------------------------------
 Via has graciously donated e-mail support and source code to help further
 the development of this driver.  Their assistance has been invaluable
 in the design and coding of the next major version of this driver.
 
-This audio chip supports a DirectSound(tm)-style hardware interface,
-with a single 16-bit stereo input channel, and a single 16-bit stereo
-output channel.  Data is transferred to/from the hardware using
-table-driven scatter-gather DMA buffers.
-
-Work is currently underway to support this "native mode" of the chip.
-When complete, SoundBlaster legacy mode will be completely removed.
-After a round of testing, this code will become version 2.0.0.
-
-Following the 2.0.0 release, the last major task to complete is
-MIDI support.  MPU-401 legacy support is available currently, but
-not well tested at all.
-
 The Via audio chip apparently provides a second PCM scatter-gather
 DMA channel just for FM data, but does not have a full hardware MIDI
 processor.  I haven't put much thought towards a solution here, but it
@@ -109,11 +91,15 @@
 
 General To-do List (patches/suggestions welcome)
 ------------------------------------------------------------------------
-Better docs
+Recording support
+
+mmap support
 
-Code review by sound guru(s)
+Other advanced ioctls
 
-Native DSP audio driver using scatter-gather DMA, as described above
+Better docs
+
+Code review
 
 Native MIDI driver, as described above
 
@@ -121,8 +107,35 @@
 
 Known bugs (patches/suggestions welcome)
 ------------------------------------------------------------------------
-1) Two MIDI devices are loaded by the sound driver.  Eliminate one of them. 
+1) Volume too low on many systems.  Workaround:  use mixer program
+such as xmixer to increase volume.
+
+2) RealPlayer output very scratchy.
+
+3) Applications which attempt to open the sound device in read/write
+mode (O_RDWR) will fail.  This is incorrect OSS behavior, but since
+this driver will eventually support recording as well as playback,
+we will be able to (in the future) support even broken programs which
+unconditionally use O_RDWR.
+
+
+
+Submitting a bug report
+------------------------------------------------------------------------
+Describe the application you were using to play/record sound, and how
+to reproduce the problem.
+
+Obtain the via-audio-diag diagnostics program from
+http://gtf.org/garzik/drivers/via82cxxx/ and provide a dump of the
+audio chip's registers while the problem is occurring.  Sample command line:
+	./via-audio-diag -aps > diag-output.txt
+
+Define "VIA_DEBUG" at the beginning of the driver, then capture and email
+the kernel log output.  This can be viewed in the system kernel log (if
+enabled), or via the 'dmesg' program.
+
+If you wish to increase the size of the buffer displayed by 'dmesg', then
+change the LOG_BUF_LEN macro at the top of linux/kernel/printk.c, recompile
+your kernel, and pass the "-s <size>" option to 'dmesg'.
+
 
-2) Two mixer devices are loaded by the sound driver.  Eliminate one of
-them.  At least one bug report says that SB mixer does not work at all,
-only AC97 mixer.
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/usb/input.txt linux/Documentation/usb/input.txt
--- v2.3.99-pre6/linux/Documentation/usb/input.txt	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/usb/input.txt	Wed May 10 16:56:44 2000
@@ -185,24 +185,28 @@
 	crw-r--r--   1 root     root      13,  33 Mar 29 00:41 mouse1
 	crw-r--r--   1 root     root      13,  34 Mar 29 00:41 mouse2
 	crw-r--r--   1 root     root      13,  35 Apr  1 10:50 mouse3
-
-and so on, up to mouse31. Each is assigned to a single mouse or digitizer,
-unless CONFIG_INPUT_MOUSEDEV_MIX is set. In that case all mice and
-digitizers share a single character device, mouse0, and even when none are
-connected, mouse0 is present. This is useful for hotplugging USB mice, so
-that programs can open the device even when no mice are present.
+	...
+	...
+	crw-r--r--   1 root     root      13,  62 Apr  1 10:50 mouse30
+	crw-r--r--   1 root     root      13,  63 Apr  1 10:50 mice
+
+Each 'mouse' device is assigned to a single mouse or digitizer, except the last
+one - 'mice'. This single character device is shared by all mice and
+digitizers, and even if none are connected, the device is present.  This is
+useful for hotplugging USB mice, so that programs can open the device even when
+no mice are present.
 
   CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
 of your screen (in pixels) in XFree86. This is needed if you want to use
 your digitizer in X, because it's movement is sent to X via a virtual PS/2
-mouse.
+mouse. These values won't be used if you use a mouse only.
 
   Mousedev.c will generate either PS/2, ImPS/2 (microsoft intellimouse) or
 GenPS/2 (genius netmouse/netscroll) protocols, depending on what the program
-wishes. You can set GPM and X to any of these. You'll need ImPS/2 if you
-want to make use of a wheel on a USB mouse and GenPS/2 if you want to use
-extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported in X,
-though.
+reading the data wishes. You can set GPM and X to any of these. You'll need
+ImPS/2 if you want to make use of a wheel on a USB mouse and GenPS/2 if you
+want to use extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported
+in X, though.
 
 3.2.3 joydev.c
 ~~~~~~~~~~~~~~
@@ -216,6 +220,7 @@
 	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
 	crw-r--r--   1 root     root      13,   2 Apr  1 10:50 js2
 	crw-r--r--   1 root     root      13,   3 Apr  1 10:50 js3
+	...
 
 And so on up to js31.
 
@@ -236,6 +241,7 @@
 	crw-r--r--   1 root     root      13,  65 Apr  1 10:50 event1
 	crw-r--r--   1 root     root      13,  66 Apr  1 10:50 event2
 	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
+	...
 
 3. Contacts
 ~~~~~~~~~~~
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- v2.3.99-pre6/linux/Documentation/usb/ov511.txt	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/usb/ov511.txt	Thu May 11 13:45:35 2000
@@ -6,8 +6,11 @@
 Homepage: http://alpha.dyndns.org/ov511
 
 NEW IN THIS VERSION:
- o Support for OV511+
- o Support for OV7620
+ o Improvements to sensor detection code
+ o Added "i2c_detect_tries" and "aperture" parameters
+ o proc filesystem status support
+ o read() fixed partially
+ o code cleanups and minor fixes
 
 INTRODUCTION:
 
@@ -151,11 +154,13 @@
  o Monochrome
  o Setting/getting of saturation, contrast and brightness (no hue yet; only
    works with OV7610, not the OV7620 or OV7620AE)
+ o proc status reporting
 
 EXPERIMENTAL FEATURES:
  o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
    corrupted frames.
  o Snapshot mode (only works with some read() based apps; see below for more)
+ o read() support
 
 TODO:
  o Fix the noise / grainy image problem.
@@ -180,6 +185,8 @@
  o Get rid of the memory management functions (put them in videodev.c??)
  o Setting of contrast and brightness not working with 7620
  o Driver/camera state save/restore for when USB supports suspend/resume
+ o Multiple cameras reportedly do not work simultaneously
+ o Problems with OHCI
 
 HOW TO CONTACT ME:
 
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/usb/scanner-hp-sane.txt linux/Documentation/usb/scanner-hp-sane.txt
--- v2.3.99-pre6/linux/Documentation/usb/scanner-hp-sane.txt	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/usb/scanner-hp-sane.txt	Tue May  2 13:49:18 2000
@@ -1,13 +1,12 @@
 Copyright (C) 1999, 2000 David E. Nelson
 
-Mar. 23, 2000
+April 26, 2000
 
 CHANGES
 
-- Amended for Linux-2.3.40
+- Amended for Linux-2.3.99-pre6-3
 - Updated for multiple scanner support
 
-
 INTRODUCTION
 
 This document will hopefully provide enough info on how to get SANE
@@ -15,9 +14,12 @@
 interface.  The majority of HP Scanners support the Scanner Control
 Language (SCL) which is both published by HP and supported by SANE.
 The only HP Scanners that I'm aware of that do not support SCL are the
-4200C and the 3300C.  All other HP scanners with USB interfaces should
-work (4100C, 5200C, 6200C, and 6300C).  Of course as HP releases new
-scanners this information may change.
+4200C ,3300C, and the PhotoSmart S20.  All other HP scanners with USB
+interfaces should work (4100C, 5200C, 6200C, and 6300C) as do models
+that are derived from the models above. ie the 6350C which is a 6300C
+with a transparency adaptor included with the scanner at time of
+purchase.  Of course as HP releases new scanners this information may
+change.
 
 
 REQUIREMENTS
@@ -37,9 +39,9 @@
 
 OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
 
-NOTE: $INSTALL_DIR is the location where SANE is installed.  It may
-be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
-your system administrator.
+NOTE: $INSTALL_DIR is the location where SANE is installed.  It may be
+/usr/local, /usr, /opt or somewhere else.  If you don't know, ask your
+system administrator.
 
 1) Make sure that you have the libsane-hp.* libraries under the
 $INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
@@ -56,17 +58,18 @@
     option connect-device
 
 NOTE: If you are using multiple scanners, make sure to have the correct
-devince, ie /dev/usbscanner0.  See scanner.txt for more info.
+device, ie /dev/usbscanner0.  See scanner.txt for more info.
 
 3) You should now be able to use SANE (xscanimage or scanimage).
 
 Don't forget to read any relevant man pages regarding the usage of
-SANE.  If you have other entries uncommented in dll.conf, you may have
-to specify the device to (x)scanimage.  Again, `man` is your friend.
-The xscanimage (1) man page has info on how to get 'The Gimp' to work
-with xscanimage.  Note that Gimp support must be compiled into SANE
-for it work.  If you are dealing with a RedHat system, this means that
-you'll also need to install the gimp-devel rpm package.
+SANE.  If you have other entries uncommented in 'dll.conf', you may
+have to specify the device to (x)scanimage.  Again, `man` is your
+friend.  The xscanimage (1) man page has info on how to get 'The Gimp'
+to work with xscanimage.  Note that Gimp support must be compiled into
+SANE for it to work.  If you are dealing with a RedHat system, this
+means that you'll also need to install the gimp-devel rpm package
+prior to compiling SANE.
 
 NOTE: The issues regarding core dumping by (x)scanimage have (or seem
 to be thus far) been resolved with version 0.2+ of the USB scanner
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- v2.3.99-pre6/linux/Documentation/usb/scanner.txt	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/usb/scanner.txt	Tue May  2 13:49:18 2000
@@ -1,25 +1,26 @@
 Copyright (C) 1999, 2000 David E. Nelson
 
-Mar. 23, 2000
+April 26, 2000
 
 CHANGES
 
-- Amended for linux-2.3.40
+- Amended for linux-2.3.99-pre6-3
 - Appended hp_scan.c to end of this README
 - Removed most references to HP
 - Updated uhci/ohci host controller info
 - Updated support for multiple scanner support
 - Updated supported scanners list
-
+- Updated usbdevfs info
+- Spellcheck
 
 OVERVIEW
 
-This README will address issues regarding how to configure the kernel
+This README addresses issues regarding how to configure the kernel
 to access a USB scanner.  Although the driver was originally conceived
 for USB HP scanners, it's general enough so that it can be used with
 other scanners.  Also, one can now pass the USB Vendor and Product
 ID's using module parameters for unknown scanners.  Refer to the
-document scanner_hp_sane.txt for guidance on how to configure SANE to
+document scanner-hp-sane.txt for guidance on how to configure SANE to
 use a USB HP Scanner.
 
 
@@ -41,11 +42,11 @@
 A Linux kernel with USB Scanner support enabled.
 
 'lspci' which is only needed to determine the type of USB hardware
-available in your machine.
+available/installed in your machine.
 
 CONFIGURATION
 
-Using `lspci -v`, determine the type of USB hardware available.
+Using `lspci -v`, determine the type of USB hardware available/installed.
 
   If you see something like:
 
@@ -68,7 +69,10 @@
 hardware (determined from the steps above), 'USB Scanner support', and
 'Preliminary USB device filesystem'.  Compile and install the modules
 (you may need to execute `depmod -a` to update the module
-dependencies).  Testing was performed only as modules, YMMV.
+dependencies). If any of the USB sections were compiled into the
+kernel, a reboot is necessary. NOTE: Updating the boot disk with
+'lilo' may also be required. Testing was performed only as modules,
+YMMV.
 
 Beginning with version 0.4 of the driver, up to 16 scanners can be
 connected/used simultaneously.  If you intend to use more than
@@ -82,14 +86,15 @@
 	`mknod /dev/usb/scanner15 180 63`
 
 
-If you forsee using only one scanner:
+If you foresee using only one scanner it is best to:
 	`mknod /dev/usbscanner0 c 180 48`
 	`ln -s /dev/usbscanner0 /dev/usbscanner`
 
 
 Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
 about group and world permissions).  Both read and write permissions
-are required for proper operation.
+are required for proper operation. For example:
+	`chmod 666 /dev/usbscanner0`
 
 Load the appropriate modules (if compiled as modules):
 
@@ -108,12 +113,23 @@
 SCL (Scanner Control Language).  Known HP scanner that support SCL are
 the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
 supported since it does not understand SCL; it's also strongly
-suspected that the 3300 is not SCL compliant.  Hp_scan.c's purpose is
-to test the driver without having to retrieve/configure SANE.
-Hp_scan.c will scan the entire bed and put the output into a file
-called 'out.dat' in the current directory.  The data in the file is
-raw data so it's not very useful for imaging.
-
+suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
+Hp_scan.c's purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called 'out.dat' in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
+
+MESSAGES
+
+On occassion the message 'usb_control/bulk_msg: timeout' or something
+similar will appear in '/var/adm/messages' or on the console or both,
+depending on how your system is configured.  This is a side effect
+that scanners are sometimes very slow at warming up and/or
+initialiazing.  In most cases, however, only several of these messages
+should appear and is generally considered to be normal.  If you see
+a message of the type 'excessive NAK's received' then this should
+be considered abnormal and generally indicates that the USB system is
+unable to communicate with the scanner for some particular reason.
 
 SUPPORTED SCANNERS
 
@@ -125,72 +141,97 @@
 At the time of this writing, the following scanners were supported by
 scanner.c:
 
-  Acer
-
-    Prisa AcerScan 620U
-
-  Agfa
-
-    SnapScan 1212U, SnapScan Touch
-
-  Genius
-
-    ColorPage Vivid Pro
-
-  Hewlett Packard
-
-    3300, 4100, 4200, 5200, 6200, 6300, PhotoSmart S20
-
-  Microtek
-
-    ScanMaker X6-X6U, Phantom 336CX - C3, Phantom C6, ScanMaker V6USL,
-    ScanMaker V6UL - SpicyU
-
-  Mustek
+ Acer
+	 Prisa Acerscan 620U & 640U (!)
+	 Prisa AcerScan 620U (!)
+ Agfa
+	 SnapScan 1212U
+	 Another SnapScan 1212U (?)
+	 SnapScan Touch
+ Colorado -- See Primax/Colorado below
+ Epson -- See Seiko/Epson below
+ Genius
+         ColorPage-Vivid Pro
+ Hewlett Packard
+	 3300C
+	 4100C
+	 4200C
+	 PhotoSmart S20
+	 5200C
+	 6200C
+	 6300C
+ Microtek
+	 ScanMaker X6 - X6U
+	 Phantom 336CX - C3
+	 Phantom 336CX - C3 #2
+	 Phantom C6
+	 ScanMaker V6USL
+	 ScanMaker V6USL #2
+	 ScanMaker V6UL - SpicyU
+ Mustek
+	 1200 CU
+ Primax/Colorado
+	 G2-300 #1
+	 G2-600 #1
+	 G2E-300 #1
+	 ReadyScan 636i
+	 G2-300 #2
+	 G2-600 #2
+	 G2E-300 #2
+	 G2E-600
+	 Colorado USB 9600
+	 Colorado USB 19200
+	 Colorado 600u
+	 Colorado 1200u
+ Seiko/Epson Corp.
+	 Perfection 636U and 636Photo
+	 Perfection 610
+	 Perfection 1200U and 1200Photo
+ Umax
+	 Astra 1220U
+	 Astra 1236U
+	 Astra 2000U
+	 Astra 2200U
+ Visioneer
+	 OneTouch 5300
+	 OneTouch 7600 duplicate ID (!)
+	 6100
 
-    1200 CU
 
-  Primax/Colorado
-
-    G2-300, G2-600, G2E-300, G2E-600, ReadyScan 636i, Colorado USB
-    19200, Colorado 600u, Colorado 1200u
-
-  Seiko/Epson
-
-    Perfection Perfection 610, Perfection 636U/636Photo, Perfection
-    1200U/1200Photo
-
-  Umax
+MODULE PARAMETERS
 
-    Astra 1220U, 1236U, 2000U
+If you have a device that you wish to experiment with or try using
+this driver with, but the Vendor and Product ID's are not coded in,
+don't despair.  If the driver was compiled as a module, you can pass
+options to the driver.  Simply add 
 
-  Visioneer
+  options scanner vendor=0x#### product=0x****
 
-    OneTouch 5300, OneTouch 7600, 6100,
+to the /etc/modules.conf file replacing the #'s and the *'s with the
+correct ID's.  The ID's can be retrieved from the messages file or
+using `cat /proc/bus/usb/devices`. Note that USB /proc support must be
+enabled during kernel configuration.  If the 'scanner' module is
+already loaded into memory, it must be reloaded for the module
+parameters to take effect.  In essence, `rmmod scanner; modprobe
+scanner` must be performed.
 
+**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced,
+usbdevfs.  To mount the filesystem, issue the command (as root):
 
-  User Specified.  See MODULE PARAMETERS for details.
+  mount -t usbdevfs /proc/bus/usb /proc/bus/usb
 
+An alternative and more permanent method would be to add
 
-MODULE PARAMETERS
+  none  /proc/bus/usb  usbdevfs  defaults  0  0
 
-If you have a device that you wish to experiment with or try using
-this driver with, but the Vendor and Product ID's are not coded in,
-don't despair.  If the driver was compiled as a module, you can pass
-options to the driver.  Simply add 'options scanner vendor=0x####
-product=0x****' to the conf.modules/modules.conf file replacing the
-#'s and the *'s with the correct ID's.  The ID's can be retrieved from
-the messages file or using `cat /proc/bus/usb/devices` if USB /proc
-support was selected during kernel configuration.  **NOTE**:In later
-kernels (2.3.38+), a new filesystem was introduced, usbdevfs.  To
-mount the filesystem, issue the command `mount -t usbdevfs
-/proc/bus/usb /proc/bus/usb`.  You can then issue ` cat
-/proc/bus/usb/devices` to extract USB device information.
+to /etc/fstab.  This will mount usbdevfs at each reboot.  You can then
+issue `cat /proc/bus/usb/devices` to extract USB device information.
 
 
 BUGS
 
-If you encounter any problems feel free to drop me an email.
+Just look at the list of fixes in the source files.  So, if you
+encounter any problems feel free to drop me an email.
 
 David /\/elson
 dnelson@jump.net
diff -u --recursive --new-file v2.3.99-pre6/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- v2.3.99-pre6/linux/Documentation/usb/usb-serial.txt	Sun Mar 19 18:35:30 2000
+++ linux/Documentation/usb/usb-serial.txt	Fri May  5 13:41:30 2000
@@ -10,30 +10,30 @@
 
 CONFIGURATION
 
-  Currently the driver can handle up to 16 different serial interfaces at
-  one time. Once more of the drivers become stable, this number will be
-  increased to the full 256. 
+  Currently the driver can handle up to 256 different serial interfaces at
+  one time. 
 
-  The major number that the driver uses is 188 so to use the driver,
-  create the following nodes:
+  If you are not using devfs:
+    The major number that the driver uses is 188 so to use the driver,
+    create the following nodes:
 	mknod /dev/ttyUSB0 c 188 0
 	mknod /dev/ttyUSB1 c 188 1
 	mknod /dev/ttyUSB2 c 188 2
 	mknod /dev/ttyUSB3 c 188 3
-	mknod /dev/ttyUSB4 c 188 4
-	mknod /dev/ttyUSB5 c 188 5
-	mknod /dev/ttyUSB6 c 188 6
-	mknod /dev/ttyUSB7 c 188 7
-	mknod /dev/ttyUSB8 c 188 8
-	mknod /dev/ttyUSB9 c 188 9
-	mknod /dev/ttyUSB10 c 188 10
-	mknod /dev/ttyUSB11 c 188 11
-	mknod /dev/ttyUSB12 c 188 12
-	mknod /dev/ttyUSB13 c 188 13
-	mknod /dev/ttyUSB14 c 188 14
-	mknod /dev/ttyUSB15 c 188 15
-	mknod /dev/ttyUSB16 c 188 16
-
+		.
+		.
+		.
+	mknod /dev/ttyUSB254 c 188 254
+	mknod /dev/ttyUSB255 c 188 255
+
+  If you are using devfs:
+    The devices supported by this driver will show up as
+    /dev/usb/tts/{0,1,...}
+
+  When the device is connected and recognized by the driver, the driver
+  will print to the system log, which node(s) the device has been bound
+  to.
+  
 
 SPECIFIC DEVICES SUPPORTED
 
@@ -45,8 +45,9 @@
   being fully supported.
 
 Current status:
-  The device's firmware is downloaded on connection, but the use of a
-  special Anchor Chips extension is currently giving me problems.
+  The device's firmware is downloaded on connection, the new firmware 
+  runs properly and all four ports are successfuly recognized and connected.
+  Now data flow needs to be implemented properly.
   This driver is not fully operational.
 
 
@@ -61,7 +62,9 @@
   
   When the device is connected, try talking to it on the second port
   (this is usually /dev/ttyUSB1 if you do not have any other usb-serial
-  devices in the system.)
+  devices in the system.) The system log should tell you which port is
+  the port to use for the HotSync transfer. The "Generic" port can be used
+  for other device communication, such as a PPP link.
 
   There is a webpage and mailing lists for this portion of the driver at: 
   http://usbvisor.sourceforge.net/
@@ -89,6 +92,19 @@
    HW flow control
    not all of the standard USB descriptors are handled: Get_Status, Set_Feature
    O_NONBLOCK, select()
+
+
+FTDI Single Port Serial Driver
+
+  This is a single port DB-25 serial adapter. More information about this
+  device and the Linux driver can be found at:
+	http://reality.sgi.com/bryder_wellington/ftdi_sio/
+
+
+ZyXEL omni.net lcd plus ISDN TA
+
+  This is an ISDN TA. Please report both successes and troubles to the
+  author at omninet@kroah.com
 
 
 Generic Serial driver
diff -u --recursive --new-file v2.3.99-pre6/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.99-pre6/linux/MAINTAINERS	Wed Apr 26 16:34:06 2000
+++ linux/MAINTAINERS	Mon May  8 22:21:58 2000
@@ -847,6 +847,11 @@
 L:	linux-ppp@vger.rutgers.edu
 S:	Maintained
 
+PPP OVER ETHERNET
+P:	Michal Ostrowski
+M:	mostrows@styx.uwaterloo.ca
+S:	Maintained
+
 PROMISE DC4030 CACHING DISK CONTROLLER DRIVER
 P:	Peter Denison
 M:	promise@pnd-pc.demon.co.uk
@@ -863,7 +868,7 @@
 RAGE128 FRAMEBUFFER DISPLAY DRIVER
 P:	Brad Douglas
 M:	brad@neruo.com
-L:	linux-fbdev@vuser.vc.union.edu
+L:	linux-fbdev@vuser.vu.union.edu
 S:	Maintained
 
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
diff -u --recursive --new-file v2.3.99-pre6/linux/Makefile linux/Makefile
--- v2.3.99-pre6/linux/Makefile	Wed Apr 26 16:34:06 2000
+++ linux/Makefile	Wed Apr 26 16:38:37 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 3
 SUBLEVEL = 99
-EXTRAVERSION = -pre6
+EXTRAVERSION = -pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.3.99-pre6/linux/arch/alpha/defconfig	Tue Apr 11 15:09:11 2000
+++ linux/arch/alpha/defconfig	Mon May  8 22:00:41 2000
@@ -361,6 +361,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.99-pre6/linux/arch/alpha/kernel/osf_sys.c	Tue Apr 11 15:09:11 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Mon May  8 13:34:03 2000
@@ -302,17 +302,14 @@
 
 asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	int retval;
 
-	lock_kernel();
-	dentry = namei(path);
-	retval = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		retval = do_osf_statfs(dentry, buffer, bufsiz);
-		dput(dentry);
+	retval = user_path_walk(path, &nd);
+	if (!retval) {
+		retval = do_osf_statfs(nd.dentry, buffer, bufsiz);
+		path_release(&nd);
 	}
-	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/alpha/lib/copy_user.S linux/arch/alpha/lib/copy_user.S
--- v2.3.99-pre6/linux/arch/alpha/lib/copy_user.S	Fri Apr 30 08:22:19 1999
+++ linux/arch/alpha/lib/copy_user.S	Thu Apr 27 22:27:16 2000
@@ -80,7 +80,7 @@
 	extql $3,$7,$3
 	extqh $2,$7,$1
 	bis $3,$1,$1
-	stq $1,0($6)
+	EXO( stq $1,0($6) )
 	addq $7,8,$7
 	subq $0,8,$0
 	addq $6,8,$6
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus
--- v2.3.99-pre6/linux/arch/arm/def-configs/brutus	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/def-configs/brutus	Mon May  8 22:00:41 2000
@@ -216,6 +216,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110
--- v2.3.99-pre6/linux/arch/arm/def-configs/ebsa110	Wed Apr 26 16:34:06 2000
+++ linux/arch/arm/def-configs/ebsa110	Mon May  8 22:00:41 2000
@@ -361,6 +361,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge
--- v2.3.99-pre6/linux/arch/arm/def-configs/footbridge	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/def-configs/footbridge	Mon May  8 22:00:41 2000
@@ -690,6 +690,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/arm/def-configs/thinclient linux/arch/arm/def-configs/thinclient
--- v2.3.99-pre6/linux/arch/arm/def-configs/thinclient	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/def-configs/thinclient	Mon May  8 22:00:41 2000
@@ -340,6 +340,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.3.99-pre6/linux/arch/arm/defconfig	Wed Apr 26 16:34:06 2000
+++ linux/arch/arm/defconfig	Mon May  8 22:00:41 2000
@@ -639,6 +639,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.99-pre6/linux/arch/i386/config.in	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/config.in	Thu Apr 27 15:55:14 2000
@@ -22,7 +22,7 @@
 	 486/Cx486		CONFIG_M486	\
 	 586/K5/5x86/6x86/6x86MX	CONFIG_M586	\
 	 Pentium/TSC		CONFIG_M586TSC	\
-	 PPro			CONFIG_M686 \
+	 PPro/P-II/P-III	CONFIG_M686 \
 	 K6/II/III		CONFIG_MK6 \
 	 Athlon                 CONFIG_MK7" PPro
 #
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.99-pre6/linux/arch/i386/defconfig	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/defconfig	Mon May  8 22:01:11 2000
@@ -387,10 +387,6 @@
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR 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
@@ -507,6 +503,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c
--- v2.3.99-pre6/linux/arch/i386/kernel/acpi.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/kernel/acpi.c	Wed May  3 09:06:37 2000
@@ -144,14 +144,21 @@
 
 struct acpi_errata_info
 {
-	const char *oem;
-	const char *oem_table;
-	u32 oem_rev;
-	unsigned long options;
+	const char *signature; // table signature (eg. "RSDT")
+	const char *oem;       // OEM name
+	const char *oem_table; // OEM table identifier (optional)
+	u32 oem_rev;           // OEM table revision (optional)
+	unsigned long options; // errata options
 };
 
+/*
+ * We must identify systems that need ACPI_TRUST_TABLES solely from the
+ * RSDP ("RSD PTR ").  All other options should be flagged from the
+ * RSDT ("RSDT") which can be better identified.
+ */
 struct acpi_errata_info acpi_errata[] =
 {
+	{"RSD PTR ", "AMI   ", NULL, 0, ACPI_TRUST_TABLES | ACPI_COPY_TABLES},
 	{NULL, NULL, 0, 0},
 };
 
@@ -521,6 +528,51 @@
 }
 
 /*
+ * Match ACPI table and set options based on platform errata, if any
+ */
+static int __init acpi_find_errata(struct acpi_table *table)
+{
+	struct acpi_errata_info *info;
+	int size;
+
+	for (info = acpi_errata; info->signature && info->oem; info++) {
+		size = strlen(info->signature);
+		if (memcmp(&table->signature, info->signature, size))
+			continue;
+		if (strcmp(info->signature, "RSD PTR ")) {
+			// ordinary ACPI table
+			size = strlen(info->oem);
+			if (memcmp(table->oem, info->oem, size))
+				continue;
+			if (info->oem_table) {
+				size = strlen(info->oem_table);
+				if (memcmp(table->oem_table,
+					   info->oem_table,
+					   size))
+					continue;
+			}
+			if (info->oem_rev && table->oem_rev != info->oem_rev)
+				continue;
+		}
+		else {
+			// special handling for RSDP
+			size = strlen(info->oem);
+			if (memcmp(((struct acpi_rsdp*) table)->oem,
+				   info->oem,
+				   size))
+				continue;
+		}
+
+		printk(KERN_INFO
+		       "ACPI: found platform errata 0x%08lx\n",
+		       info->options);
+		acpi_opts |= info->options;
+		return 0;
+	}
+	return -1;
+}
+
+/*
  * Locate and map ACPI tables
  */
 static int __init acpi_find_tables(void)
@@ -556,6 +608,14 @@
 	if (i >= ACPI_BIOS_ROM_END)
 		return -ENODEV;
 
+	// find any errata based on the RSDP
+	if (!acpi_find_errata((struct acpi_table*) rsdp)) {
+		if (acpi_opts & ACPI_DISABLED)
+			return -EINVAL;
+		else if (acpi_opts & ACPI_CHIPSET_ONLY)
+			return -ENODEV;
+	}
+
 	// fetch RSDT from RSDP
 	rsdt = acpi_map_table(rsdp->rsdt);
 	if (!rsdt) {
@@ -569,6 +629,15 @@
 		acpi_unmap_table(rsdt);
 		return -EINVAL;
 	}
+
+	// find any errata based on the RSDT
+	if (!acpi_find_errata(rsdt)) {
+		if (acpi_opts & ACPI_DISABLED)
+			return -EINVAL;
+		else if (acpi_opts & ACPI_CHIPSET_ONLY)
+			return -ENODEV;
+	}
+
 	// search RSDT for FACP
 	acpi_facp.table = NULL;
 	rsdt_entry = (u32 *) (rsdt + 1);
@@ -631,11 +700,7 @@
 	if (!(pmregmisc & ACPI_PIIX4_PMIOSE))
 		return -ENODEV;
 	
-	pci_read_config_dword(dev, 0x40, &base);
-	if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
-		return -ENODEV;
-	
-	base &= PCI_BASE_ADDRESS_IO_MASK;
+	base = dev->resource[PCI_BRIDGE_RESOURCES].start & PCI_BASE_ADDRESS_IO_MASK;
 	if (!base)
 		return -ENODEV;
 
@@ -688,16 +753,13 @@
 	if (!(tmp & 0x80))
 		return -ENODEV;
 
-	pci_read_config_byte(dev, PCI_CLASS_REVISION, &tmp);
-	tmp = (tmp & 0x10 ? 0x48 : 0x20);
-
-	pci_read_config_dword(dev, tmp, &base);
-	if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
-		return -ENODEV;
-
+	base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES);
+	if (!base) {
+		base = pci_resource_start(dev, PCI_BASE_ADDRESS_4);
+		if (!base)
+			return -ENODEV;
+	}
 	base &= PCI_BASE_ADDRESS_IO_MASK;
-	if (!base)
-		return -ENODEV;
 
 	pci_read_config_byte(dev, 0x42, &irq);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- v2.3.99-pre6/linux/arch/i386/kernel/apic.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/kernel/apic.c	Mon May  8 15:57:02 2000
@@ -615,6 +615,7 @@
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
+	int user = user_mode(regs);
 	int cpu = smp_processor_id();
 
 	/*
@@ -623,6 +624,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) {
 		/*
@@ -640,7 +643,7 @@
 		}
 
 #ifdef CONFIG_SMP
-		handle_smp_time(user_mode(regs), cpu);
+		handle_smp_time(user, cpu);
 #endif
 	}
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.3.99-pre6/linux/arch/i386/kernel/pci-i386.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/pci-i386.c	Sat Apr 29 10:19:57 2000
@@ -330,12 +330,18 @@
  *  If we set up a device for bus mastering, we need to check the latency
  *  timer as certain crappy BIOSes forget to set it properly.
  */
+unsigned int pcibios_max_latency = 255;
+
 void pcibios_set_master(struct pci_dev *dev)
 {
 	u8 lat;
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-	if (lat < 16) {
-		printk("PCI: Increasing latency timer of device %s to 64\n", dev->slot_name);
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-	}
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h
--- v2.3.99-pre6/linux/arch/i386/kernel/pci-i386.h	Wed Apr 12 10:02:34 2000
+++ linux/arch/i386/kernel/pci-i386.h	Sat Apr 29 10:19:57 2000
@@ -25,6 +25,8 @@
 
 /* pci-i386.c */
 
+extern unsigned int pcibios_max_latency;
+
 void pcibios_resource_survey(void);
 int pcibios_enable_resources(struct pci_dev *);
 
@@ -64,5 +66,6 @@
 
 extern unsigned int pcibios_irq_mask;
 
+void pcibios_irq_init(void);
 void pcibios_fixup_irqs(void);
 int pcibios_lookup_irq(struct pci_dev *dev, int assign);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.3.99-pre6/linux/arch/i386/kernel/pci-irq.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/kernel/pci-irq.c	Wed May  3 11:39:45 2000
@@ -125,11 +125,22 @@
 	}
 }
 
+static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+	pirq--;
+	if (pirq < 8) {
+		u8 x;
+		unsigned reg = 0x48 + (pirq >> 1);
+		pci_read_config_byte(router, reg, &x);
+		return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)];
+	}
+	return 0;
+}
+
 static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
 {
-	static unsigned char irqmap[16] = {
-		0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15
-	};
+	static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
 	unsigned int val = irqmap[irq];
 	pirq--;
 	if (val && pirq < 8) {
@@ -211,7 +222,7 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
-	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL, pirq_ali_set },
+	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
@@ -236,7 +247,9 @@
 	}
 #endif
 	if (!(pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
-		DBG("PCI: Interrupt router not found\n");
+		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
+		/* fall back to default router */
+		pirq_router = pirq_routers + sizeof(pirq_routers) / sizeof(pirq_routers[0]) - 1;
 		return;
 	}
 	if (rt->rtr_vendor) {
@@ -354,12 +367,9 @@
 	return 1;
 }
 
-void __init pcibios_fixup_irqs(void)
+void __init pcibios_irq_init(void)
 {
-	struct pci_dev *dev;
-	u8 pin;
-
-	DBG("PCI: IRQ fixup\n");
+	DBG("PCI: IRQ init\n");
 	pirq_table = pirq_find_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
@@ -369,7 +379,14 @@
 		pirq_peer_trick();
 		pirq_find_router();
 	}
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	u8 pin;
 
+	DBG("PCI: IRQ fixup\n");
 	pci_for_each_dev(dev) {
 		/*
 		 * If the BIOS has set an out of range IRQ number, just ignore it.
@@ -416,7 +433,6 @@
 					dev->irq = irq;
 				}
 			}
-			pirq_table = NULL;	/* Avoid automatic IRQ assignment */
 		}
 #endif
 		/*
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.99-pre6/linux/arch/i386/kernel/pci-pc.c	Wed Apr 12 10:02:34 2000
+++ linux/arch/i386/kernel/pci-pc.c	Sat Apr 29 10:19:57 2000
@@ -10,6 +10,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -208,6 +209,7 @@
 			outl (tmp, 0xCF8);
 			__restore_flags(flags);
 			printk("PCI: Using configuration type 1\n");
+			request_region(0xCF8, 8, "PCI conf1");
 			return &pci_direct_conf1;
 		}
 		outl (tmp, 0xCF8);
@@ -224,6 +226,7 @@
 		    pci_sanity_check(&pci_direct_conf2)) {
 			__restore_flags(flags);
 			printk("PCI: Using configuration type 2\n");
+			request_region(0xCF8, 4, "PCI conf2");
 			return &pci_direct_conf2;
 		}
 	}
@@ -912,6 +915,16 @@
 		d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
 }
 
+static void __init pci_fixup_latency(struct pci_dev *d)
+{
+	/*
+	 *  SiS 5597 and 5598 chipsets require latency timer set to
+	 *  at most 32 to avoid lockups.
+	 */
+	DBG("PCI: Setting max latency to 32\n");
+	pcibios_max_latency = 32;
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
@@ -921,6 +934,8 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5513,		pci_fixup_ide_trash },
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
 	{ 0 }
 };
 
@@ -969,8 +984,9 @@
 	printk("PCI: Probing PCI hardware\n");
 	pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
 
-	pcibios_fixup_irqs();
+	pcibios_irq_init();
 	pcibios_fixup_peer_bridges();
+	pcibios_fixup_irqs();
 	pcibios_resource_survey();
 
 #ifdef CONFIG_PCI_BIOS
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.3.99-pre6/linux/arch/i386/kernel/ptrace.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/i386/kernel/ptrace.c	Fri May  5 12:22:54 2000
@@ -134,7 +134,6 @@
 {
 	struct task_struct *child;
 	struct user * dummy = NULL;
-	unsigned long flags;
 	int i, ret;
 
 	lock_kernel();
@@ -151,15 +150,19 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);	/* FIXME!!! */
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
+
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
-			goto out;
+			goto out_tsk;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
@@ -168,34 +171,33 @@
 	 	    (current->gid != child->sgid) ||
 	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
 	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
+			goto out_tsk;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
-			goto out;
+			goto out_tsk;
 		child->flags |= PF_PTRACED;
 
-		write_lock_irqsave(&tasklist_lock, flags);
+		write_lock_irq(&tasklist_lock);
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
 		}
-		write_unlock_irqrestore(&tasklist_lock, flags);
+		write_unlock_irq(&tasklist_lock);
 
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	if (!(child->flags & PF_PTRACED))
-		goto out;
+		goto out_tsk;
 	if (child->state != TASK_STOPPED) {
 		if (request != PTRACE_KILL)
-			goto out;
+			goto out_tsk;
 	}
 	if (child->p_pptr != current)
-		goto out;
-
+		goto out_tsk;
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -270,7 +272,7 @@
 				  data &= ~DR_CONTROL_RESERVED;
 				  for(i=0; i<4; i++)
 					  if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-						  goto out;
+						  goto out_tsk;
 			  }
 
 			  addr -= (long) &dummy->u_debugreg;
@@ -347,11 +349,11 @@
 			break;
 		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 		child->exit_code = data;
-		write_lock_irqsave(&tasklist_lock, flags);
+		write_lock_irq(&tasklist_lock);
 		REMOVE_LINKS(child);
 		child->p_pptr = child->p_opptr;
 		SET_LINKS(child);
-		write_unlock_irqrestore(&tasklist_lock, flags);
+		write_unlock_irq(&tasklist_lock);
 		/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 		put_stack_long(child, EFL_OFFSET, tmp);
@@ -435,6 +437,8 @@
 		ret = -EIO;
 		break;
 	}
+out_tsk:
+	free_task_struct(child);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.99-pre6/linux/arch/i386/kernel/setup.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/kernel/setup.c	Wed May 10 16:56:41 2000
@@ -32,9 +32,13 @@
  *	Added proper L2 cache detection for Coppermine
  *	Dragan Stancevic <visitor@valinux.com>, October 1999
  *
- *  Added the origninal array for capability flags but forgot to credit 
+ *  Added the original array for capability flags but forgot to credit 
  *  myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff
  *  	Jauder Ho <jauderho@carumba.com>, January 2000
+ *
+ *  Detection for Celeron coppermine, identify_cpu() overhauled,
+ *  and a few other clean ups.
+ *  Dave Jones <dave@powertweak.com>, April 2000
  *  	
  */
 
@@ -794,7 +798,7 @@
 
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
-	unsigned int n, dummy, *v, ecx, edx;
+	unsigned int n, dummy, *v;
 
 	/* Actually we must have cpuid or we could never have
 	 * figured out that this was AMD/Cyrix from the vendor info :-).
@@ -809,29 +813,6 @@
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
-	/*  Set MTRR capability flag if appropriate  */
-	
-	if(c->x86_vendor==X86_VENDOR_AMD)
-	{
-		if(boot_cpu_data.x86 == 5) {
-			if((boot_cpu_data.x86_model == 9) ||
-			   ((boot_cpu_data.x86_model == 8) && 
-			    (boot_cpu_data.x86_mask >= 8)))
-				c->x86_capability |= X86_FEATURE_MTRR;
-		}
-	
-		if (n >= 0x80000005){
-			cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-			printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK\n",
-				ecx>>24, edx>>24);
-			c->x86_cache_size=(ecx>>24)+(edx>>24);	
-		}
-		if (n >= 0x80000006){
-			cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
-			printk("CPU: L2 Cache: %dK\n", ecx>>16);
-			c->x86_cache_size=(ecx>>16);
-		}
-	}
 	return 1;
 }
 
@@ -839,14 +820,24 @@
 {
 	u32 l, h;
 	unsigned long flags;
+	unsigned int n, dummy, ecx, edx;
 	int mbytes = max_mapnr >> (20-PAGE_SHIFT);
-	
+
 	int r=get_model_name(c);
-	
+
 	/*
-	 *	Now do the cache operations. 
+	 * Set MTRR capability flag if appropriate
+	 */
+	if(boot_cpu_data.x86 == 5) {
+		if((boot_cpu_data.x86_model == 9) ||
+		   ((boot_cpu_data.x86_model == 8) && 
+		    (boot_cpu_data.x86_mask >= 8)))
+			c->x86_capability |= X86_FEATURE_MTRR;
+	}
+
+	/*
+	 * Now do the cache operations. 
 	 */
-	 
 	switch(c->x86)
 	{
 		case 5:
@@ -903,6 +894,20 @@
 		case 6:	/* An Athlon. We can trust the BIOS probably */
 			break;		
 	}
+
+	cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+	if (n >= 0x80000005) {
+		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+		printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK\n",
+			ecx>>24, edx>>24);
+		c->x86_cache_size=(ecx>>24)+(edx>>24);	
+	}
+	if (n >= 0x80000006) {
+		cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
+		printk("CPU: L2 Cache: %dK\n", ecx>>16);
+		c->x86_cache_size=(ecx>>16);
+	}
+
 	return r;
 }
 			
@@ -1029,13 +1034,13 @@
 		/* It isnt really a PCI quirk directly, but the cure is the
 		   same. The MediaGX has deep magic SMM stuff that handles the
 		   SB emulation. It thows away the fifo on disable_dma() which
-                   is wrong and ruins the audio. 
+		   is wrong and ruins the audio. 
                    
-                   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
-                   causes bad things. According to NatSemi VSA2 has another
-                   bug to do with 'hlt'. I've not seen any boards using VSA2
-                   and X doesn't seem to support it either so who cares 8).
-                   VSA1 we work around however.
+		   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
+		   causes bad things. According to NatSemi VSA2 has another
+		   bug to do with 'hlt'. I've not seen any boards using VSA2
+		   and X doesn't seem to support it either so who cares 8).
+		   VSA1 we work around however.
                    
 		*/
 		
@@ -1043,7 +1048,7 @@
 		isa_dma_bridge_buggy = 2;
 #endif		
 		c->x86_cache_size=16;	/* Yep 16K integrated cache thats it */
-		
+
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
 			get_model_name(c);  /* get CPU marketing name */
@@ -1256,7 +1261,7 @@
 
 void __init identify_cpu(struct cpuinfo_x86 *c)
 {
-	int i;
+	int i=0;
 	char *p = NULL;
 
 	c->loops_per_sec = loops_per_sec;
@@ -1264,100 +1269,118 @@
 
 	get_cpu_vendor(c);
 
-	if (c->x86_vendor == X86_VENDOR_UNKNOWN &&
-	    c->cpuid_level < 0)
-		return;
+	switch (c->x86_vendor) {
 
-	if (c->x86_vendor == X86_VENDOR_CYRIX) {
-		cyrix_model(c);
-		return;
-	}
+		case X86_VENDOR_UNKNOWN:
+			if (c->cpuid_level < 0)
+				return;
+			break;
 
-	if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
-		return;
+		case X86_VENDOR_CYRIX:
+			cyrix_model(c);
+			return;
 
-	if (c->x86_vendor == X86_VENDOR_CENTAUR) {
-		centaur_model(c);
-		return;
-	}
-		
-	if (c->cpuid_level > 0 && c->x86_vendor == X86_VENDOR_INTEL)
-	{
-		if(c->x86_capability&(1<<18))
-		{
-			/* Disable processor serial number on Intel Pentium III 
-			   from code by Phil Karn */
-			unsigned long lo,hi;
-			rdmsr(0x119,lo,hi);
-			lo |= 0x200000;
-			wrmsr(0x119,lo,hi);
-			printk(KERN_INFO "Pentium-III serial number disabled.\n");
-		}
-	}
+		case X86_VENDOR_AMD:
+			if (amd_model(c))
+				return;
+			break;
 
-	if (c->cpuid_level > 1) {
-		/* supports eax=2  call */
-		int edx, dummy;
-
-		cpuid(2, &dummy, &dummy, &dummy, &edx);
-
-		/* We need only the LSB */
-		edx &= 0xff;
-
-		switch (edx) {
-			case 0x40:
-				c->x86_cache_size = 0;
-				break;
+		case X86_VENDOR_CENTAUR:
+			centaur_model(c);
+			return;
 
-			case 0x41:
-				c->x86_cache_size = 128;
-				break;
+		case X86_VENDOR_INTEL:
+			if(c->x86_capability&(1<<18)) {
+				/* Disable processor serial number on Intel Pentium III 
+				   from code by Phil Karn */
+				unsigned long lo,hi;
+				rdmsr(0x119,lo,hi);
+				lo |= 0x200000;
+				wrmsr(0x119,lo,hi);
+				printk(KERN_INFO "Pentium-III serial number disabled.\n");
+			}
 
-			case 0x42:
-			case 0x82: /*Detect 256-Kbyte cache on Coppermine*/
-				c->x86_cache_size = 256;
-				break;
+			if (c->cpuid_level > 1) {
+				/* supports eax=2  call */
+				int edx, dummy;
+
+				cpuid(2, &dummy, &dummy, &dummy, &edx);
+
+				/* We need only the LSB */
+				edx &= 0xff;
+
+				switch (edx) {
+				case 0x40:
+					c->x86_cache_size = 0;
+					break;
 
-			case 0x43:
-				c->x86_cache_size = 512;
-				break;
+				case 0x41:
+					c->x86_cache_size = 128;
+					break;
 
-			case 0x44:
-				c->x86_cache_size = 1024;
-				break;
+				case 0x42:
+				case 0x82: /*Detect 256-Kbyte cache on Coppermine*/
+					c->x86_cache_size = 256;
+					break;
 
-			case 0x45:
-				c->x86_cache_size = 2048;
-				break;
+				case 0x43:
+					c->x86_cache_size = 512;
+					break;
 
-			default:
-				c->x86_cache_size = 0;
-				break;
-		}
-	}
+				case 0x44:
+					c->x86_cache_size = 1024;
+					break;
+
+				case 0x45:
+					c->x86_cache_size = 2048;
+					break;
+
+				default:
+					c->x86_cache_size = 0;
+					break;
+				}
+			}
 
+			/* Names for the Pentium II/Celeron processors 
+			   detectable only by also checking the cache size.
+			   Dixon is NOT a Celeron. */
+			if (c->x86 == 6) {
+				switch (c->x86_model) {
+					case 5:
+						if (c->x86_cache_size == 0)
+							p = "Celeron (Covington)";
+						if (c->x86_cache_size == 256)
+							p = "Mobile Pentium II (Dixon)";
+						break;
+
+					case 6:
+						if (c->x86_cache_size == 128)
+							p = "Celeron (Mendocino)";
+						break;
+
+					case 8:
+						if (c->x86_cache_size == 128)
+							p = "Celeron (Coppermine)";
+						break;
+				}
+			}
+			if (p!=NULL)
+				goto name_decoded;
+
+			break;
+	}
+	
+	
 	for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
 		if (cpu_models[i].vendor == c->x86_vendor &&
 		    cpu_models[i].x86 == c->x86) {
 			if (c->x86_model <= 16)
 				p = cpu_models[i].model_names[c->x86_model];
-
-			/* Names for the Pentium II/Celeron processors 
-                           detectable only by also checking the cache size.
-			   Dixon is NOT a Celeron. */
-			if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
-			    && (cpu_models[i].x86 == 6))
-			{
-			 	if(c->x86_model == 5 &&  c->x86_cache_size == 0)
-					p = "Celeron (Covington)";						
-				else if(c->x86_model == 6 && c->x86_cache_size == 128)
-                            		p = "Celeron (Mendocino)"; 
- 			  	else if(c->x86_model == 5 && c->x86_cache_size == 256)
-					p = "Mobile Pentium II (Dixon)";
-			}
 		}
 	}
 
+name_decoded:
+
 	if (p) {
 		strcpy(c->x86_model_id, p);
 		return;
@@ -1373,11 +1396,10 @@
 void __init dodgy_tsc(void)
 {
 	get_cpu_vendor(&boot_cpu_data);
-	
+
 	if(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)
-	{
 		return;
-	}
+
 	cyrix_model(&boot_cpu_data);
 }
 	
@@ -1442,15 +1464,15 @@
 			continue;
 #endif
 		p += sprintf(p,"processor\t: %d\n"
-			       "vendor_id\t: %s\n"
-			       "cpu family\t: %c\n"
-			       "model\t\t: %d\n"
-			       "model name\t: %s\n",
-			       n,
-			       c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
-			       c->x86 + '0',
-			       c->x86_model,
-			       c->x86_model_id[0] ? c->x86_model_id : "unknown");
+			"vendor_id\t: %s\n"
+			"cpu family\t: %c\n"
+			"model\t\t: %d\n"
+			"model name\t: %s\n",
+			n,
+			c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
+			c->x86 + '0',
+			c->x86_model,
+			c->x86_model_id[0] ? c->x86_model_id : "unknown");
 
 		if (c->x86_mask || c->cpuid_level >= 0)
 			p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
@@ -1470,32 +1492,32 @@
 		switch (c->x86_vendor) {
 
 		    case X86_VENDOR_CYRIX:
-			x86_cap_flags[24] = "cxmmx";
-			break;
+				x86_cap_flags[24] = "cxmmx";
+				break;
 
 		    case X86_VENDOR_AMD:
-			if (c->x86 == 5 && c->x86_model == 6)
-				x86_cap_flags[10] = "sep";
-			if (c->x86 < 6)
-				x86_cap_flags[16] = "fcmov";
-			x86_cap_flags[22] = "mmxext";
-			x86_cap_flags[30] = "3dnowext";
-			x86_cap_flags[31] = "3dnow";
-			break;
+				if (c->x86 == 5 && c->x86_model == 6)
+					x86_cap_flags[10] = "sep";
+				if (c->x86 < 6)
+					x86_cap_flags[16] = "fcmov";
+				x86_cap_flags[22] = "mmxext";
+				x86_cap_flags[30] = "3dnowext";
+				x86_cap_flags[31] = "3dnow";
+				break;
 
 		    case X86_VENDOR_INTEL:
-			x86_cap_flags[16] = "pat";
-			x86_cap_flags[24] = "fxsr";
-			break;
+				x86_cap_flags[16] = "pat";
+				x86_cap_flags[24] = "fxsr";
+				break;
 
 		    case X86_VENDOR_CENTAUR:
-			if (c->x86_model >=8)	/* Only Winchip2 and above */
-			    x86_cap_flags[31] = "3dnow";
-			break;
+				if (c->x86_model >=8)	/* Only Winchip2 and above */
+				    x86_cap_flags[31] = "3dnow";
+				break;
 
 		    default:
-			/* Unknown CPU manufacturer. Transmeta ? :-) */
-			break;
+				/* Unknown CPU manufacturer. Transmeta ? :-) */
+				break;
 		}
 
 		sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
@@ -1528,9 +1550,10 @@
 		for ( i = 0 ; i < 32 ; i++ )
 			if ( c->x86_capability & (1 << i) )
 				p += sprintf(p, " %s", x86_cap_flags[i]);
+
 		p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
-			     (c->loops_per_sec+2500)/500000,
-			     ((c->loops_per_sec+2500)/5000) % 100);
+			(c->loops_per_sec+2500)/500000,
+			((c->loops_per_sec+2500)/5000) % 100);
 	}
 	return p - buffer;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.99-pre6/linux/arch/i386/mm/fault.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/i386/mm/fault.c	Tue May  2 17:10:22 2000
@@ -192,12 +192,17 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	{
-		int fault = handle_mm_fault(mm, vma, address, write);
-		if (fault < 0)
-			goto out_of_memory;
-		if (!fault)
-			goto do_sigbus;
+	switch (handle_mm_fault(mm, vma, address, write)) {
+	case 1:
+		tsk->min_flt++;
+		break;
+	case 2:
+		tsk->maj_flt++;
+		break;
+	case 0:
+		goto do_sigbus;
+	default:
+		goto out_of_memory;
 	}
 
 	/*
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ia64/defconfig linux/arch/ia64/defconfig
--- v2.3.99-pre6/linux/arch/ia64/defconfig	Wed Apr 26 16:34:06 2000
+++ linux/arch/ia64/defconfig	Mon May  8 22:00:41 2000
@@ -242,6 +242,7 @@
 # CONFIG_HPFS_FS is not set
 # CONFIG_PROC_FS is not set
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ia64/sn/sn1/setup.c linux/arch/ia64/sn/sn1/setup.c
--- v2.3.99-pre6/linux/arch/ia64/sn/sn1/setup.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/sn/sn1/setup.c	Mon May  8 22:00:01 2000
@@ -70,7 +70,7 @@
 	outb(LATCH >> 8, 0x40);	     /* MSB */
 	printk("PIT: LATCH at 0x%x%x for %d HZ\n", LATCH >> 8, LATCH & 0xff, HZ);
 #endif
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	init_smp_config();
 #endif
 	screen_info = sn1_screen_info;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.3.99-pre6/linux/arch/m68k/atari/atakeyb.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/atari/atakeyb.c	Fri May  5 12:37:52 2000
@@ -287,8 +287,8 @@
 	/* A keyboard int may have come in before we disabled the irq, so
 	 * double-check whether rep_scancode is still != 0 */
 	if (rep_scancode) {
+		init_timer(&atakeyb_rep_timer);
 		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
-		atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
 		add_timer( &atakeyb_rep_timer );
 
 		handle_scancode(rep_scancode, 1);
@@ -444,7 +444,6 @@
 		    del_timer( &atakeyb_rep_timer );
 		    rep_scancode = scancode;
 		    atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
-		    atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
 		    add_timer( &atakeyb_rep_timer );
 		}
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.3.99-pre6/linux/arch/m68k/defconfig	Tue Apr 11 15:09:13 2000
+++ linux/arch/m68k/defconfig	Mon May  8 22:00:41 2000
@@ -235,6 +235,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.3.99-pre6/linux/arch/mips/defconfig	Tue Apr 11 15:09:13 2000
+++ linux/arch/mips/defconfig	Mon May  8 22:00:41 2000
@@ -360,6 +360,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips/defconfig-ip22 linux/arch/mips/defconfig-ip22
--- v2.3.99-pre6/linux/arch/mips/defconfig-ip22	Fri Mar 10 16:40:40 2000
+++ linux/arch/mips/defconfig-ip22	Mon May  8 22:00:41 2000
@@ -314,6 +314,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S
--- v2.3.99-pre6/linux/arch/mips/kernel/head.S	Sat Feb 26 22:31:40 2000
+++ linux/arch/mips/kernel/head.S	Mon May  8 22:00:01 2000
@@ -157,7 +157,7 @@
 	eret
 	END(except_vec0_r45k_bvahwbug)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */
 	LEAF(except_vec0_r4k_mphwbug)
 	.set	mips3
@@ -216,7 +216,7 @@
 	eret
 	END(except_vec0_r4k_250MHZhwbug)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */
 	LEAF(except_vec0_r4k_MP250MHZhwbug)
 	.set	mips3
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.99-pre6/linux/arch/mips/kernel/sysirix.c	Wed Apr 26 16:34:06 2000
+++ linux/arch/mips/kernel/sysirix.c	Mon May  8 11:17:47 2000
@@ -724,7 +724,7 @@
 asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
 			   int len, int fs_type)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	struct statfs kbuf;
 	int error, i;
 
@@ -738,12 +738,11 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
 	if (error)
 		goto out;
-	dentry = namei(path);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	error = user_path_walk(path, &nd);
+	if (error)
 		goto out;
 
-	error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
 	if (error)
 		goto dput_and_out;
 
@@ -761,7 +760,7 @@
 	error = 0;
 
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return error;
@@ -1484,7 +1483,7 @@
 
 asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	struct statfs kbuf;
 	int error, i;
 
@@ -1494,11 +1493,10 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if(error)
 		goto out;
-	dentry = namei(fname);
-	error = PTR_ERR(dentry);
-	if(!IS_ERR(dentry))
+	error = user_path_walk(fname, &nd);
+	if (err)
 		goto out;
-	error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
 	if (error)
 		goto dput_and_out;
 
@@ -1525,7 +1523,7 @@
 	error = 0;
 
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return error;
@@ -1759,7 +1757,7 @@
 
 asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	struct statfs kbuf;
 	int error, i;
 
@@ -1769,11 +1767,10 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if(error)
 		goto out;
-	dentry = namei(fname);
-	error = PTR_ERR(dentry);
-	if(IS_ERR(dentry))
+	error = user_path_walk(fname, &nd);
+	if (error)
 		goto out;
-	error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
 	if (error)
 		goto dput_and_out;
 
@@ -1800,7 +1797,7 @@
 	error = 0;
 
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips/sgi/kernel/reset.c linux/arch/mips/sgi/kernel/reset.c
--- v2.3.99-pre6/linux/arch/mips/sgi/kernel/reset.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips/sgi/kernel/reset.c	Fri Apr 28 22:50:12 2000
@@ -88,9 +88,7 @@
 	sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF);
 	hpc3mregs->write1 = sgi_hpc_write1;
 
-	del_timer(&blink_timer);
-	blink_timer.expires = jiffies + data;
-	add_timer(&blink_timer);
+	mod_timer(&blink_timer, jiffies+data);
 }
 
 static void debounce(unsigned long data)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips64/defconfig linux/arch/mips64/defconfig
--- v2.3.99-pre6/linux/arch/mips64/defconfig	Tue Apr 11 15:09:13 2000
+++ linux/arch/mips64/defconfig	Mon May  8 22:00:41 2000
@@ -349,6 +349,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22
--- v2.3.99-pre6/linux/arch/mips64/defconfig-ip22	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips64/defconfig-ip22	Mon May  8 22:00:41 2000
@@ -268,6 +268,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips64/kernel/entry.S linux/arch/mips64/kernel/entry.S
--- v2.3.99-pre6/linux/arch/mips64/kernel/entry.S	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips64/kernel/entry.S	Mon May  8 22:00:01 2000
@@ -9,6 +9,7 @@
  * Copyright (C) 1994 - 2000 by Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics
  */
+#include <linux/config.h>
 #include <asm/asm.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
@@ -33,7 +34,7 @@
 
 FEXPORT(ret_from_sys_call)
 FEXPORT(ret_from_irq)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error Barffff...
 #else
 		la	t1, softirq_state
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/mips64/sgi-ip22/ip22-reset.c linux/arch/mips64/sgi-ip22/ip22-reset.c
--- v2.3.99-pre6/linux/arch/mips64/sgi-ip22/ip22-reset.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips64/sgi-ip22/ip22-reset.c	Fri Apr 28 22:50:12 2000
@@ -87,9 +87,7 @@
 	sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF);
 	hpc3mregs->write1 = sgi_hpc_write1;
 
-	del_timer(&blink_timer);
-	blink_timer.expires = jiffies + data;
-	add_timer(&blink_timer);
+	mod_timer(&blink_timer, jiffies+data);
 }
 
 static void debounce(unsigned long data)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8260_io/Config.in linux/arch/ppc/8260_io/Config.in
--- v2.3.99-pre6/linux/arch/ppc/8260_io/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/Config.in	Tue May  2 13:05:39 2000
@@ -0,0 +1,22 @@
+#
+# MPC8260 Communication options
+#
+if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'MPC8260 Communication Options'
+  bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
+  if [ "$CONFIG_SCC_ENET" = "y" ]; then
+  bool 'Ethernet on SCC1' CONFIG_SCC1_ENET
+    if [ "$CONFIG_SCC1_ENET" != "y" ]; then
+      bool 'Ethernet on SCC2' CONFIG_SCC2_ENET
+    fi
+  fi
+  bool 'FCC Ethernet' CONFIG_FCC_ENET
+  if [ "$CONFIG_FCC_ENET" = "y" ]; then
+  bool 'Ethernet on FCC1' CONFIG_FCC1_ENET
+    if [ "$CONFIG_FCC1_ENET" != "y" ]; then
+      bool 'Ethernet on FCC2' CONFIG_FCC2_ENET
+    fi
+  fi
+  endmenu
+fi
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8260_io/Makefile linux/arch/ppc/8260_io/Makefile
--- v2.3.99-pre6/linux/arch/ppc/8260_io/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/Makefile	Tue May  2 13:05:39 2000
@@ -0,0 +1,20 @@
+#
+# Makefile for the linux MPC8xx ppc-specific parts of comm processor
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := 8260_io.a
+O_OBJS	= commproc.o uart.o
+
+ifdef CONFIG_FCC_ENET
+O_OBJS += fcc.o
+endif
+ifdef CONFIG_SCC_ENET
+O_OBJS += enet.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8260_io/commproc.c linux/arch/ppc/8260_io/commproc.c
--- v2.3.99-pre6/linux/arch/ppc/8260_io/commproc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/commproc.c	Wed May  3 01:47:56 2000
@@ -0,0 +1,162 @@
+
+/*
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ *	2.3.99 Updates
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <asm/irq.h>
+#include <asm/mpc8260.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/immap_8260.h>
+#include <asm/cpm_8260.h>
+
+static	uint	dp_alloc_base;	/* Starting offset in DP ram */
+static	uint	dp_alloc_top;	/* Max offset + 1 */
+static	uint	host_buffer;	/* One page of host buffer */
+static	uint	host_end;	/* end + 1 */
+cpm8260_t	*cpmp;		/* Pointer to comm processor space */
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+immap_t		*immr;
+
+void
+m8260_cpm_reset(void)
+{
+	volatile immap_t	 *imp;
+	volatile cpm8260_t	*commproc;
+	uint			vpgaddr;
+
+	immr = imp = (volatile immap_t *)IMAP_ADDR;
+	commproc = &imp->im_cpm;
+
+	/* Reclaim the DP memory for our use.
+	*/
+	dp_alloc_base = CPM_DATAONLY_BASE;
+	dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
+	/* Set the host page for allocation.
+	*/
+	host_buffer =
+		(uint) alloc_bootmem_pages(PAGE_SIZE * NUM_CPM_HOST_PAGES);
+	host_end = host_buffer + (PAGE_SIZE * NUM_CPM_HOST_PAGES);
+
+	vpgaddr = host_buffer;
+
+	/* Tell everyone where the comm processor resides.
+	*/
+	cpmp = (cpm8260_t *)commproc;
+}
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint
+m8260_cpm_dpalloc(uint size)
+{
+	uint	retloc;
+
+	if ((dp_alloc_base + size) >= dp_alloc_top)
+		return(CPM_DP_NOSPACE);
+
+	retloc = dp_alloc_base;
+	dp_alloc_base += size;
+
+	return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8260_cpm_hostalloc(uint size)
+{
+	uint	retloc;
+
+	if ((host_buffer + size) >= host_end)
+		return(0);
+
+	retloc = host_buffer;
+	host_buffer += size;
+
+	return(retloc);
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks.  The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers).  Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK	(((bd_t *)__res)->bi_brgfreq * 1000000)
+#define BRG_UART_CLK	(BRG_INT_CLK/16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+m8260_cpm_setbrg(uint brg, uint rate)
+{
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+m8260_cpm_fastbrg(uint brg, uint rate, int div16)
+{
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+	if (div16)
+		*bp |= CPM_BRG_DIV16;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8260_io/enet.c linux/arch/ppc/8260_io/enet.c
--- v2.3.99-pre6/linux/arch/ppc/8260_io/enet.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/enet.c	Wed May  3 01:47:56 2000
@@ -0,0 +1,856 @@
+/*
+ * Ethernet driver for Motorola MPC8260.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com)
+ *	2.3.99 Updates
+ *
+ * I copied this from the 8xx CPM Ethernet driver, so follow the
+ * credits back through that.
+ *
+ * This version of the driver is somewhat selectable for the different
+ * processor/board combinations.  It works for the boards I know about
+ * now, and should be easily modified to include others.  Some of the
+ * configuration information is contained in "commproc.h" and the
+ * remainder is here.
+ *
+ * Buffer descriptors are kept in the CPM dual port RAM, and the frame
+ * buffers are in the host memory.
+ *
+ * Right now, I am very watseful with the buffers.  I allocate memory
+ * pages and then divide them into 2K frame buffers.  This way I know I
+ * have buffers large enough to hold one frame within one buffer descriptor.
+ * Once I get this working, I will use 64 or 128 byte CPM buffers, which
+ * will be much more memory efficient and will easily handle lots of
+ * small packets.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.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/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+#include <asm/immap_8260.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8260.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/cpm_8260.h>
+#include <asm/irq.h>
+
+/*
+ *				Theory of Operation
+ *
+ * The MPC8260 CPM performs the Ethernet processing on an SCC.  It can use
+ * an aribtrary number of buffers on byte boundaries, but must have at
+ * least two receive buffers to prevent constant overrun conditions.
+ *
+ * The buffer descriptors are allocated from the CPM dual port memory
+ * with the data buffers allocated from host memory, just like all other
+ * serial communication protocols.  The host memory buffers are allocated
+ * from the free page pool, and then divided into smaller receive and
+ * transmit buffers.  The size of the buffers should be a power of two,
+ * since that nicely divides the page.  This creates a ring buffer
+ * structure similar to the LANCE and other controllers.
+ *
+ * Like the LANCE driver:
+ * The driver runs as two independent, single-threaded flows of control.  One
+ * is the send-packet routine, which enforces single-threaded use by the
+ * cep->tx_busy flag.  The other thread is the interrupt handler, which is
+ * single threaded by the hardware and other software.
+ */
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
+/* The number of Tx and Rx buffers.  These are allocated from the page
+ * pool.  The code may assume these are power of two, so it is best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter.  We just use
+ * the skbuffer directly.
+ */
+#define CPM_ENET_RX_PAGES	4
+#define CPM_ENET_RX_FRSIZE	2048
+#define CPM_ENET_RX_FRPPG	(PAGE_SIZE / CPM_ENET_RX_FRSIZE)
+#define RX_RING_SIZE		(CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES)
+#define TX_RING_SIZE		8	/* Must be power of two */
+#define TX_RING_MOD_MASK	7	/*   for this to work */
+
+/* The CPM stores dest/src/type, data, and checksum for receive packets.
+ */
+#define PKT_MAXBUF_SIZE		1518
+#define PKT_MINBUF_SIZE		64
+#define PKT_MAXBLR_SIZE		1520
+
+/* The CPM buffer descriptors track the ring buffers.  The rx_bd_base and
+ * tx_bd_base always point to the base of the buffer descriptors.  The
+ * cur_rx and cur_tx point to the currently available buffer.
+ * The dirty_tx tracks the current buffer that is being sent by the
+ * controller.  The cur_tx and dirty_tx are equal under both completely
+ * empty and completely full conditions.  The empty/ready indicator in
+ * the buffer descriptor determines the actual condition.
+ */
+struct scc_enet_private {
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct	sk_buff* tx_skbuff[TX_RING_SIZE];
+	ushort	skb_cur;
+	ushort	skb_dirty;
+
+	/* CPM dual port RAM relative addresses.
+	*/
+	cbd_t	*rx_bd_base;		/* Address of Rx and Tx buffers. */
+	cbd_t	*tx_bd_base;
+	cbd_t	*cur_rx, *cur_tx;		/* The next free ring entry */
+	cbd_t	*dirty_tx;	/* The ring entries to be free()ed. */
+	scc_t	*sccp;
+	struct	net_device_stats stats;
+	uint	tx_full;
+	spinlock_t lock;
+};
+
+static int scc_enet_open(struct net_device *dev);
+static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int scc_enet_rx(struct net_device *dev);
+static void scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static int scc_enet_close(struct net_device *dev);
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+
+/* These will be configurable for the SCC choice.
+*/
+#define CPM_ENET_BLOCK	CPM_CR_SCC1_SBLOCK
+#define CPM_ENET_PAGE	CPM_CR_SCC1_PAGE
+#define PROFF_ENET	PROFF_SCC1
+#define SCC_ENET	0
+#define SIU_INT_ENET	SIU_INT_SCC1
+
+/* These are both board and SCC dependent....
+*/
+#define PD_ENET_RXD	((uint)0x00000001)
+#define PD_ENET_TXD	((uint)0x00000002)
+#define PD_ENET_TENA	((uint)0x00000004)
+#define PC_ENET_RENA	((uint)0x00020000)
+#define PC_ENET_CLSN	((uint)0x00000004)
+#define PC_ENET_TXCLK	((uint)0x00000800)
+#define PC_ENET_RXCLK	((uint)0x00000400)
+#define CMX_CLK_ROUTE	((uint)0x25000000)
+#define CMX_CLK_MASK	((uint)0xff000000)
+
+/* Specific to a board.
+*/
+#define PC_EST8260_ENET_LOOPBACK	((uint)0x80000000)
+#define PC_EST8260_ENET_SQE		((uint)0x40000000)
+#define PC_EST8260_ENET_NOTFD		((uint)0x20000000)
+
+static int
+scc_enet_open(struct net_device *dev)
+{
+
+	/* I should reset the ring buffers here, but I don't yet know
+	 * a simple way to do that.
+	 */
+	netif_start_queue(dev);
+	return 0;					/* Always succeed */
+}
+
+static int
+scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
+	volatile cbd_t	*bdp;
+
+
+	/* Fill in a Tx ring entry */
+	bdp = cep->cur_tx;
+
+#ifndef final_version
+	if (bdp->cbd_sc & BD_ENET_TX_READY) {
+		/* Ooops.  All transmit buffers are full.  Bail out.
+		 * This should not happen, since cep->tx_busy should be set.
+		 */
+		printk("%s: tx queue full!.\n", dev->name);
+		return 1;
+	}
+#endif
+
+	/* Clear all of the status flags.
+	 */
+	bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+
+	/* If the frame is short, tell CPM to pad it.
+	*/
+	if (skb->len <= ETH_ZLEN)
+		bdp->cbd_sc |= BD_ENET_TX_PAD;
+	else
+		bdp->cbd_sc &= ~BD_ENET_TX_PAD;
+
+	/* Set buffer length and buffer pointer.
+	*/
+	bdp->cbd_datlen = skb->len;
+	bdp->cbd_bufaddr = __pa(skb->data);
+
+	/* Save skb pointer.
+	*/
+	cep->tx_skbuff[cep->skb_cur] = skb;
+
+	cep->stats.tx_bytes += skb->len;
+	cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+	
+	/* Push the data cache so the CPM does not get stale memory
+	 * data.
+	 */
+	flush_dcache_range((unsigned long)(skb->data),
+					(unsigned long)(skb->data + skb->len));
+
+	spin_lock_irq(&cep->lock);
+
+	/* Send it on its way.  Tell CPM its ready, interrupt when done,
+	 * its the last BD of the frame, and to put the CRC on the end.
+	 */
+	bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+
+	dev->trans_start = jiffies;
+
+	/* If this was the last BD in the ring, start at the beginning again.
+	*/
+	if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+		bdp = cep->tx_bd_base;
+	else
+		bdp++;
+
+	if (bdp->cbd_sc & BD_ENET_TX_READY)
+		netif_stop_queue(dev);
+
+	cep->cur_tx = (cbd_t *)bdp;
+
+	spin_unlock_irq(&cep->lock);
+
+	return 0;
+}
+
+static void
+scc_enet_timeout(struct net_device *dev)
+{
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
+
+	printk("%s: transmit timed out.\n", dev->name);
+	cep->stats.tx_errors++;
+#ifndef final_version
+	{
+		int	i;
+		cbd_t	*bdp;
+		printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
+		       cep->cur_tx, cep->tx_full ? " (full)" : "",
+		       cep->cur_rx);
+		bdp = cep->tx_bd_base;
+		for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
+			printk("%04x %04x %08x\n",
+			       bdp->cbd_sc,
+			       bdp->cbd_datlen,
+			       bdp->cbd_bufaddr);
+		bdp = cep->rx_bd_base;
+		for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
+			printk("%04x %04x %08x\n",
+			       bdp->cbd_sc,
+			       bdp->cbd_datlen,
+			       bdp->cbd_bufaddr);
+	}
+#endif
+	if (!cep->tx_full)
+		netif_wake_queue(dev);
+}
+
+/* The interrupt handler.
+ * This is called from the CPM handler, not the MPC core interrupt.
+ */
+static void
+scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+	struct	net_device *dev = dev_id;
+	volatile struct	scc_enet_private *cep;
+	volatile cbd_t	*bdp;
+	ushort	int_events;
+	int	must_restart;
+
+	cep = (struct scc_enet_private *)dev->priv;
+
+	/* Get the interrupt events that caused us to be here.
+	*/
+	int_events = cep->sccp->scc_scce;
+	cep->sccp->scc_scce = int_events;
+	must_restart = 0;
+
+	/* Handle receive event in its own function.
+	*/
+	if (int_events & SCCE_ENET_RXF)
+		scc_enet_rx(dev_id);
+
+	/* Check for a transmit error.  The manual is a little unclear
+	 * about this, so the debug code until I get it figured out.  It
+	 * appears that if TXE is set, then TXB is not set.  However,
+	 * if carrier sense is lost during frame transmission, the TXE
+	 * bit is set, "and continues the buffer transmission normally."
+	 * I don't know if "normally" implies TXB is set when the buffer
+	 * descriptor is closed.....trial and error :-).
+	 */
+
+	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.
+	*/
+	if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+	    spin_lock(&cep->lock);
+	    bdp = cep->dirty_tx;
+	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
+		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+		    break;
+
+		if (bdp->cbd_sc & BD_ENET_TX_HB)	/* No heartbeat */
+			cep->stats.tx_heartbeat_errors++;
+		if (bdp->cbd_sc & BD_ENET_TX_LC)	/* Late collision */
+			cep->stats.tx_window_errors++;
+		if (bdp->cbd_sc & BD_ENET_TX_RL)	/* Retrans limit */
+			cep->stats.tx_aborted_errors++;
+		if (bdp->cbd_sc & BD_ENET_TX_UN)	/* Underrun */
+			cep->stats.tx_fifo_errors++;
+		if (bdp->cbd_sc & BD_ENET_TX_CSL)	/* Carrier lost */
+			cep->stats.tx_carrier_errors++;
+
+
+		/* No heartbeat or Lost carrier are not really bad errors.
+		 * The others require a restart transmit command.
+		 */
+		if (bdp->cbd_sc &
+		    (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
+			must_restart = 1;
+			cep->stats.tx_errors++;
+		}
+
+		cep->stats.tx_packets++;
+
+		/* Deferred means some collisions occurred during transmit,
+		 * but we eventually sent the packet OK.
+		 */
+		if (bdp->cbd_sc & BD_ENET_TX_DEF)
+			cep->stats.collisions++;
+
+		/* Free the sk buffer associated with this last transmit.
+		*/
+		dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
+		cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+		/* Update pointer to next buffer descriptor to be transmitted.
+		*/
+		if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+			bdp = cep->tx_bd_base;
+		else
+			bdp++;
+
+		/* I don't know if we can be held off from processing these
+		 * interrupts for more than one frame time.  I really hope
+		 * not.  In such a case, we would now want to check the
+		 * currently available BD (cur_tx) and determine if any
+		 * buffers between the dirty_tx and cur_tx have also been
+		 * sent.  We would want to process anything in between that
+		 * does not have BD_ENET_TX_READY set.
+		 */
+
+		/* Since we have freed up a buffer, the ring is no longer
+		 * full.
+		 */
+		if (cep->tx_full) {
+			if (netif_queue_stopped(dev)) {
+				netif_wake_queue(dev);
+			}
+		}
+
+		cep->dirty_tx = (cbd_t *)bdp;
+	    }
+
+	    if (must_restart) {
+		volatile cpm8260_t *cp;
+
+		/* Some transmit errors cause the transmitter to shut
+		 * down.  We now issue a restart transmit.  Since the
+		 * errors close the BD and update the pointers, the restart
+		 * _should_ pick up without having to reset any of our
+		 * pointers either.
+		 */
+		cp = cpmp;
+		cp->cp_cpcr =
+		    mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0,
+		    			CPM_CR_RESTART_TX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	    }
+	    spin_unlock(&cep->lock);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them.  This "can't happen" because the receive interrupt
+	 * is tossing previous frames.
+	 */
+	if (int_events & SCCE_ENET_BSY) {
+		cep->stats.rx_dropped++;
+		printk("SCC ENET: BSY can't happen.\n");
+	}
+
+	return;
+}
+
+/* During a receive, the cur_rx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static int
+scc_enet_rx(struct net_device *dev)
+{
+	struct	scc_enet_private *cep;
+	volatile cbd_t	*bdp;
+	struct	sk_buff *skb;
+	ushort	pkt_len;
+
+	cep = (struct scc_enet_private *)dev->priv;
+
+	/* First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	bdp = cep->cur_rx;
+
+for (;;) {
+	if (bdp->cbd_sc & BD_ENET_RX_EMPTY)
+		break;
+		
+#ifndef final_version
+	/* Since we have allocated space to hold a complete frame, both
+	 * the first and last indicators should be set.
+	 */
+	if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) !=
+		(BD_ENET_RX_FIRST | BD_ENET_RX_LAST))
+			printk("CPM ENET: rcv is not first+last\n");
+#endif
+
+	/* Frame too long or too short.
+	*/
+	if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+		cep->stats.rx_length_errors++;
+	if (bdp->cbd_sc & BD_ENET_RX_NO)	/* Frame alignment */
+		cep->stats.rx_frame_errors++;
+	if (bdp->cbd_sc & BD_ENET_RX_CR)	/* CRC Error */
+		cep->stats.rx_crc_errors++;
+	if (bdp->cbd_sc & BD_ENET_RX_OV)	/* FIFO overrun */
+		cep->stats.rx_crc_errors++;
+
+	/* Report late collisions as a frame error.
+	 * On this error, the BD is closed, but we don't know what we
+	 * have in the buffer.  So, just drop this frame on the floor.
+	 */
+	if (bdp->cbd_sc & BD_ENET_RX_CL) {
+		cep->stats.rx_frame_errors++;
+	}
+	else {
+
+		/* Process the incoming frame.
+		*/
+		cep->stats.rx_packets++;
+		pkt_len = bdp->cbd_datlen;
+		cep->stats.rx_bytes += pkt_len;
+
+		/* This does 16 byte alignment, much more than we need.
+		*/
+		skb = dev_alloc_skb(pkt_len);
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			cep->stats.rx_dropped++;
+		}
+		else {
+			skb->dev = dev;
+			skb_put(skb,pkt_len);	/* Make room */
+			eth_copy_and_sum(skb,
+				(unsigned char *)__va(bdp->cbd_bufaddr),
+				pkt_len, 0);
+			skb->protocol=eth_type_trans(skb,dev);
+			netif_rx(skb);
+		}
+	}
+
+	/* Clear the status flags for this buffer.
+	*/
+	bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+
+	/* Mark the buffer empty.
+	*/
+	bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+
+	/* Update BD pointer to next entry.
+	*/
+	if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+		bdp = cep->rx_bd_base;
+	else
+		bdp++;
+
+   }
+	cep->cur_rx = (cbd_t *)bdp;
+
+	return 0;
+}
+
+static int
+scc_enet_close(struct net_device *dev)
+{
+	/* Don't know what to do yet.
+	*/
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev)
+{
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
+
+	return &cep->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ * Skeleton taken from sunlance driver.
+ * The CPM Ethernet implementation allows Multicast as well as individual
+ * MAC address filtering.  Some of the drivers check to make sure it is
+ * a group multicast address, and discard those that are not.  I guess I
+ * will do the same for now, but just remove the test if you want
+ * individual filtering as well (do the upper net layers want or support
+ * this kind of feature?).
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+	struct	scc_enet_private *cep;
+	struct	dev_mc_list *dmi;
+	u_char	*mcptr, *tdptr;
+	volatile scc_enet_t *ep;
+	int	i, j;
+	cep = (struct scc_enet_private *)dev->priv;
+
+	/* Get pointer to SCC area in parameter RAM.
+	*/
+	ep = (scc_enet_t *)dev->base_addr;
+
+	if (dev->flags&IFF_PROMISC) {
+	  
+		/* Log any net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		cep->sccp->scc_pmsr |= SCC_PMSR_PRO;
+	} else {
+
+		cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			ep->sen_gaddr1 = 0xffff;
+			ep->sen_gaddr2 = 0xffff;
+			ep->sen_gaddr3 = 0xffff;
+			ep->sen_gaddr4 = 0xffff;
+		}
+		else {
+			/* Clear filter and add the addresses in the list.
+			*/
+			ep->sen_gaddr1 = 0;
+			ep->sen_gaddr2 = 0;
+			ep->sen_gaddr3 = 0;
+			ep->sen_gaddr4 = 0;
+
+			dmi = dev->mc_list;
+
+			for (i=0; i<dev->mc_count; i++) {
+				
+				/* Only support group multicast for now.
+				*/
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				/* The address in dmi_addr is LSB first,
+				 * and taddr is MSB first.  We have to
+				 * copy bytes MSB first from dmi_addr.
+				 */
+				mcptr = (u_char *)dmi->dmi_addr + 5;
+				tdptr = (u_char *)&ep->sen_taddrh;
+				for (j=0; j<6; j++)
+					*tdptr++ = *mcptr--;
+
+				/* Ask CPM to run CRC and set bit in
+				 * filter mask.
+				 */
+				cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE,
+						CPM_ENET_BLOCK, 0,
+						CPM_CR_SET_GADDR) | CPM_CR_FLG;
+				/* this delay is necessary here -- Cort */
+				udelay(10);
+				while (cpmp->cp_cpcr & CPM_CR_FLG);
+			}
+		}
+	}
+}
+
+/* Initialize the CPM Ethernet on SCC.
+ */
+int __init scc_enet_init(void)
+{
+	struct net_device *dev;
+	struct scc_enet_private *cep;
+	int i, j;
+	unsigned char	*eap;
+	unsigned long	mem_addr;
+	bd_t		*bd;
+	volatile	cbd_t		*bdp;
+	volatile	cpm8260_t	*cp;
+	volatile	scc_t		*sccp;
+	volatile	scc_enet_t	*ep;
+	volatile	immap_t		*immap;
+	volatile	iop8260_t	*io;
+
+	cp = cpmp;	/* Get pointer to Communication Processor */
+
+	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
+	io = &immap->im_ioport;
+
+	bd = (bd_t *)__res;
+
+	/* Allocate some private information.
+	*/
+	cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+	__clear_user(cep,sizeof(*cep));
+	spin_lock_init(&cep->lock);
+
+	/* Create an Ethernet device instance.
+	*/
+	dev = init_etherdev(0, 0);
+
+	/* Get pointer to SCC area in parameter RAM.
+	*/
+	ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]);
+
+	/* And another to the SCC register area.
+	*/
+	sccp = (volatile scc_t *)(&immap->im_scc[SCC_ENET]);
+	cep->sccp = (scc_t *)sccp;		/* Keep the pointer handy */
+
+	/* Disable receive and transmit in case someone left it running.
+	*/
+	sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* Configure port C and D pins for SCC Ethernet.  This
+	 * won't work for all SCC possibilities....it will be
+	 * board/port specific.
+	 */
+	io->iop_pparc |=
+		(PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK);
+	io->iop_pdirc &=
+		~(PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK);
+	io->iop_psorc &= 
+		~(PC_ENET_RENA | PC_ENET_TXCLK | PC_ENET_RXCLK);
+	io->iop_psorc |= PC_ENET_CLSN;
+
+	io->iop_ppard |= (PD_ENET_RXD | PD_ENET_TXD | PD_ENET_TENA);
+	io->iop_pdird |= (PD_ENET_TXD | PD_ENET_TENA);
+	io->iop_pdird &= ~PD_ENET_RXD;
+	io->iop_psord |= PD_ENET_TXD;
+	io->iop_psord &= ~(PD_ENET_RXD | PD_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	immap->im_cpmux.cmx_scr &= ~CMX_CLK_MASK;
+	immap->im_cpmux.cmx_scr |= CMX_CLK_ROUTE;
+
+	/* Allocate space for the buffer descriptors in the DP ram.
+	 * These are relative offsets in the DP ram address space.
+	 * Initialize base addresses for the buffer descriptors.
+	 */
+	i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);
+	ep->sen_genscc.scc_rbase = i;
+	cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i];
+
+	i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);
+	ep->sen_genscc.scc_tbase = i;
+	cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i];
+
+	cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
+	cep->cur_rx = cep->rx_bd_base;
+
+	ep->sen_genscc.scc_rfcr = SCC_EB;
+	ep->sen_genscc.scc_tfcr = SCC_EB;
+
+	/* Set maximum bytes per receive buffer.
+	 * This appears to be an Ethernet frame size, not the buffer
+	 * fragment size.  It must be a multiple of four.
+	 */
+	ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE;
+
+	/* Set CRC preset and mask.
+	*/
+	ep->sen_cpres = 0xffffffff;
+	ep->sen_cmask = 0xdebb20e3;
+
+	ep->sen_crcec = 0;	/* CRC Error counter */
+	ep->sen_alec = 0;	/* alignment error counter */
+	ep->sen_disfc = 0;	/* discard frame counter */
+
+	ep->sen_pads = 0x8888;	/* Tx short frame pad character */
+	ep->sen_retlim = 15;	/* Retry limit threshold */
+
+	ep->sen_maxflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
+	ep->sen_minflr = PKT_MINBUF_SIZE;  /* minimum frame length register */
+
+	ep->sen_maxd1 = PKT_MAXBLR_SIZE;	/* maximum DMA1 length */
+	ep->sen_maxd2 = PKT_MAXBLR_SIZE;	/* maximum DMA2 length */
+
+	/* Clear hash tables.
+	*/
+	ep->sen_gaddr1 = 0;
+	ep->sen_gaddr2 = 0;
+	ep->sen_gaddr3 = 0;
+	ep->sen_gaddr4 = 0;
+	ep->sen_iaddr1 = 0;
+	ep->sen_iaddr2 = 0;
+	ep->sen_iaddr3 = 0;
+	ep->sen_iaddr4 = 0;
+
+	/* Set Ethernet station address.
+	 *
+	 * This is supplied in the board information structure, so we
+	 * copy that into the controller.
+	 */
+	eap = (unsigned char *)&(ep->sen_paddrh);
+	for (i=5; i>=0; i--)
+		*eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
+
+	ep->sen_pper = 0;	/* 'cause the book says so */
+	ep->sen_taddrl = 0;	/* temp address (LSB) */
+	ep->sen_taddrm = 0;
+	ep->sen_taddrh = 0;	/* temp address (MSB) */
+
+	/* Now allocate the host memory pages and initialize the
+	 * buffer descriptors.
+	 */
+	bdp = cep->tx_bd_base;
+	for (i=0; i<TX_RING_SIZE; i++) {
+
+		/* Initialize the BD for every fragment in the page.
+		*/
+		bdp->cbd_sc = 0;
+		bdp->cbd_bufaddr = 0;
+		bdp++;
+	}
+
+	/* Set the last buffer to wrap.
+	*/
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	bdp = cep->rx_bd_base;
+	for (i=0; i<CPM_ENET_RX_PAGES; i++) {
+
+		/* Allocate a page.
+		*/
+		mem_addr = __get_free_page(GFP_KERNEL);
+
+		/* Initialize the BD for every fragment in the page.
+		*/
+		for (j=0; j<CPM_ENET_RX_FRPPG; j++) {
+			bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR;
+			bdp->cbd_bufaddr = __pa(mem_addr);
+			mem_addr += CPM_ENET_RX_FRSIZE;
+			bdp++;
+		}
+	}
+
+	/* Set the last buffer to wrap.
+	*/
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	/* Let's re-initialize the channel now.  We have to do it later
+	 * than the manual describes because we have just now finished
+	 * the BD initialization.
+	 */
+	cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0,
+			CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	cep->skb_cur = cep->skb_dirty = 0;
+
+	sccp->scc_scce = 0xffff;	/* Clear any pending events */
+
+	/* Enable interrupts for transmit error, complete frame
+	 * received, and any transmit buffer we have also set the
+	 * interrupt flag.
+	 */
+	sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
+
+	/* Install our interrupt handler.
+	*/
+	request_8xxirq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev);
+
+	/* Set GSMR_H to enable all normal operating modes.
+	 * Set GSMR_L to enable Ethernet to MC68160.
+	 */
+	sccp->scc_gsmrh = 0;
+	sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET);
+
+	/* Set sync/delimiters.
+	*/
+	sccp->scc_dsr = 0xd555;
+
+	/* Set processing mode.  Use Ethernet CRC, catch broadcast, and
+	 * start frame search 22 bit times after RENA.
+	 */
+	sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22);
+
+	/* It is now OK to enable the Ethernet transmitter.
+	 * Unfortunately, there are board implementation differences here.
+	 */
+	io->iop_pparc &= ~(PC_EST8260_ENET_LOOPBACK |
+				PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD);
+	io->iop_psorc &= ~(PC_EST8260_ENET_LOOPBACK |
+				PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD);
+	io->iop_pdirc |= (PC_EST8260_ENET_LOOPBACK |
+				PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD);
+	io->iop_pdatc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE);
+	io->iop_pdatc |= PC_EST8260_ENET_NOTFD;
+
+	dev->base_addr = (unsigned long)ep;
+	dev->priv = cep;
+
+	/* The CPM Ethernet specific entries in the device structure. */
+	dev->open = scc_enet_open;
+	dev->hard_start_xmit = scc_enet_start_xmit;
+	dev->tx_timeout = scc_enet_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->stop = scc_enet_close;
+	dev->get_stats = scc_enet_get_stats;
+	dev->set_multicast_list = set_multicast_list;
+
+	/* And last, enable the transmit and receive processing.
+	*/
+	sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	printk("%s: SCC ENET Version 0.1, ", dev->name);
+	for (i=0; i<5; i++)
+		printk("%02x:", dev->dev_addr[i]);
+	printk("%02x\n", dev->dev_addr[5]);
+
+	return 0;
+}
+
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c
--- v2.3.99-pre6/linux/arch/ppc/8260_io/uart.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/uart.c	Tue May  2 13:05:39 2000
@@ -0,0 +1,2772 @@
+/*
+ *  UART driver for MPC8260 CPM SCC or SMC
+ *  Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ *  Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com)
+ *	2.3.99 updates
+ *
+ * I used the 8xx uart.c driver as the framework for this driver.
+ * The original code was written for the EST8260 board.  I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ *
+ * The 8xx and 8260 are similar, but not identical.  Over time we
+ * could probably merge these two drivers.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ *	int rs_8xx_init(void);
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/immap_8260.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+
+/* this defines the index into rs_table for the port to use
+*/
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT	0
+#endif
+#endif
+
+#define TX_WAKEUP	ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.01";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+static int serial_console_setup(struct console *co, char *options);
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+  
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs.  For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
+ * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
+ * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs.
+ * Since these ports are so versatile, I don't yet have a strategy for
+ * their management.  For example, SCC1 is used for Ethernet.  Right
+ * now, just don't put them in the table.  Of course, right now I just
+ * want the SMC to work as a uart :-)..
+ * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
+ * not currently used.  I should probably use it to indicate the port
+ * type of CMS or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num	hub6
+
+/* SMC2 is sometimes used for low performance TDM interfaces.  Define
+ * this as 1 if you want SMC2 as a serial port UART managed by this driver.
+ * Define this as 0 if you wish to use SMC2 for something else.
+ */
+#define USE_SMC2 1
+
+/* Define SCC to ttySx mapping.
+*/
+#define SCC_NUM_BASE	(USE_SMC2 + 1)	/* SCC base tty "number" */
+
+/* Define which SCC is the first one to use for a serial port.  These
+ * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
+ * for Ethernet, and the first available SCC for serial UART is SCC2.
+ * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
+ * interrupt vectors in the table below to match.
+ */
+#define SCC_IDX_BASE	1	/* table index */
+
+static struct serial_state rs_table[] = {
+	/* UART CLK   PORT          IRQ      FLAGS  NUM   */
+	{ 0,     0, PROFF_SMC1, SIU_INT_SMC1,   0,    0 },    /* SMC1 ttyS0 */
+#if USE_SMC2
+	{ 0,     0, PROFF_SMC2, SIU_INT_SMC2,   0,    1 },    /* SMC2 ttyS1 */
+#endif
+	{ 0,     0, PROFF_SCC2, SIU_INT_SCC2,   0, SCC_NUM_BASE},    /* SCC2 ttyS2 */
+	{ 0,     0, PROFF_SCC3, SIU_INT_SCC3,   0, SCC_NUM_BASE + 1},    /* SCC3 ttyS3 */
+};
+
+#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+/* The number of buffer descriptors and their sizes.
+*/
+#define RX_NUM_FIFO	4
+#define RX_BUF_SIZE	32
+#define TX_NUM_FIFO	4
+#define TX_BUF_SIZE	32
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+	int			magic;
+	int			flags;
+	struct serial_state	*state;
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			line;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+
+	/* CPM Buffer Descriptor pointers.
+	*/
+	cbd_t			*rx_bd_base;
+	cbd_t			*rx_cur;
+	cbd_t			*tx_bd_base;
+	cbd_t			*tx_cur;
+} ser_info_t;
+
+static void change_speed(ser_info_t *info);
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value.  The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_stop(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	idx;
+	unsigned long flags;
+	volatile scc_t	*sccp;
+	volatile smc_t	*smcp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+		smcp->smc_smcm &= ~SMCM_TX;
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		sccp->scc_sccm &= ~UART_SCCM_TX;
+	}
+	restore_flags(flags);
+}
+
+static void rs_8xx_start(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	idx;
+	unsigned long flags;
+	volatile scc_t	*sccp;
+	volatile smc_t	*smcp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+		smcp->smc_smcm |= SMCM_TX;
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		sccp->scc_sccm |= UART_SCCM_TX;
+	}
+	restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(ser_info_t *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, *cp;
+	/*int	ignored = 0;*/
+	int	i;
+	ushort	status;
+	struct	async_icount *icount;
+	volatile cbd_t	*bdp;
+
+	icount = &info->state->icount;
+
+	/* Just loop through the closed BDs and copy the characters into
+	 * the buffer.
+	 */
+	bdp = info->rx_cur;
+	for (;;) {
+		if (bdp->cbd_sc & BD_SC_EMPTY)	/* If this one is empty */
+			break;			/*   we are all done */
+
+		/* The read status mask tell us what we should do with
+		 * incoming characters, especially if errors occur.
+		 * One special case is the use of BD_SC_EMPTY.  If
+		 * this is not set, we are supposed to be ignoring
+		 * inputs.  In this case, just mark the buffer empty and
+		 * continue.
+		if (!(info->read_status_mask & BD_SC_EMPTY)) {
+			bdp->cbd_sc |= BD_SC_EMPTY;
+			bdp->cbd_sc &=
+				~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+			if (bdp->cbd_sc & BD_SC_WRAP)
+				bdp = info->rx_bd_base;
+			else
+				bdp++;
+			continue;
+		}
+		 */
+
+		/* Get the number of characters and the buffer pointer.
+		*/
+		i = bdp->cbd_datlen;
+		cp = (unsigned char *)__va(bdp->cbd_bufaddr);
+		status = bdp->cbd_sc;
+
+		/* Check to see if there is room in the tty buffer for
+		 * the characters in our BD buffer.  If not, we exit
+		 * now, leaving the BD with the characters.  We'll pick
+		 * them up again on the next receive interrupt (which could
+		 * be a timeout).
+		 */
+		if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE)
+			break;
+
+		while (i-- > 0) {
+			ch = *cp++;
+			*tty->flip.char_buf_ptr = ch;
+			icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+			printk("DR%02x:%02x...", ch, *status);
+#endif
+			*tty->flip.flag_buf_ptr = 0;
+			if (status & (BD_SC_BR | BD_SC_FR |
+				       BD_SC_PR | BD_SC_OV)) {
+				/*
+				 * For statistics only
+				 */
+				if (status & BD_SC_BR)
+					icount->brk++;
+				else if (status & BD_SC_PR)
+					icount->parity++;
+				else if (status & BD_SC_FR)
+					icount->frame++;
+				if (status & BD_SC_OV)
+					icount->overrun++;
+
+				/*
+				 * Now check to see if character should be
+				 * ignored, and mask off conditions which
+				 * should be ignored.
+				if (status & info->ignore_status_mask) {
+					if (++ignored > 100)
+						break;
+					continue;
+				}
+				 */
+				status &= info->read_status_mask;
+		
+				if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+					printk("handling break....");
+#endif
+					*tty->flip.flag_buf_ptr = TTY_BREAK;
+					if (info->flags & ASYNC_SAK)
+						do_SAK(tty);
+				} else if (status & BD_SC_PR)
+					*tty->flip.flag_buf_ptr = TTY_PARITY;
+				else if (status & BD_SC_FR)
+					*tty->flip.flag_buf_ptr = TTY_FRAME;
+				if (status & BD_SC_OV) {
+					/*
+					 * Overrun is special, since it's
+					 * reported immediately, and doesn't
+					 * affect the current character
+					 */
+					if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+						tty->flip.count++;
+						tty->flip.flag_buf_ptr++;
+						tty->flip.char_buf_ptr++;
+						*tty->flip.flag_buf_ptr =
+								TTY_OVERRUN;
+					}
+				}
+			}
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				break;
+
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+
+		/* This BD is ready to be used again.  Clear status.
+		 * Get next BD.
+		 */
+		bdp->cbd_sc |= BD_SC_EMPTY;
+		bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+		if (bdp->cbd_sc & BD_SC_WRAP)
+			bdp = info->rx_bd_base;
+		else
+			bdp++;
+	}
+
+	info->rx_cur = (cbd_t *)bdp;
+
+	queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+	
+	if (info->flags & TX_WAKEUP) {
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+	}
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+	/* I need to do this for the SCCs, so it is left as a reminder.
+	*/
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+	int	status;
+	struct	async_icount *icount;
+	
+	status = serial_in(info, UART_MSR);
+
+	if (status & UART_MSR_ANY_DELTA) {
+		icount = &info->state->icount;
+		/* update input line counters */
+		if (status & UART_MSR_TERI)
+			icount->rng++;
+		if (status & UART_MSR_DDSR)
+			icount->dsr++;
+		if (status & UART_MSR_DDCD) {
+			icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			    (status & UART_MSR_DCD))
+				hardpps();
+#endif
+		}
+		if (status & UART_MSR_DCTS)
+			icount->cts++;
+		wake_up_interruptible(&info->delta_msr_wait);
+	}
+
+	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+		printk("ttys%d CD now %s...", info->line,
+		       (status & UART_MSR_DCD) ? "on" : "off");
+#endif		
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+			printk("scheduling hangup...");
+#endif
+			queue_task(&info->tqueue_hangup,
+					   &tq_scheduler);
+		}
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx start...");
+#endif
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				return;
+			}
+		} else {
+			if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx stop...");
+#endif
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+			}
+		}
+	}
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+	u_char	events;
+	int	idx;
+	ser_info_t *info;
+	volatile smc_t	*smcp;
+	volatile scc_t	*sccp;
+	
+	info = (ser_info_t *)dev_id;
+
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+		events = smcp->smc_smce;
+		if (events & SMCM_RX)
+			receive_chars(info);
+		if (events & SMCM_TX)
+			transmit_chars(info);
+		smcp->smc_smce = events;
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		events = sccp->scc_scce;
+		if (events & SCCM_RX)
+			receive_chars(info);
+		if (events & SCCM_TX)
+			transmit_chars(info);
+		sccp->scc_scce = events;
+	}
+	
+#ifdef SERIAL_DEBUG_INTR
+	printk("rs_interrupt_single(%d, %x)...",
+					info->state->smc_scc_num, events);
+#endif
+#ifdef modem_control
+	check_modem_status(info);
+#endif
+	info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	ser_info_t	*info = (ser_info_t *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+	struct async_struct	*info = (struct async_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+/*static void rs_8xx_timer(void)
+{
+	printk("rs_8xx_timer\n");
+}*/
+
+
+static int startup(ser_info_t *info)
+{
+	unsigned long flags;
+	int	retval=0;
+	int	idx;
+	struct serial_state *state= info->state;
+	volatile smc_t		*smcp;
+	volatile scc_t		*sccp;
+	volatile smc_uart_t	*up;
+	volatile scc_uart_t	*scup;
+
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		goto errout;
+	}
+
+#ifdef maybe
+	if (!state->port || !state->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		goto errout;
+	}
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+	
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info);
+	
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+
+		/* Enable interrupts and I/O.
+		*/
+		smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+		smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+		/* We can tune the buffer length and idle characters
+		 * to take advantage of the entire incoming buffer size.
+		 * If mrblr is something other than 1, maxidl has to be
+		 * non-zero or we never get an interrupt.  The maxidl
+		 * is the number of character times we wait after reception
+		 * of the last character before we decide no more characters
+		 * are coming.
+		 */
+		up = (smc_uart_t *)&immr->im_dprambase[state->port];
+#if 0
+		up->smc_mrblr = 1;	/* receive buffer length */
+		up->smc_maxidl = 0;	/* wait forever for next char */
+#else
+		up->smc_mrblr = RX_BUF_SIZE;
+		up->smc_maxidl = RX_BUF_SIZE;
+#endif
+		up->smc_brkcr = 1;	/* number of break chars */
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		scup = (scc_uart_t *)&immr->im_dprambase[state->port];
+#if 0
+		scup->scc_genscc.scc_mrblr = 1;	/* receive buffer length */
+		scup->scc_maxidl = 0;	/* wait forever for next char */
+#else
+		scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
+		scup->scc_maxidl = RX_BUF_SIZE;
+#endif
+
+		sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
+		sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+	}
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+	
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t * info)
+{
+	unsigned long	flags;
+	struct serial_state *state;
+	int		idx;
+	volatile smc_t	*smcp;
+	volatile scc_t	*sccp;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       state->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+
+		/* Disable interrupts and I/O.
+		*/
+		smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+		/* We can't disable the transmitter if this is the
+		 * system console.
+		 */
+		if (idx != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+			smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+		sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+	}
+	
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+	int	baud_rate;
+	unsigned cflag, cval, scval, prev_mode;
+	int	i, bits, sbits, idx;
+	unsigned long	flags;
+	volatile smc_t	*smcp;
+	volatile scc_t	*sccp;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+
+	/* Character length programmed into the mode register is the
+	 * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+	 * 1 or 2 stop bits, minus 1.
+	 * The value 'bits' counts this for us.
+	 */
+	cval = 0;
+	scval = 0;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	      case CS5: bits = 5; break;
+	      case CS6: bits = 6; break;
+	      case CS7: bits = 7; break;
+	      case CS8: bits = 8; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  bits = 8; break;
+	}
+	sbits = bits - 5;
+
+	if (cflag & CSTOPB) {
+		cval |= SMCMR_SL;	/* Two stops */
+		scval |= SCU_PMSR_SL;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		cval |= SMCMR_PEN;
+		scval |= SCU_PMSR_PEN;
+		bits++;
+	}
+	if (!(cflag & PARODD)) {
+		cval |= SMCMR_PM_EVEN;
+		scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
+	}
+
+	/* Determine divisor based on baud rate */
+	i = cflag & CBAUD;
+	if (i >= (sizeof(baud_table)/sizeof(int)))
+		baud_rate = 9600;
+	else
+		baud_rate = baud_table[i];
+
+	info->timeout = (TX_BUF_SIZE*HZ*bits);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+#ifdef modem_control
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+#endif
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= BD_SC_BR;
+	
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= BD_SC_BR;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= BD_SC_OV;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->read_status_mask &= ~BD_SC_EMPTY;
+	save_flags(flags); cli();
+
+	/* Start bit has not been added (so don't, because we would just
+	 * subtract it later), and we need to add one for the number of
+	 * stops bits (there is always at least one).
+	 */
+	bits++;
+	if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		smcp = &immr->im_smc[idx];
+
+		/* Set the mode register.  We want to keep a copy of the
+		 * enables, because we want to put them back if they were
+		 * present.
+		 */
+		prev_mode = smcp->smc_smcmr;
+		smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
+		smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+	}
+	else {
+		sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+		sccp->scc_pmsr = (sbits << 12) | scval;
+	}
+
+	m8260_cpm_setbrg(info->state->smc_scc_num, baud_rate);
+
+	restore_flags(flags);
+}
+
+static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	volatile cbd_t	*bdp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+		return;
+
+	if (!tty)
+		return;
+
+	bdp = info->tx_cur;
+	while (bdp->cbd_sc & BD_SC_READY);
+
+	*((char *)__va(bdp->cbd_bufaddr)) = ch;
+	bdp->cbd_datlen = 1;
+	bdp->cbd_sc |= BD_SC_READY;
+
+	/* Get next BD.
+	*/
+	if (bdp->cbd_sc & BD_SC_WRAP)
+		bdp = info->tx_bd_base;
+	else
+		bdp++;
+
+	info->tx_cur = (cbd_t *)bdp;
+
+}
+
+static int rs_8xx_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	volatile cbd_t *bdp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty) 
+		return 0;
+
+	bdp = info->tx_cur;
+
+	while (1) {
+		c = MIN(count, TX_BUF_SIZE);
+
+		if (c <= 0)
+			break;
+
+		if (bdp->cbd_sc & BD_SC_READY) {
+			info->flags |= TX_WAKEUP;
+			break;
+		}
+
+		if (from_user) {
+			if (c !=
+			    copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+		} else {
+			memcpy(__va(bdp->cbd_bufaddr), buf, c);
+		}
+
+		bdp->cbd_datlen = c;
+		bdp->cbd_sc |= BD_SC_READY;
+
+		buf += c;
+		count -= c;
+		ret += c;
+
+		/* Get next BD.
+		*/
+		if (bdp->cbd_sc & BD_SC_WRAP)
+			bdp = info->tx_bd_base;
+		else
+			bdp++;
+		info->tx_cur = (cbd_t *)bdp;
+	}
+	return ret;
+}
+
+static int rs_8xx_write_room(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	ret;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+
+	if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) {
+		info->flags &= ~TX_WAKEUP;
+		ret = TX_BUF_SIZE;
+	}
+	else {
+		info->flags |= TX_WAKEUP;
+		ret = 0;
+	}
+	return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_8xx_chars_in_buffer(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return 0;
+}
+
+static void rs_8xx_flush_buffer(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+
+	/* There is nothing to "flush", whatever we gave the CPM
+	 * is on its way out.
+	 */
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+	info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_8xx_send_xchar(struct tty_struct *tty, char ch)
+{
+	volatile cbd_t	*bdp;
+
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+		return;
+
+	bdp = info->tx_cur;
+	while (bdp->cbd_sc & BD_SC_READY);
+
+	*((char *)__va(bdp->cbd_bufaddr)) = ch;
+	bdp->cbd_datlen = 1;
+	bdp->cbd_sc |= BD_SC_READY;
+
+	/* Get next BD.
+	*/
+	if (bdp->cbd_sc & BD_SC_WRAP)
+		bdp = info->tx_bd_base;
+	else
+		bdp++;
+
+	info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_throttle(struct tty_struct * tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		rs_8xx_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+#endif
+}
+
+static void rs_8xx_unthrottle(struct tty_struct * tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_8xx_send_xchar(tty, START_CHAR(tty));
+	}
+#ifdef modem_control
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+
+	cli();
+	status = serial_in(info, UART_LSR);
+	sti();
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+	return put_user(result,value);
+}
+#endif
+
+static int get_modem_info(ser_info_t *info, unsigned int *value)
+{
+	unsigned int result = 0;
+#ifdef modem_control
+	unsigned char control, status;
+
+	control = info->MCR;
+	cli();
+	status = serial_in(info, UART_MSR);
+	sti();
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+	return put_user(result,value);
+}
+
+static int set_modem_info(ser_info_t *info, unsigned int cmd,
+			  unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+
+	error = get_user(arg, value);
+	if (error)
+		return error;
+#ifdef modem_control
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+					    UART_MCR_OUT1 |
+					    UART_MCR_OUT2 |
+#endif
+					    UART_MCR_DTR))
+			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+#endif
+	return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command.  We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static void begin_break(ser_info_t *info)
+{
+	volatile cpm8260_t *cp;
+	uint	page, sblock;
+	ushort	num;
+
+	cp = cpmp;
+
+	if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		if (num == 0) {
+			page = CPM_CR_SMC1_PAGE;
+			sblock = CPM_CR_SMC1_SBLOCK;
+		}
+		else {
+			page = CPM_CR_SMC2_PAGE;
+			sblock = CPM_CR_SMC2_SBLOCK;
+		}
+	}
+	else {
+		num -= SCC_NUM_BASE;
+		switch (num) {
+		case 0:
+			page = CPM_CR_SCC1_PAGE;
+			sblock = CPM_CR_SCC1_SBLOCK;
+			break;
+		case 1:
+			page = CPM_CR_SCC2_PAGE;
+			sblock = CPM_CR_SCC2_SBLOCK;
+			break;
+		case 2:
+			page = CPM_CR_SCC3_PAGE;
+			sblock = CPM_CR_SCC3_SBLOCK;
+			break;
+		case 3:
+			page = CPM_CR_SCC4_PAGE;
+			sblock = CPM_CR_SCC4_SBLOCK;
+			break;
+		default: return;
+		}
+	}
+	cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_STOP_TX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+	volatile cpm8260_t *cp;
+	uint	page, sblock;
+	ushort	num;
+
+	cp = cpmp;
+
+	if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+		if (num == 0) {
+			page = CPM_CR_SMC1_PAGE;
+			sblock = CPM_CR_SMC1_SBLOCK;
+		}
+		else {
+			page = CPM_CR_SMC2_PAGE;
+			sblock = CPM_CR_SMC2_SBLOCK;
+		}
+	}
+	else {
+		num -= SCC_NUM_BASE;
+		switch (num) {
+		case 0:
+			page = CPM_CR_SCC1_PAGE;
+			sblock = CPM_CR_SCC1_SBLOCK;
+			break;
+		case 1:
+			page = CPM_CR_SCC2_PAGE;
+			sblock = CPM_CR_SCC2_SBLOCK;
+			break;
+		case 2:
+			page = CPM_CR_SCC3_PAGE;
+			sblock = CPM_CR_SCC3_SBLOCK;
+			break;
+		case 3:
+			page = CPM_CR_SCC4_PAGE;
+			sblock = CPM_CR_SCC4_SBLOCK;
+			break;
+		default: return;
+		}
+	}
+	cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, int duration)
+{
+	current->state = TASK_INTERRUPTIBLE;
+#ifdef SERIAL_DEBUG_SEND_BREAK
+	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+	begin_break(info);
+	schedule_timeout(duration);
+	end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+	printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int retval;
+	struct async_icount cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4);	/* 1/4 second */
+				if (signal_pending(current))
+					return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCSBRK:
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			begin_break(info);
+			return 0;
+		case TIOCCBRK:
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			end_break(info);
+			return 0;
+		case TIOCGSOFTCAR:
+			return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+		case TIOCSSOFTCAR:
+			error = get_user(arg, (unsigned int *) arg);
+			if (error)
+				return error;
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+#ifdef maybe
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+#endif
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		 case TIOCMIWAIT:
+#ifdef modem_control
+			cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			sti();
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				cli();
+				cnow = info->state->icount; /* atomic copy */
+				sti();
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				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)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+#else
+			return 0;
+#endif
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			cli();
+			cnow = info->state->icount;
+			sti();
+			p_cuser = (struct serial_icounter_struct *) arg;
+			error = put_user(cnow.cts, &p_cuser->cts);
+			if (error) return error;
+			error = put_user(cnow.dsr, &p_cuser->dsr);
+			if (error) return error;
+			error = put_user(cnow.rng, &p_cuser->rng);
+			if (error) return error;
+			error = put_user(cnow.dcd, &p_cuser->dcd);
+			if (error) return error;
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+	if (   (tty->termios->c_cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info);
+
+#ifdef modem_control
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		cli();
+		serial_out(info, UART_MCR, info->MCR);
+		sti();
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (tty->termios->c_cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!tty->hw_stopped ||
+		    !(tty->termios->c_cflag & CRTSCTS)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		cli();
+		serial_out(info, UART_MCR, info->MCR);
+		sti();
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_8xx_start(tty);
+	}
+#endif
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_close(struct tty_struct *tty, struct file * filp)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long	flags;
+	int		idx;
+	volatile smc_t	*smcp;
+	volatile scc_t	*sccp;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->read_status_mask &= ~BD_SC_EMPTY;
+	if (info->flags & ASYNC_INITIALIZED) {
+		if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+			smcp = &immr->im_smc[idx];
+			smcp->smc_smcm &= ~SMCM_RX;
+			smcp->smc_smcmr &= ~SMCMR_REN;
+		}
+		else {
+			sccp = &immr->im_scc[idx - SCC_IDX_BASE];
+			sccp->scc_sccm &= ~UART_SCCM_RX;
+			sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
+		}
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		rs_8xx_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+	restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	/*int lsr;*/
+	volatile cbd_t *bdp;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+#ifdef maybe
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+#endif
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = 1;
+	if (timeout)
+		char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+
+	/* We go through the loop at least once because we can't tell
+	 * exactly when the last character exits the shifter.  There can
+	 * be at least two characters waiting to be sent after the buffers
+	 * are empty.
+	 */
+	do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+/*		current->counter = 0;	 make us low-priority */
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+		bdp = info->tx_cur;
+	} while (bdp->cbd_sc & BD_SC_READY);
+	current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_8xx_hangup(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	struct serial_state *state = info->state;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	state = info->state;
+	
+	rs_8xx_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+	DECLARE_WAITQUEUE(wait, current);
+#endif
+	struct serial_state *state = info->state;
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 * If this is an SMC port, we don't have modem control to wait
+	 * for, so just get out here.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR)) ||
+	    (info->state->smc_scc_num < SCC_NUM_BASE)) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+#ifdef DO_THIS_LATER
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       state->line, state->count);
+#endif
+	cli();
+	if (!tty_hung_up_p(filp)) 
+		state->count--;
+	sti();
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		sti();
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, state->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	if (sstate->info) {
+		sstate->count++;
+		*ret_info = (ser_info_t *)sstate->info;
+		return 0;
+	}
+	else {
+		return -ENOMEM;
+	}
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_8xx_open(struct tty_struct *tty, struct file * filp)
+{
+	ser_info_t	*info;
+	int 		retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		return -ENODEV;
+	retval = get_async_struct(line, &info);
+	if (retval)
+		return retval;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->state->count);
+#endif
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	MOD_INC_USE_COUNT;
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else 
+			*tty->termios = info->state->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static int inline line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+	struct async_struct *info = state->info, scr_info;
+	char	stat_buf[30], control, status;
+#endif
+	int	ret;
+
+	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+		      state->line,
+		      (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
+		      state->port, state->irq);
+
+	if (!state->port || (state->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+#ifdef notdef
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info;	/* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	cli();
+	status = serial_in(info, UART_MSR);
+	control = info ? info->MCR : serial_in(info, UART_MCR);
+	sti();
+	
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+		strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+		strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+		strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       state->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+	return ret;
+}
+
+int rs_8xx_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		len += line_info(page + len, &rs_table[i]);
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (begin-off);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+/*
+ * The serial console driver used during boot.  Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time.  I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void serial_console_write(struct console *c, const char *s,
+				unsigned count)
+{
+	struct		serial_state	*ser;
+	ser_info_t			*info;
+	unsigned			i;
+	volatile	cbd_t		*bdp, *bdbase;
+	volatile	smc_uart_t	*up;
+	volatile	u_char		*cp;
+
+	ser = rs_table + c->index;
+
+	/* If the port has been initialized for general use, we have
+	 * to use the buffer descriptors allocated there.  Otherwise,
+	 * we simply use the single buffer allocated.
+	 */
+	if ((info = (ser_info_t *)ser->info) != NULL) {
+		bdp = info->tx_cur;
+		bdbase = info->tx_bd_base;
+	}
+	else {
+		/* Pointer to UART in parameter ram.
+		*/
+		up = (smc_uart_t *)&immr->im_dprambase[ser->port];
+
+		/* Get the address of the host memory buffer.
+		 */
+		bdp = bdbase = (cbd_t *)&immr->im_dprambase[up->smc_tbase];
+	}
+
+	/*
+	 * We need to gracefully shut down the transmitter, disable
+	 * interrupts, then send our bytes out.
+	 */
+
+	/*
+	 * Now, do each character.  This is not as bad as it looks
+	 * since this is a holding FIFO and not a transmitting FIFO.
+	 * We could add the complexity of filling the entire transmit
+	 * buffer, but we would just wait longer between accesses......
+	 */
+	for (i = 0; i < count; i++, s++) {
+		/* Wait for transmitter fifo to empty.
+		 * Ready indicates output is ready, and xmt is doing
+		 * that, not that it is ready for us to send.
+		 */
+		while (bdp->cbd_sc & BD_SC_READY);
+		/* Send the character out. */
+		cp = __va(bdp->cbd_bufaddr);
+		*cp = *s;
+		
+		bdp->cbd_datlen = 1;
+		bdp->cbd_sc |= BD_SC_READY;
+
+		if (bdp->cbd_sc & BD_SC_WRAP)
+			bdp = bdbase;
+		else
+			bdp++;
+
+		/* if a LF, also do CR... */
+		if (*s == 10) {
+			while (bdp->cbd_sc & BD_SC_READY);
+			cp = __va(bdp->cbd_bufaddr);
+			*cp = 13;
+			bdp->cbd_datlen = 1;
+			bdp->cbd_sc |= BD_SC_READY;
+
+			if (bdp->cbd_sc & BD_SC_WRAP) {
+				bdp = bdbase;
+			}
+			else {
+				bdp++;
+			}
+		}
+	}
+
+	/*
+	 * Finally, Wait for transmitter & holding register to empty
+	 *  and restore the IER
+	 */
+	while (bdp->cbd_sc & BD_SC_READY);
+
+	if (info)
+		info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * Receive character from the serial port.  This only works well
+ * before the port is initialize for real use.
+ */
+static int serial_console_wait_key(struct console *co)
+{
+	struct serial_state		*ser;
+	u_char				c, *cp;
+	ser_info_t			*info;
+	volatile	cbd_t		*bdp;
+	volatile	smc_uart_t	*up;
+
+	ser = rs_table + co->index;
+
+	/* Pointer to UART in parameter ram.
+	*/
+	up = (smc_uart_t *)&immr->im_dprambase[ser->port];
+
+	/* Get the address of the host memory buffer.
+	 * If the port has been initialized for general use, we must
+	 * use information from the port structure.
+	 */
+	if ((info = (ser_info_t *)ser->info))
+		bdp = info->rx_cur;
+	else
+		bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase];
+
+	/*
+	 * We need to gracefully shut down the receiver, disable
+	 * interrupts, then read the input.
+	 */
+	while (bdp->cbd_sc & BD_SC_EMPTY);	/* Wait for a character */
+	cp = __va(bdp->cbd_bufaddr);
+
+	if (info) {
+		if (bdp->cbd_sc & BD_SC_WRAP) {
+			bdp = info->rx_bd_base;
+		}
+		else {
+			bdp++;
+		}
+		info->rx_cur = (cbd_t *)bdp;
+	}
+
+	c = *cp;
+	return((int)c);
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 64 + c->index);
+}
+
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	CONFIG_SERIAL_CONSOLE_PORT,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+long __init console_8xx_init(long kmem_start, long kmem_end)
+{
+	register_console(&sercons);
+	return kmem_start;
+}
+
+#endif
+
+/* Default console baud rate as determined by the board information
+ * structure.
+ */
+static	int	baud_idx;
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+int __init rs_8xx_init(void)
+{
+	struct serial_state * state;
+	ser_info_t	*info;
+	uint		mem_addr, dp_addr;
+	int		i, j, idx;
+	uint		page, sblock;
+	volatile	cbd_t		*bdp;
+	volatile	cpm8260_t	*cp;
+	volatile	smc_t		*sp;
+	volatile	smc_uart_t	*up;
+	volatile	scc_t		*scp;
+	volatile	scc_uart_t	*sup;
+	volatile	immap_t		*immap;
+	volatile	iop8260_t	*io;
+	
+	init_bh(SERIAL_BH, do_serial_bh);
+#if 0
+	timer_table[RS_TIMER].fn = rs_8xx_timer;
+	timer_table[RS_TIMER].expires = 0;
+#endif
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	
+	/*memset(&serial_driver, 0, sizeof(struct tty_driver));*/
+	__clear_user(&serial_driver,sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "serial";
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_8xx_open;
+	serial_driver.close = rs_8xx_close;
+	serial_driver.write = rs_8xx_write;
+	serial_driver.put_char = rs_8xx_put_char;
+	serial_driver.write_room = rs_8xx_write_room;
+	serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer;
+	serial_driver.flush_buffer = rs_8xx_flush_buffer;
+	serial_driver.ioctl = rs_8xx_ioctl;
+	serial_driver.throttle = rs_8xx_throttle;
+	serial_driver.unthrottle = rs_8xx_unthrottle;
+	serial_driver.send_xchar = rs_8xx_send_xchar;
+	serial_driver.set_termios = rs_8xx_set_termios;
+	serial_driver.stop = rs_8xx_stop;
+	serial_driver.start = rs_8xx_start;
+	serial_driver.hangup = rs_8xx_hangup;
+	serial_driver.wait_until_sent = rs_8xx_wait_until_sent;
+	serial_driver.read_proc = rs_8xx_read_proc;
+	
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	immap = immr;
+	cp = &immap->im_cpm;
+	io = &immap->im_ioport;
+
+	/* This should have been done long ago by the early boot code,
+	 * but do it again to make sure.
+	 */
+	*(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
+	*(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
+
+	/* Geeze, here we go....Picking I/O port bits....Lots of
+	 * choices.  If you don't like mine, pick your own.
+	 * Configure SMCs Tx/Rx.  SMC1 is only on Port D, SMC2 is
+	 * only on Port A.  You either pick 'em, or not.
+	 */
+	io->iop_ppard |= 0x00c00000;
+	io->iop_pdird |= 0x00400000;
+	io->iop_pdird &= ~0x00800000;
+	io->iop_psord &= ~0x00c00000;
+#if USE_SMC2
+	io->iop_ppara |= 0x01800000;
+	io->iop_pdira |= 0x00800000;
+	io->iop_pdira &= ~0x01000000;
+	io->iop_psora &= ~0x01800000;
+#endif
+
+	/* Configure SCC2 and SCC3.  Be careful about the fine print.
+	 * Secondary options are only available when you take away
+	 * the primary option.  Unless the pins are used for something
+	 * else, SCC2 and SCC3 are on Port B.
+	 *	Port B,  8 - SCC3 TxD
+	 *	Port B, 12 - SCC2 TxD
+	 *	Port B, 14 - SCC3 RxD
+	 *	Port B, 15 - SCC2 RxD
+	 */
+	io->iop_pparb |= 0x008b0000;
+	io->iop_pdirb |= 0x00880000;
+	io->iop_psorb |= 0x00880000;
+	io->iop_pdirb &= ~0x00030000;
+	io->iop_psorb &= ~0x00030000;
+
+	/* Wire BRG1 to SMC1 and BRG2 to SMC2.
+	*/
+	immap->im_cpmux.cmx_smr = 0;
+
+	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
+	 * BRG4 to SCC3.
+	 */
+	immap->im_cpmux.cmx_scr &= ~0x00ffff00;
+	immap->im_cpmux.cmx_scr |= 0x00121b00;
+
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = PORT_UNKNOWN;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = callout_driver.init_termios;
+		state->normal_termios = serial_driver.init_termios;
+		state->icount.cts = state->icount.dsr = 
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
+		       i, state->port,
+		       (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");
+#ifdef CONFIG_SERIAL_CONSOLE
+		/* If we just printed the message on the console port, and
+		 * we are about to initialize it for general use, we have
+		 * to wait a couple of character times for the CR/NL to
+		 * make it out of the transmit buffer.
+		 */
+		if (i == CONFIG_SERIAL_CONSOLE_PORT)
+			mdelay(2);
+#endif
+		info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
+		if (info) {
+			/*memset(info, 0, sizeof(ser_info_t));*/
+			__clear_user(info,sizeof(ser_info_t));
+			info->magic = SERIAL_MAGIC;
+			info->flags = state->flags;
+			info->tqueue.routine = do_softint;
+			info->tqueue.data = info;
+			info->tqueue_hangup.routine = do_serial_hangup;
+			info->tqueue_hangup.data = info;
+			info->line = i;
+			info->state = state;
+			state->info = (struct async_struct *)info;
+
+			/* We need to allocate a transmit and receive buffer
+			 * descriptors from dual port ram, and a character
+			 * buffer area from host mem.
+			 */
+			dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO);
+
+			/* Allocate space for FIFOs in the host memory.
+			*/
+			mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE);
+
+			/* Set the physical address of the host memory
+			 * buffers in the buffer descriptors, and the
+			 * virtual address for us to work with.
+			 */
+			bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
+			info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;
+
+			for (j=0; j<(RX_NUM_FIFO-1); j++) {
+				bdp->cbd_bufaddr = __pa(mem_addr);
+				bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+				mem_addr += RX_BUF_SIZE;
+				bdp++;
+			}
+			bdp->cbd_bufaddr = __pa(mem_addr);
+			bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+			if ((idx = state->smc_scc_num) < SCC_NUM_BASE) {
+				sp = &immap->im_smc[idx];
+				up = (smc_uart_t *)&immap->im_dprambase[state->port];
+				up->smc_rbase = dp_addr;
+			}
+			else {
+				scp = &immap->im_scc[idx - SCC_IDX_BASE];
+				sup = (scc_uart_t *)&immap->im_dprambase[state->port];
+				sup->scc_genscc.scc_rbase = dp_addr;
+			}
+
+			dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO);
+
+			/* Allocate space for FIFOs in the host memory.
+			*/
+			mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE);
+
+			/* Set the physical address of the host memory
+			 * buffers in the buffer descriptors, and the
+			 * virtual address for us to work with.
+			 */
+			bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
+			info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;
+
+			for (j=0; j<(TX_NUM_FIFO-1); j++) {
+				bdp->cbd_bufaddr = __pa(mem_addr);
+				bdp->cbd_sc = BD_SC_INTRPT;
+				mem_addr += TX_BUF_SIZE;
+				bdp++;
+			}
+			bdp->cbd_bufaddr = __pa(mem_addr);
+			bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
+
+			if (idx < SCC_NUM_BASE) {
+				up->smc_tbase = dp_addr;
+
+				/* Set up the uart parameters in the
+				 * parameter ram.
+				 */
+				up->smc_rfcr = SMC_EB;
+				up->smc_tfcr = SMC_EB;
+
+				/* Set this to 1 for now, so we get single
+				 * character interrupts.  Using idle charater
+				 * time requires some additional tuning.
+				 */
+				up->smc_mrblr = 1;
+				up->smc_maxidl = 0;
+				up->smc_brkcr = 1;
+
+				/* Send the CPM an initialize command.
+				*/
+				if (state->smc_scc_num == 0) {
+					page = CPM_CR_SMC1_PAGE;
+					sblock = CPM_CR_SMC1_SBLOCK;
+				}
+				else {
+					page = CPM_CR_SMC2_PAGE;
+					sblock = CPM_CR_SMC2_SBLOCK;
+				}
+
+				cp->cp_cpcr = mk_cr_cmd(page, sblock, 0,
+						CPM_CR_INIT_TRX) | CPM_CR_FLG;
+				while (cp->cp_cpcr & CPM_CR_FLG);
+
+				/* Set UART mode, 8 bit, no parity, one stop.
+				 * Enable receive and transmit.
+				 */
+				sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+				/* Disable all interrupts and clear all pending
+				 * events.
+				 */
+				sp->smc_smcm = 0;
+				sp->smc_smce = 0xff;
+			}
+			else {
+				sup->scc_genscc.scc_tbase = dp_addr;
+
+				/* Set up the uart parameters in the
+				 * parameter ram.
+				 */
+				sup->scc_genscc.scc_rfcr = SMC_EB;
+				sup->scc_genscc.scc_tfcr = SMC_EB;
+
+				/* Set this to 1 for now, so we get single
+				 * character interrupts.  Using idle charater
+				 * time requires some additional tuning.
+				 */
+				sup->scc_genscc.scc_mrblr = 1;
+				sup->scc_maxidl = 0;
+				sup->scc_brkcr = 1;
+				sup->scc_parec = 0;
+				sup->scc_frmec = 0;
+				sup->scc_nosec = 0;
+				sup->scc_brkec = 0;
+				sup->scc_uaddr1 = 0;
+				sup->scc_uaddr2 = 0;
+				sup->scc_toseq = 0;
+				sup->scc_char1 = 0x8000;
+				sup->scc_char2 = 0x8000;
+				sup->scc_char3 = 0x8000;
+				sup->scc_char4 = 0x8000;
+				sup->scc_char5 = 0x8000;
+				sup->scc_char6 = 0x8000;
+				sup->scc_char7 = 0x8000;
+				sup->scc_char8 = 0x8000;
+				sup->scc_rccm = 0xc0ff;
+
+				/* Send the CPM an initialize command.
+				*/
+				if (state->smc_scc_num == 2) {
+					page = CPM_CR_SCC2_PAGE;
+					sblock = CPM_CR_SCC2_SBLOCK;
+				}
+				else {
+					page = CPM_CR_SCC3_PAGE;
+					sblock = CPM_CR_SCC3_SBLOCK;
+				}
+
+				cp->cp_cpcr = mk_cr_cmd(page, sblock, 0,
+						CPM_CR_INIT_TRX) | CPM_CR_FLG;
+				while (cp->cp_cpcr & CPM_CR_FLG);
+
+				/* Set UART mode, 8 bit, no parity, one stop.
+				 * Enable receive and transmit.
+				 */
+				scp->scc_gsmrh = 0;
+				scp->scc_gsmrl = 
+					(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+				/* Disable all interrupts and clear all pending
+				 * events.
+				 */
+				scp->scc_sccm = 0;
+				scp->scc_scce = 0xffff;
+				scp->scc_dsr = 0x7e7e;
+				scp->scc_pmsr = 0x3000;
+			}
+
+			/* Install interrupt handler.
+			*/
+			request_8xxirq(state->irq, rs_8xx_interrupt, 0, "uart", info);
+
+			/* Set up the baud rate generator.
+			*/
+			m8260_cpm_setbrg(state->smc_scc_num,
+							baud_table[baud_idx]);
+
+			/* If the port is the console, enable Rx and Tx.
+			*/
+#ifdef CONFIG_SERIAL_CONSOLE
+			if (i == CONFIG_SERIAL_CONSOLE_PORT)
+				sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+		}
+	}
+	return 0;
+}
+
+/* This must always be called before the rs_8xx_init() function, otherwise
+ * it blows away the port control information.
+*/
+static int __init serial_console_setup(struct console *co, char *options)
+{
+	struct		serial_state *ser;
+	uint		mem_addr, dp_addr, bidx;
+	volatile	cbd_t		*bdp;
+	volatile	cpm8260_t	*cp;
+	volatile	immap_t		*immap;
+	volatile	smc_t		*sp;
+	volatile	smc_uart_t	*up;
+	volatile	iop8260_t	*io;
+	bd_t				*bd;
+
+	bd = (bd_t *)__res;
+
+	for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
+		if (bd->bi_baudrate == baud_table[bidx])
+			break;
+
+	co->cflag = CREAD|CLOCAL|bidx|CS8;
+	baud_idx = bidx;
+
+	ser = rs_table + co->index;
+
+	
+	immap = immr;
+	cp = &immap->im_cpm;
+	io = &immap->im_ioport;
+
+	/* This should have been done long ago by the early boot code,
+	 * but do it again to make sure.
+	 */
+	*(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
+	*(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
+
+	/* Right now, assume we are using SMCs.
+	*/
+	sp = &immap->im_smc[ser->smc_scc_num];
+
+	/* When we get here, the CPM has been reset, so we need
+	 * to configure the port.
+	 * We need to allocate a transmit and receive buffer descriptor
+	 * from dual port ram, and a character buffer area from host mem.
+	 */
+	up = (smc_uart_t *)&immap->im_dprambase[ser->port];
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* Use Port D for SMC1 instead of other functions.
+	*/
+	io->iop_ppard |= 0x00c00000;
+	io->iop_pdird |= 0x00400000;
+	io->iop_pdird &= ~0x00800000;
+	io->iop_psord &= ~0x00c00000;
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	*/
+	dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2);
+
+	/* Allocate space for two 2 byte FIFOs in the host memory.
+	*/
+	mem_addr = m8260_cpm_hostalloc(4);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
+	bdp->cbd_bufaddr = __pa(mem_addr);
+	(bdp+1)->cbd_bufaddr = __pa(mem_addr+2);
+
+	/* For the receive, set empty and wrap.
+	 * For transmit, set wrap.
+	 */
+	bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	(bdp+1)->cbd_sc = BD_SC_WRAP;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->smc_rbase = dp_addr;	/* Base of receive buffer desc. */
+	up->smc_tbase = dp_addr+sizeof(cbd_t);	/* Base of xmt buffer desc. */
+	up->smc_rfcr = SMC_EB;
+	up->smc_tfcr = SMC_EB;
+
+	/* Set this to 1 for now, so we get single character interrupts.
+	*/
+	up->smc_mrblr = 1;		/* receive buffer length */
+	up->smc_maxidl = 0;		/* wait forever for next char */
+
+	/* Send the CPM an initialize command.
+	*/
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0,
+			CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Set up the baud rate generator.
+	*/
+	m8260_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate);
+
+	/* And finally, enable Rx and Tx.
+	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+	return 0;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.3.99-pre6/linux/arch/ppc/8xx_io/enet.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/8xx_io/enet.c	Tue May  2 13:05:39 2000
@@ -37,6 +37,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
@@ -108,6 +109,10 @@
  *	Port C,  9 (CTS2) - SCC Ethernet Collision
  */
 
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it is best
  * to keep them that size.
@@ -135,7 +140,7 @@
  * empty and completely full conditions.  The empty/ready indicator in
  * the buffer descriptor determines the actual condition.
  */
-struct cpm_enet_private {
+struct scc_enet_private {
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct	sk_buff* tx_skbuff[TX_RING_SIZE];
 	ushort	skb_cur;
@@ -150,17 +155,15 @@
 	scc_t	*sccp;
 	struct	net_device_stats stats;
 	uint	tx_full;
-	uint	tx_busy;
-	unsigned long lock;
-	int	interrupt;
+	spinlock_t lock;
 };
 
-static int cpm_enet_open(struct net_device *dev);
-static int cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int cpm_enet_rx(struct net_device *dev);
-static void cpm_enet_interrupt(void *dev_id);
-static int cpm_enet_close(struct net_device *dev);
-static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev);
+static int scc_enet_open(struct net_device *dev);
+static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int scc_enet_rx(struct net_device *dev);
+static void scc_enet_interrupt(void *dev_id);
+static int scc_enet_close(struct net_device *dev);
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 
 /* Get this from various configuration locations (depends on board).
@@ -185,7 +188,7 @@
 #endif
 
 static int
-cpm_enet_open(struct net_device *dev)
+scc_enet_open(struct net_device *dev)
 {
 
 	/* I should reset the ring buffers here, but I don't yet know
@@ -197,60 +200,10 @@
 }
 
 static int
-cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
 	volatile cbd_t	*bdp;
-	unsigned long flags;
-
-	/* Transmitter timeout, serious problems. */
-	if (cep->tx_busy) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 200)
-			return 1;
-		printk("%s: transmit timed out.\n", dev->name);
-		cep->stats.tx_errors++;
-#ifndef final_version
-		{
-			int	i;
-			cbd_t	*bdp;
-			printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
-				   cep->cur_tx, cep->tx_full ? " (full)" : "",
-				   cep->cur_rx);
-			bdp = cep->tx_bd_base;
-			for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
-				printk("%04x %04x %08x\n",
-					bdp->cbd_sc,
-					bdp->cbd_datlen,
-					bdp->cbd_bufaddr);
-			bdp = cep->rx_bd_base;
-			for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
-				printk("%04x %04x %08x\n",
-					bdp->cbd_sc,
-					bdp->cbd_datlen,
-					bdp->cbd_bufaddr);
-		}
-#endif
-
-		cep->tx_busy=0;
-		dev->trans_start = jiffies;
-
-		return 0;
-	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	 * done with atomic_swap(1, cep->tx_busy), but set_bit() works as well.
-	 */
-	if (test_and_set_bit(0, (void*)&cep->tx_busy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
-
-	if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
-		printk("%s: tx queue lock!.\n", dev->name);
-		/* don't clear cep->tx_busy flag. */
-		return 1;
-	}
 
 	/* Fill in a Tx ring entry */
 	bdp = cep->cur_tx;
@@ -261,7 +214,6 @@
 		 * This should not happen, since cep->tx_busy should be set.
 		 */
 		printk("%s: tx queue full!.\n", dev->name);
-		cep->lock = 0;
 		return 1;
 	}
 #endif
@@ -292,7 +244,10 @@
 	/* Push the data cache so the CPM does not get stale memory
 	 * data.
 	 */
-	flush_dcache_range(skb->data, skb->data + skb->len);
+	flush_dcache_range((unsigned long)(skb->data),
+					(unsigned long)(skb->data + skb->len));
+
+	spin_lock_irq(&cep->lock);
 
 	/* Send it on its way.  Tell CPM its ready, interrupt when done,
 	 * its the last BD of the frame, and to put the CRC on the end.
@@ -308,37 +263,61 @@
 	else
 		bdp++;
 
-	save_flags(flags);
-	cli();
-	cep->lock = 0;
 	if (bdp->cbd_sc & BD_ENET_TX_READY)
-		cep->tx_full = 1;
-	else
-		cep->tx_busy=0;
-	restore_flags(flags);
+		netif_stop_queue(dev);
 
 	cep->cur_tx = (cbd_t *)bdp;
 
+	spin_unlock_irq(&cep->lock);
+
 	return 0;
 }
 
+static void
+scc_enet_timeout(struct net_device *dev)
+{
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
+
+	printk("%s: transmit timed out.\n", dev->name);
+	cep->stats.tx_errors++;
+#ifndef final_version
+	{
+		int	i;
+		cbd_t	*bdp;
+		printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
+		       cep->cur_tx, cep->tx_full ? " (full)" : "",
+		       cep->cur_rx);
+		bdp = cep->tx_bd_base;
+		for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
+			printk("%04x %04x %08x\n",
+			       bdp->cbd_sc,
+			       bdp->cbd_datlen,
+			       bdp->cbd_bufaddr);
+		bdp = cep->rx_bd_base;
+		for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
+			printk("%04x %04x %08x\n",
+			       bdp->cbd_sc,
+			       bdp->cbd_datlen,
+			       bdp->cbd_bufaddr);
+	}
+#endif
+	if (!cep->tx_full)
+		netif_wake_queue(dev);
+}
+
 /* The interrupt handler.
  * This is called from the CPM handler, not the MPC core interrupt.
  */
 static void
-cpm_enet_interrupt(void *dev_id)
+scc_enet_interrupt(void *dev_id)
 {
 	struct	net_device *dev = dev_id;
-	volatile struct	cpm_enet_private *cep;
+	volatile struct	scc_enet_private *cep;
 	volatile cbd_t	*bdp;
 	ushort	int_events;
 	int	must_restart;
 
-	cep = (struct cpm_enet_private *)dev->priv;
-	if (cep->interrupt)
-		printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
-	cep->interrupt = 1;
+	cep = (struct scc_enet_private *)dev->priv;
 
 	/* Get the interrupt events that caused us to be here.
 	*/
@@ -349,7 +328,7 @@
 	/* Handle receive event in its own function.
 	*/
 	if (int_events & SCCE_ENET_RXF)
-		cpm_enet_rx(dev_id);
+		scc_enet_rx(dev_id);
 
 	/* Check for a transmit error.  The manual is a little unclear
 	 * about this, so the debug code until I get it figured out.  It
@@ -363,6 +342,7 @@
 	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.
 	*/
 	if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+	    spin_lock(&cep->lock);
 	    bdp = cep->dirty_tx;
 	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
 		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
@@ -421,10 +401,9 @@
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
-		if (cep->tx_full && cep->tx_busy) {
-			cep->tx_full = 0;
-			cep->tx_busy = 0;
-			netif_wake_queue(dev);
+		if (cep->tx_full) {
+			if (netif_queue_stopped(dev))
+				netif_wake_queue(dev);
 		}
 
 		cep->dirty_tx = (cbd_t *)bdp;
@@ -444,6 +423,7 @@
 		    mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG;
 		while (cp->cp_cpcr & CPM_CR_FLG);
 	    }
+	    spin_unlock(&cep->lock);
 	}
 
 	/* Check for receive busy, i.e. packets coming but no place to
@@ -455,8 +435,6 @@
 		printk("CPM ENET: BSY can't happen.\n");
 	}
 
-	cep->interrupt = 0;
-
 	return;
 }
 
@@ -466,14 +444,14 @@
  * effectively tossing the packet.
  */
 static int
-cpm_enet_rx(struct net_device *dev)
+scc_enet_rx(struct net_device *dev)
 {
-	struct	cpm_enet_private *cep;
+	struct	scc_enet_private *cep;
 	volatile cbd_t	*bdp;
 	struct	sk_buff *skb;
 	ushort	pkt_len;
 
-	cep = (struct cpm_enet_private *)dev->priv;
+	cep = (struct scc_enet_private *)dev->priv;
 
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
@@ -560,7 +538,7 @@
 }
 
 static int
-cpm_enet_close(struct net_device *dev)
+scc_enet_close(struct net_device *dev)
 {
 	/* Don't know what to do yet.
 	*/
@@ -569,9 +547,9 @@
 	return 0;
 }
 
-static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev)
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev)
 {
-	struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+	struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
 
 	return &cep->stats;
 }
@@ -588,12 +566,12 @@
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct	cpm_enet_private *cep;
+	struct	scc_enet_private *cep;
 	struct	dev_mc_list *dmi;
 	u_char	*mcptr, *tdptr;
 	volatile scc_enet_t *ep;
 	int	i, j;
-	cep = (struct cpm_enet_private *)dev->priv;
+	cep = (struct scc_enet_private *)dev->priv;
 
 	/* Get pointer to SCC area in parameter RAM.
 	*/
@@ -661,10 +639,10 @@
  * transmit and receive to make sure we don't catch the CPM with some
  * inconsistent control information.
  */
-int __init cpm_enet_init(void)
+int __init scc_enet_init(void)
 {
 	struct net_device *dev;
-	struct cpm_enet_private *cep;
+	struct scc_enet_private *cep;
 	int i, j;
 	unsigned char	*eap;
 	unsigned long	mem_addr;
@@ -684,9 +662,10 @@
 
 	/* Allocate some private information.
 	*/
-	cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+	cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
 	/*memset(cep, 0, sizeof(*cep));*/
 	__clear_user(cep,sizeof(*cep));
+	spin_lock_init(&cep->lock);
 
 	/* Create an Ethernet device instance.
 	*/
@@ -858,7 +837,7 @@
 		*/
 		pte = find_pte(&init_mm, mem_addr);
 		pte_val(*pte) |= _PAGE_NO_CACHE;
-		flush_tlb_page(current->mm->mmap, mem_addr);
+		flush_tlb_page(init_mm.mmap, mem_addr);
 
 		/* Initialize the BD for every fragment in the page.
 		*/
@@ -894,7 +873,7 @@
 
 	/* Install our interrupt handler.
 	*/
-	cpm_install_handler(CPMVEC_ENET, cpm_enet_interrupt, dev);
+	cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev);
 
 	/* Set GSMR_H to enable all normal operating modes.
 	 * Set GSMR_L to enable Ethernet to MC68160.
@@ -953,10 +932,12 @@
 #endif
 
 	/* The CPM Ethernet specific entries in the device structure. */
-	dev->open = cpm_enet_open;
-	dev->hard_start_xmit = cpm_enet_start_xmit;
-	dev->stop = cpm_enet_close;
-	dev->get_stats = cpm_enet_get_stats;
+	dev->open = scc_enet_open;
+	dev->hard_start_xmit = scc_enet_start_xmit;
+	dev->tx_timeout = scc_enet_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->stop = scc_enet_close;
+	dev->get_stats = scc_enet_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
 	/* And last, enable the transmit and receive processing.
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.3.99-pre6/linux/arch/ppc/8xx_io/uart.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/8xx_io/uart.c	Tue May  2 13:05:39 2000
@@ -41,6 +41,10 @@
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
 #include "commproc.h"
+ 
+#ifdef CONFIG_KGDB
+extern int  kgdb_output_string (const char* s, unsigned int count);
+#endif
 
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
@@ -700,25 +704,18 @@
 		 * are coming.
 		 */
 		up = (smc_uart_t *)&cpmp->cp_dparam[state->port];
-#if 0
-		up->smc_mrblr = 1;	/* receive buffer length */
-		up->smc_maxidl = 0;	/* wait forever for next char */
-#else
+
 		up->smc_mrblr = RX_BUF_SIZE;
 		up->smc_maxidl = RX_BUF_SIZE;
-#endif
+
 		up->smc_brkcr = 1;	/* number of break chars */
 	}
 	else {
 		sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
 		scup = (scc_uart_t *)&cpmp->cp_dparam[state->port];
-#if 0
-		scup->scc_genscc.scc_mrblr = 1;	/* receive buffer length */
-		scup->scc_maxidl = 0;	/* wait forever for next char */
-#else
+
 		scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
 		scup->scc_maxidl = RX_BUF_SIZE;
-#endif
 
 		sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
 		sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
@@ -959,6 +956,12 @@
 	ser_info_t *info = (ser_info_t *)tty->driver_data;
 	volatile cbd_t *bdp;
 
+#ifdef CONFIG_KGDB
+	/* Try to let stub handle output. Returns true if it did. */ 
+	if (kgdb_output_string(buf, count))
+		return ret;
+#endif
+
 	if (serial_paranoia_check(info, tty->device, "rs_write"))
 		return 0;
 
@@ -979,8 +982,8 @@
 		}
 
 		if (from_user) {
-			if (c !=
-			    copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
+			c -= copy_from_user(__va(bdp->cbd_bufaddr), buf, c);
+			if (!c) {
 				if (!ret)
 					ret = -EFAULT;
 				break;
@@ -2099,7 +2102,7 @@
  * Print a string to the serial port trying not to disturb any possible
  * real use of the port...
  */
-static void serial_console_write(struct console *c, const char *s,
+static void my_console_write(int idx, const char *s,
 				unsigned count)
 {
 	struct		serial_state	*ser;
@@ -2109,7 +2112,7 @@
 	volatile	smc_uart_t	*up;
 	volatile	u_char		*cp;
 
-	ser = rs_table + c->index;
+	ser = rs_table + idx;
 
 	/* If the port has been initialized for general use, we have
 	 * to use the buffer descriptors allocated there.  Otherwise,
@@ -2146,8 +2149,15 @@
 		 * that, not that it is ready for us to send.
 		 */
 		while (bdp->cbd_sc & BD_SC_READY);
-		/* Send the character out. */
-		cp = __va(bdp->cbd_bufaddr);
+
+		/* Send the character out.
+		 * If the buffer address is in the CPM DPRAM, don't
+		 * convert it.
+		 */
+		if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)
+			cp = (u_char *)(bdp->cbd_bufaddr);
+		else
+			cp = __va(bdp->cbd_bufaddr);
 		*cp = *s;
 		
 		bdp->cbd_datlen = 1;
@@ -2185,19 +2195,48 @@
 		info->tx_cur = (cbd_t *)bdp;
 }
 
+static void serial_console_write(struct console *c, const char *s,
+				unsigned count)
+{
+#ifdef CONFIG_KGDB
+	/* Try to let stub handle output. Returns true if it did. */ 
+	if (kgdb_output_string(s, count))
+		return;
+#endif
+	my_console_write(c->index, s, count);
+}
+
+#ifdef CONFIG_XMON
+int
+xmon_8xx_write(const char *s, unsigned count)
+{
+	my_console_write(0, s, count);
+	return(count);
+}
+#endif
+
+#ifdef CONFIG_KGDB
+void
+putDebugChar(char ch)
+{
+	my_console_write(0, &ch, 1);
+}
+#endif
+
 /*
  * Receive character from the serial port.  This only works well
  * before the port is initialize for real use.
  */
-static int serial_console_wait_key(struct console *co)
+static int my_console_wait_key(int idx, int xmon, char *obuf)
 {
 	struct serial_state		*ser;
 	u_char				c, *cp;
 	ser_info_t			*info;
 	volatile	cbd_t		*bdp;
 	volatile	smc_uart_t	*up;
+	int				i;
 
-	ser = rs_table + co->index;
+	ser = rs_table + idx;
 
 	/* Pointer to UART in parameter ram.
 	*/
@@ -2215,9 +2254,34 @@
 	/*
 	 * We need to gracefully shut down the receiver, disable
 	 * interrupts, then read the input.
+	 * XMON just wants a poll.  If no character, return -1, else
+	 * return the character.
+	 */
+	if (!xmon) {
+		while (bdp->cbd_sc & BD_SC_EMPTY);
+	}
+	else {
+		if (bdp->cbd_sc & BD_SC_EMPTY)
+			return -1;
+	}
+
+	/* If the buffer address is in the CPM DPRAM, don't
+	 * convert it.
 	 */
-	while (bdp->cbd_sc & BD_SC_EMPTY);	/* Wait for a character */
-	cp = __va(bdp->cbd_bufaddr);
+	if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)
+		cp = (u_char *)(bdp->cbd_bufaddr);
+	else
+		cp = __va(bdp->cbd_bufaddr);
+
+	if (obuf) {
+		i = c = bdp->cbd_datlen;
+		while (i-- > 0)
+			*obuf++ = *cp++;
+	}
+	else {
+		c = *cp;
+	}
+	bdp->cbd_sc |= BD_SC_EMPTY;
 
 	if (info) {
 		if (bdp->cbd_sc & BD_SC_WRAP) {
@@ -2229,10 +2293,89 @@
 		info->rx_cur = (cbd_t *)bdp;
 	}
 
-	c = *cp;
 	return((int)c);
 }
 
+static int serial_console_wait_key(struct console *co)
+{
+	return(my_console_wait_key(co->index, 0, NULL));
+}
+
+#ifdef CONFIG_XMON
+int
+xmon_8xx_read_poll(void)
+{
+	return(my_console_wait_key(0, 1, NULL));
+}
+
+int
+xmon_8xx_read_char(void)
+{
+	return(my_console_wait_key(0, 0, NULL));
+}
+#endif
+
+#ifdef CONFIG_KGDB
+static char kgdb_buf[RX_BUF_SIZE], *kgdp;
+static int kgdb_chars;
+
+unsigned char
+getDebugChar(void)
+{
+	if (kgdb_chars <= 0) {
+		kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
+		kgdp = kgdb_buf;
+	}
+	kgdb_chars--;
+
+	return(*kgdp++);
+}
+
+void kgdb_interruptible(int state)
+{
+}
+void kgdb_map_scc(void)
+{
+	struct		serial_state *ser;
+	uint		mem_addr;
+	volatile	cbd_t		*bdp;
+	volatile	smc_uart_t	*up;
+
+	cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+
+	/* To avoid data cache CPM DMA coherency problems, allocate a
+	 * buffer in the CPM DPRAM.  This will work until the CPM and
+	 * serial ports are initialized.  At that time a memory buffer
+	 * will be allcoated.
+	 * The port is already initialized from the boot procedure, all
+	 * we do here is give it a different buffer and make it a FIFO.
+	 */
+
+	ser = rs_table;
+
+	/* Right now, assume we are using SMCs.
+	*/
+	up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+	/* Allocate space for an input FIFO, plus a few bytes for output.
+	 * Allocate bytes to maintain word alignment.
+	 */
+	mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+	bdp->cbd_bufaddr = mem_addr;
+
+	bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+	bdp->cbd_bufaddr = mem_addr+RX_BUF_SIZE;
+
+	up->smc_mrblr = RX_BUF_SIZE;		/* receive buffer length */
+	up->smc_maxidl = RX_BUF_SIZE;
+}
+#endif
+
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTYAUX_MAJOR, 64 + c->index);
@@ -2522,8 +2665,8 @@
 				 * character interrupts.  Using idle charater
 				 * time requires some additional tuning.
 				 */
-				up->smc_mrblr = 1;
-				up->smc_maxidl = 0;
+				up->smc_mrblr = RX_BUF_SIZE;
+				up->smc_maxidl = RX_BUF_SIZE;
 				up->smc_brkcr = 1;
 
 				/* Send the CPM an initialize command.
@@ -2557,12 +2700,8 @@
 				sup->scc_genscc.scc_rfcr = SMC_EB;
 				sup->scc_genscc.scc_tfcr = SMC_EB;
 
-				/* Set this to 1 for now, so we get single
-				 * character interrupts.  Using idle charater
-				 * time requires some additional tuning.
-				 */
-				sup->scc_genscc.scc_mrblr = 1;
-				sup->scc_maxidl = 0;
+				sup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
+				sup->scc_maxidl = RX_BUF_SIZE;
 				sup->scc_brkcr = 1;
 				sup->scc_parec = 0;
 				sup->scc_frmec = 0;
@@ -2629,6 +2768,7 @@
 #endif
 		}
 	}
+
 	return 0;
 }
 
@@ -2678,16 +2818,17 @@
 	*/
 	dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 2);
 
-	/* Allocate space for two 2 byte FIFOs in the host memory.
-	*/
-	mem_addr = m8xx_cpm_hostalloc(4);
+	/* Allocate space for an input FIFO, plus a few bytes for output.
+	 * Allocate bytes to maintain word alignment.
+	 */
+	mem_addr = m8xx_cpm_hostalloc(RX_BUF_SIZE + 4);
 
 	/* Set the physical address of the host memory buffers in
 	 * the buffer descriptors.
 	 */
 	bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
 	bdp->cbd_bufaddr = __pa(mem_addr);
-	(bdp+1)->cbd_bufaddr = __pa(mem_addr+2);
+	(bdp+1)->cbd_bufaddr = __pa(mem_addr+RX_BUF_SIZE);
 
 	/* For the receive, set empty and wrap.
 	 * For transmit, set wrap.
@@ -2702,10 +2843,8 @@
 	up->smc_rfcr = SMC_EB;
 	up->smc_tfcr = SMC_EB;
 
-	/* Set this to 1 for now, so we get single character interrupts.
-	*/
-	up->smc_mrblr = 1;		/* receive buffer length */
-	up->smc_maxidl = 0;		/* wait forever for next char */
+	up->smc_mrblr = RX_BUF_SIZE;		/* receive buffer length */
+	up->smc_maxidl = RX_BUF_SIZE;
 
 	/* Send the CPM an initialize command.
 	*/
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.99-pre6/linux/arch/ppc/Makefile	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/Makefile	Tue May  2 13:05:39 2000
@@ -22,7 +22,7 @@
 LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
 CPPFLAGS	:= $(CPPFLAGS) -D__powerpc__
 CFLAGS		:= $(CFLAGS) -D__powerpc__ -fsigned-char \
-		-msoft-float -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized \
+		-msoft-float -pipe -ffixed-r2 -Wno-uninitialized \
 		-mmultiple -mstring
 CPP		= $(CC) -E $(CFLAGS)
 
@@ -75,6 +75,11 @@
 DRIVERS += arch/ppc/8xx_io/8xx_io.a
 endif
 
+ifdef CONFIG_8260
+SUBDIRS += arch/ppc/8260_io
+DRIVERS += arch/ppc/8260_io/8260_io.a
+endif
+
 ifdef CONFIG_APUS
 SUBDIRS += arch/ppc/amiga
 ARCHIVES += arch/ppc/amiga/amiga.o
@@ -98,6 +103,7 @@
 endif
 
 ifdef CONFIG_6xx
+ifndef CONFIG_8260
 $(BOOT_TARGETS): $(CHECKS) vmlinux
 	@$(MAKECOFFBOOT) $@
 	@$(MAKEBOOT) $@
@@ -114,6 +120,12 @@
 	@$(MAKECOFFBOOT) $@
 	@$(MAKEBOOT) $@
 	@$(MAKECHRPBOOT) $@
+else
+# 8260 is custom 6xx
+$(BOOT_TARGETS): $(CHECKS) vmlinux
+	@$(MAKECOFFBOOT) $@
+	@$(MAKEMBXBOOT) $@
+endif
 endif
 
 ifdef CONFIG_PPC64
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.99-pre6/linux/arch/ppc/config.in	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/config.in	Tue May  2 13:05:39 2000
@@ -18,9 +18,14 @@
 	"6xx/7xx/7400		CONFIG_6xx	\
 	 4xx			CONFIG_4xx	\
 	 630/Power3(64-Bit)	CONFIG_PPC64	\
-	 82xx			CONFIG_82xx	\
+	 8260			CONFIG_8260	\
 	 8xx			CONFIG_8xx"	6xx
 
+if [ "$CONFIG_8260" = "y" ]; then
+  define_bool CONFIG_6xx y
+  define_bool CONFIG_SERIAL_CONSOLE y
+fi
+
 if [ "$CONFIG_4xx" = "y" ]; then
     choice 'Machine Type'			\
 	"Oak			CONFIG_OAK 	\
@@ -49,6 +54,7 @@
   choice 'Machine Type'		\
 	"PowerMac/PReP/MTX/CHRP	CONFIG_ALL_PPC	\
 	 Gemini		CONFIG_GEMINI		\
+	 EST8260	CONFIG_EST8260		\
 	 APUS		CONFIG_APUS"		PowerMac/PReP/MTX/CHRP
 fi
 
@@ -56,6 +62,10 @@
   define_bool CONFIG_ALL_PPC y
 fi
 
+if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then
+  define_bool CONFIG_ALL_PPC n
+fi
+
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_6xx" = "y" ];then
   bool 'AltiVec Support' CONFIG_ALTIVEC
@@ -86,7 +96,7 @@
 define_bool CONFIG_SBUS n
 
 if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \
-     "$CONFIG_82xx" = "y" ]; then
+     "$CONFIG_8260" = "y" ]; then
    define_bool CONFIG_PCI n
 else
    if [ "$CONFIG_6xx" = "y" -o "$CONFIG_PPC64" = "y" ]; then
@@ -144,7 +154,6 @@
      bool 'Support for ADB mouse' CONFIG_ADBMOUSE
   fi
   bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-  bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
   bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
   bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
 fi
@@ -226,6 +235,8 @@
 
 source net/ax25/Config.in
 
+source net/irda/Config.in
+
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
@@ -264,6 +275,10 @@
 
 if [ "$CONFIG_8xx" = "y" ]; then
 source arch/ppc/8xx_io/Config.in
+fi
+
+if [ "$CONFIG_8260" = "y" ]; then
+source arch/ppc/8260_io/Config.in
 fi
 
 source drivers/usb/Config.in
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/configs/chrp_defconfig linux/arch/ppc/configs/chrp_defconfig
--- v2.3.99-pre6/linux/arch/ppc/configs/chrp_defconfig	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/configs/chrp_defconfig	Wed Dec 31 16:00:00 1969
@@ -1,319 +0,0 @@
-#
-# Automatically generated by make menuconfig: don't edit
-#
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_6xx=y
-# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
-# CONFIG_PREP is not set
-CONFIG_CHRP=y
-# CONFIG_ALL_PPC is not set
-# CONFIG_APUS is not set
-# CONFIG_MBX is not set
-# CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
-CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
-CONFIG_NET=y
-CONFIG_SYSCTL=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_FB=y
-CONFIG_FB_COMPAT_XPMAC=y
-# CONFIG_PMAC_PBOOK is not set
-CONFIG_MAC_KEYBOARD=y
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADBMOUSE is not set
-CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-# CONFIG_TOTALMP is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
-# CONFIG_IDE_CHIPSETS is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
-CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
-CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
-# CONFIG_NET_SCHED is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
-# CONFIG_SCSI_DEBUG is not set
-CONFIG_SCSI_MESH=y
-CONFIG_SCSI_MESH_SYNC_RATE=10
-CONFIG_SCSI_MAC53C94=y
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-# 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_NET_ISA is not set
-CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
-CONFIG_DEC_ELCP=y
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_LNE390 is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_TLAN is not set
-# CONFIG_ES3210 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
-# CONFIG_NET_POCKET is not set
-# CONFIG_FDDI is not set
-# CONFIG_DLCI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_RADIO is not set
-# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
-#
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_OF=y
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
-CONFIG_FB_ATY=y
-CONFIG_FB_IMSTT=y
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_S3TRIO is not set
-CONFIG_FB_VGA=y
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-CONFIG_FBCON_VGA=y
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-# CONFIG_FBCON_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_MOUSE is not set
-# CONFIG_UMISC is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_VIDEO_DEV is not set
-CONFIG_NVRAM=y
-# CONFIG_JOYSTICK is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-
-#
-# Filesystems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET 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_PROC_FS=y
-CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_ADFS_FS is not set
-CONFIG_MAC_PARTITION=y
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig
--- v2.3.99-pre6/linux/arch/ppc/configs/common_defconfig	Mon Mar 27 08:08:22 2000
+++ linux/arch/ppc/configs/common_defconfig	Tue May  2 13:05:39 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 # CONFIG_UID16 is not set
 
@@ -33,8 +33,8 @@
 #
 # General setup
 #
-# CONFIG_PCI is not set
-CONFIG_PCI=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
 CONFIG_PCI=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
@@ -46,6 +46,7 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -57,6 +58,7 @@
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADB=y
 CONFIG_ADB_CUDA=y
 CONFIG_ADB_MACIO=y
@@ -64,7 +66,6 @@
 CONFIG_ADB_KEYBOARD=y
 CONFIG_ADBMOUSE=y
 CONFIG_PROC_DEVICETREE=y
-# CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
 # CONFIG_CMDLINE_BOOL is not set
@@ -73,21 +74,22 @@
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_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=y
 # 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
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 
@@ -112,18 +114,10 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_DECNET is not set
@@ -150,35 +144,52 @@
 # IDE, ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS 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
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_CMD64X_RAID is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_HPT366_FIP is not set
+# CONFIG_HPT366_MODE3 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_VIA82CXXX_TUNING is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -192,10 +203,6 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
@@ -203,10 +210,6 @@
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
@@ -226,12 +229,12 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
@@ -262,11 +265,9 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -345,6 +346,7 @@
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
@@ -483,66 +485,17 @@
 #
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
 # CONFIG_AGP is not set
 
 #
-# USB support
-#
-CONFIG_USB=y
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_CPIA is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_DSBR is not set
-
-#
-# USB HID
-#
-# CONFIG_USB_HID is not set
-CONFIG_USB_KBD=y
-CONFIG_USB_MOUSE=y
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_WMFORCE is not set
-CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_MIX is not set
-# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
 # 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=y
 # CONFIG_BFS_FS is not set
@@ -552,32 +505,51 @@
 CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
@@ -632,6 +604,7 @@
 # Sound
 #
 CONFIG_SOUND=y
+CONFIG_DMASOUND_AWACS=y
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -652,6 +625,7 @@
 CONFIG_SOUND_CS4232=m
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_VMIDI is not set
 # CONFIG_SOUND_TRIX is not set
 # CONFIG_SOUND_MSS is not set
@@ -659,6 +633,7 @@
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_SOFTOSS is not set
 # CONFIG_SOUND_SB is not set
@@ -671,6 +646,41 @@
 # CONFIG_SOUND_OPL3SA2 is not set
 # CONFIG_SOUND_UART6850 is not set
 # CONFIG_SOUND_AEDSP16 is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_HID=y
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_WMFORCE is not set
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/configs/pmac_defconfig linux/arch/ppc/configs/pmac_defconfig
--- v2.3.99-pre6/linux/arch/ppc/configs/pmac_defconfig	Fri Jan 21 18:19:16 2000
+++ linux/arch/ppc/configs/pmac_defconfig	Wed Dec 31 16:00:00 1969
@@ -1,550 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_6xx=y
-# CONFIG_PPC64 is not set
-# CONFIG_82xx is not set
-# CONFIG_8xx is not set
-CONFIG_PMAC=y
-# CONFIG_PREP is not set
-# CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
-# CONFIG_GEMINI is not set
-# CONFIG_APUS is not set
-# CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
-CONFIG_6xx=y
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_SYSCTL=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/Cardbus support
-#
-CONFIG_PCMCIA=m
-CONFIG_CARDBUS=y
-# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FB=y
-CONFIG_FB_COMPAT_XPMAC=y
-CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_FLOPPY=y
-CONFIG_MAC_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_MACIO=y
-CONFIG_ADB_PMU=y
-CONFIG_ADB_KEYBOARD=y
-CONFIG_PROC_DEVICETREE=y
-# CONFIG_TOTALMP is not set
-CONFIG_BOOTX_TEXT=y
-# CONFIG_MOTOROLA_HOTSWAP is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y
-CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-CONFIG_BLK_DEV_CMD646=y
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_IDEDMA_PMAC_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-CONFIG_ATALK=m
-# CONFIG_DECNET is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_PROC_STATS=y
-CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
-# CONFIG_SCSI_DEBUG is not set
-CONFIG_SCSI_MESH=y
-CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MAC53C94=y
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
-# CONFIG_NET_SB1000 is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MACE=y
-CONFIG_BMAC=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_YELLOWFIN is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
-# CONFIG_ACENIC is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_LNE390 is not set
-# CONFIG_NE3210 is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_ES3210 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
-# CONFIG_NET_POCKET is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring driver support
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# PCMCIA network devices
-#
-# CONFIG_PCMCIA_PCNET is not set
-# CONFIG_PCMCIA_3C589 is not set
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
-#
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
-CONFIG_FB_OF=y
-CONFIG_FB_CONTROL=y
-CONFIG_FB_PLATINUM=y
-CONFIG_FB_VALKYRIE=y
-CONFIG_FB_IMSTT=y
-CONFIG_FB_CT65550=y
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-CONFIG_FONT_8x16=y
-CONFIG_FONT_SUN8x16=y
-CONFIG_FONT_SUN12x22=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# Mice
-#
-CONFIG_BUSMOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_LOGIBUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_ADBMOUSE=y
-# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
-# CONFIG_RTC is not set
-
-#
-# 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
-
-#
-# USB drivers - not for the faint of heart
-#
-CONFIG_USB=y
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-CONFIG_USB_OHCI=y
-CONFIG_USB_OHCI_DEBUG=y
-# CONFIG_USB_OHCI_HCD is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEBUG_ISOC=y
-CONFIG_USB_PROC=y
-# CONFIG_USB_EZUSB is not set
-
-#
-# USB Devices
-#
-CONFIG_USB_HUB=y
-CONFIG_USB_MOUSE=y
-CONFIG_USB_HP_SCANNER=m
-CONFIG_USB_KBD=y
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_CPIA is not set
-CONFIG_USB_SCSI=m
-CONFIG_USB_SCSI_DEBUG=y
-# CONFIG_USB_USS720 is not set
-
-#
-# Filesystems
-#
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFSD=y
-# CONFIG_NFSD_SUN is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_OSF_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
-
-#
-# Kernel hacking
-#
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/configs/prep_defconfig linux/arch/ppc/configs/prep_defconfig
--- v2.3.99-pre6/linux/arch/ppc/configs/prep_defconfig	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/configs/prep_defconfig	Wed Dec 31 16:00:00 1969
@@ -1,361 +0,0 @@
-#
-# Automatically generated by make menuconfig: don't edit
-#
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_6xx=y
-# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
-CONFIG_PREP=y
-# CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
-# CONFIG_APUS is not set
-# CONFIG_MBX is not set
-# CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
-CONFIG_NET=y
-CONFIG_SYSCTL=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-# CONFIG_FB is not set
-CONFIG_VGA_CONSOLE=y
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_KEYBOARD is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADBMOUSE is not set
-# CONFIG_PROC_DEVICETREE is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-# CONFIG_IDE_CHIPSETS is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_RARP is not set
-# CONFIG_IP_NOSR is not set
-CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
-# CONFIG_NET_SCHED is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-# CONFIG_NET_VENDOR_3COM is not set
-CONFIG_LANCE=y
-# 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_NET_ISA is not set
-CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_LNE390 is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_TLAN is not set
-# CONFIG_ES3210 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
-# CONFIG_NET_POCKET is not set
-# CONFIG_FDDI is not set
-# CONFIG_DLCI is not set
-CONFIG_PPP=m
-# CONFIG_SLIP is not set
-# CONFIG_NET_RADIO is not set
-# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
-#
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_MOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
-# CONFIG_JOYSTICK is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-
-#
-# Filesystems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_DEVPTS_FS is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_KOI8_R is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=y
-CONFIG_CS4232_BASE=530
-CONFIG_CS4232_IRQ=11
-CONFIG_CS4232_DMA=0
-CONFIG_CS4232_DMA2=3
-CONFIG_CS4232_MPU_BASE=330
-CONFIG_CS4232_MPU_IRQ=9
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.99-pre6/linux/arch/ppc/defconfig	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/defconfig	Mon May  8 22:00:41 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 # CONFIG_UID16 is not set
 
@@ -66,7 +66,6 @@
 CONFIG_ADB_KEYBOARD=y
 CONFIG_ADBMOUSE=y
 CONFIG_PROC_DEVICETREE=y
-# CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
 # CONFIG_CMDLINE_BOOL is not set
@@ -85,13 +84,12 @@
 # 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=y
 # 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
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 
@@ -116,18 +114,10 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_DECNET is not set
@@ -154,10 +144,6 @@
 # IDE, ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
@@ -167,10 +153,6 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
@@ -207,6 +189,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_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -220,10 +203,6 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
@@ -231,10 +210,6 @@
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
@@ -254,12 +229,12 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
@@ -290,11 +265,9 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -373,6 +346,7 @@
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
@@ -515,65 +489,13 @@
 # CONFIG_AGP is not set
 
 #
-# USB support
-#
-CONFIG_USB=y
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_CPIA is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_DSBR is not set
-
-#
-# USB HID
-#
-# CONFIG_USB_HID is not set
-CONFIG_USB_KBD=y
-CONFIG_USB_MOUSE=y
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_WMFORCE is not set
-CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_MIX is not set
-# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
 # 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=y
 # CONFIG_BFS_FS is not set
@@ -583,27 +505,35 @@
 CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
@@ -611,6 +541,16 @@
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
@@ -665,6 +605,7 @@
 # Sound
 #
 CONFIG_SOUND=y
+CONFIG_DMASOUND_AWACS=y
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -685,6 +626,7 @@
 CONFIG_SOUND_CS4232=m
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_VMIDI is not set
 # CONFIG_SOUND_TRIX is not set
 # CONFIG_SOUND_MSS is not set
@@ -705,6 +647,41 @@
 # CONFIG_SOUND_OPL3SA2 is not set
 # CONFIG_SOUND_UART6850 is not set
 # CONFIG_SOUND_AEDSP16 is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_HID=y
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_WMFORCE is not set
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.99-pre6/linux/arch/ppc/kernel/Makefile	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/Makefile	Tue May  2 13:05:39 2000
@@ -31,7 +31,7 @@
 endif
 
 O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \
-	  misc.o bitops.o ptrace.o align.o ppc_htab.o semaphore.o
+	  misc.o ptrace.o align.o ppc_htab.o semaphore.o bitops.o
 
 ifndef CONFIG_8xx
 O_OBJS += hashtable.o
@@ -45,10 +45,6 @@
 O_OBJS += ppc-stub.o
 endif
 
-ifdef CONFIG_TOTALMP
-O_OBJS += totalmp.o
-endif
-
 ifdef CONFIG_PMAC_PBOOK
 O_OBJS += sleep.o
 endif
@@ -99,6 +95,9 @@
 endif
 ifeq ($(CONFIG_GEMINI),y)
   O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o open_pic.o
+endif
+ifeq ($(CONFIG_8260),y)
+  O_OBJS += m8260_setup.o ppc8260_pic.o
 endif
 
 all: $(KHEAD) kernel.o
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/align.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/align.c	Tue May  2 13:05:39 2000
@@ -14,6 +14,7 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/cache.h>
 
 struct aligninfo {
 	unsigned char len;
@@ -38,6 +39,8 @@
 #define S	0x40	/* single-precision fp, or byte-swap value */
 #define HARD	0x80	/* string, stwcx. */
 
+#define DCBZ	0x5f	/* 8xx/82xx dcbz faults when cache not enabled */
+
 /*
  * The PowerPC stores certain bits of the instruction that caused the
  * alignment exception in the DSISR register.  This array maps those
@@ -220,9 +223,27 @@
 	areg = regs->dsisr & 0x1f;		/* register to update */
 	instr = (regs->dsisr >> 10) & 0x7f;
 #endif
+
 	nb = aligninfo[instr].len;
-	if (nb == 0)
-		return 0;	/* too hard or invalid instruction bits */
+	if (nb == 0) {
+		long *p;
+		int i;
+
+		if (instr != DCBZ)
+			return 0;	/* too hard or invalid instruction */
+		/*
+		 * The dcbz (data cache block zero) instruction
+		 * gives an alignment fault if used on non-cacheable
+		 * memory.  We handle the fault mainly for the
+		 * case when we are running with the cache disabled
+		 * for debugging.
+		 */
+		p = (long *) (regs->dar & -L1_CACHE_BYTES);
+		for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
+			p[i] = 0;
+		return 1;
+	}
+
 	flags = aligninfo[instr].flags;
 
 	/* For the 4xx-family processors, the 'dar' field of the
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/feature.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/kernel/feature.c	Tue May  2 13:05:39 2000
@@ -57,8 +57,8 @@
 	{0x38,1,OH_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
 	{0x38,1,OH_BAY_POWER_N},	/* FEATURE_Mediabay_power */
 	{0x38,0,OH_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
-	{0x38,0,OH_BAY_IDE_ENABLE},	/* FEATURE_Mediabay_IDE_enable */
-	{0x38,1,OH_IDE1_RESET_N},	/* FEATURE_Mediabay_IDE_reset */
+	{0x38,0,OH_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,OH_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
 	{0x38,0,OH_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
 	{0x38,0,0},			/* FEATURE_BMac_reset */
 	{0x38,0,0},			/* FEATURE_BMac_IO_enable */
@@ -68,6 +68,8 @@
 	{0x38,0,0},			/* FEATURE_Sound_CLK_Enable */
 	{0x38,0,0},			/* FEATURE_IDE2_enable */
 	{0x38,0,0},			/* FEATURE_IDE2_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
+	{0x38,0,0},			/* FEATURE_Mediabay_content */
 };
 
 /* Those bits are from a PowerBook. It's possible that desktop machines
@@ -87,8 +89,8 @@
 	{0x38,1,HRW_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
 	{0x38,1,HRW_BAY_POWER_N},	/* FEATURE_Mediabay_power */
 	{0x38,0,HRW_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
-	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_Mediabay_IDE_enable */
-	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_Mediabay_IDE_reset */
+	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
 	{0x38,0,HRW_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
 	{0x38,0,HRW_BMAC_RESET},	/* FEATURE_BMac_reset */
 	{0x38,0,HRW_BMAC_IO_ENABLE},	/* FEATURE_BMac_IO_enable */
@@ -98,9 +100,44 @@
 	{0x38,0,HRW_SOUND_CLK_ENABLE},	/* FEATURE_Sound_CLK_Enable */
 	{0x38,0,0},			/* FEATURE_IDE2_enable */
 	{0x38,0,0},			/* FEATURE_IDE2_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
+	{0x38,0,0},			/* FEATURE_Mediabay_content */
 };
 
-/* Those bits are from an iBook.
+/*
+ * Those bits are from a 1999 G3 PowerBook, with a paddington chip.
+ * Mostly the same as the heathrow.
+ */
+static fbit feature_bits_paddington[] = {
+	{0x38,0,0},			/* FEATURE_null */
+	{0x38,0,0},			/* FEATURE_Serial_reset */
+	{0x38,0,HRW_SCC_ENABLE},	/* FEATURE_Serial_enable */
+	{0x38,0,HRW_SCCA_IO},		/* FEATURE_Serial_IO_A */
+	{0x38,0,HRW_SCCB_IO},		/* FEATURE_Serial_IO_B */
+	{0x38,0,HRW_SWIM_ENABLE},	/* FEATURE_SWIM3_enable */
+	{0x38,0,HRW_MESH_ENABLE},	/* FEATURE_MESH_enable */
+	{0x38,0,HRW_IDE0_ENABLE},	/* FEATURE_IDE0_enable */
+	{0x38,1,HRW_IDE0_RESET_N},	/* FEATURE_IDE0_reset */
+	{0x38,0,HRW_IOBUS_ENABLE},	/* FEATURE_IOBUS_enable */
+	{0x38,1,HRW_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
+	{0x38,1,HRW_BAY_POWER_N},	/* FEATURE_Mediabay_power */
+	{0x38,0,HRW_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
+	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
+	{0x38,0,HRW_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
+	{0x38,0,HRW_BMAC_RESET},	/* FEATURE_BMac_reset */
+	{0x38,0,HRW_BMAC_IO_ENABLE},	/* FEATURE_BMac_IO_enable */
+	{0x38,1,PADD_MODEM_POWER_N},	/* FEATURE_Modem_power */
+	{0x38,0,HRW_SLOW_SCC_PCLK},	/* FEATURE_Slow_SCC_PCLK */
+	{0x38,1,HRW_SOUND_POWER_N},	/* FEATURE_Sound_Power */
+	{0x38,0,HRW_SOUND_CLK_ENABLE},	/* FEATURE_Sound_CLK_Enable */
+	{0x38,0,0},			/* FEATURE_IDE2_enable */
+	{0x38,0,0},			/* FEATURE_IDE2_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
+	{0x38,0,0},			/* FEATURE_Mediabay_content */
+};
+
+/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
  */
 static fbit feature_bits_keylargo[] = {
 	{0x38,0,0},			/* FEATURE_null */
@@ -110,14 +147,14 @@
 	{0x38,0,0},			/* FEATURE_Serial_IO_B */
 	{0x38,0,0},			/* FEATURE_SWIM3_enable */
 	{0x38,0,0},			/* FEATURE_MESH_enable */
-	{0x38,0,0},			/* FEATURE_IDE0_enable */
-	{0x3c,1,0x01000000},		/* FEATURE_IDE0_reset */
+	{0x3c,0,0},			/* FEATURE_IDE0_enable */
+ 	{0x3c,1,0x01000000},		/* FEATURE_IDE0_reset */
 	{0x38,0,0},			/* FEATURE_IOBUS_enable */
-	{0x38,0,0},			/* FEATURE_Mediabay_reset */
-	{0x38,0,0},			/* FEATURE_Mediabay_power */
+	{0x34,1,0x00000200},		/* FEATURE_Mediabay_reset */
+	{0x34,1,0x00000400},		/* FEATURE_Mediabay_power */
 	{0x38,0,0},			/* FEATURE_Mediabay_PCI_enable */
-	{0x38,0,0},			/* FEATURE_Mediabay_IDE_enable */
-	{0x3c,1,0x08000000},		/* FEATURE_Mediabay_IDE_reset */
+	{0x3c,0,0x0},			/* FEATURE_IDE1_enable */
+	{0x3c,1,0x08000000},		/* FEATURE_IDE1_reset */
 	{0x38,0,0},			/* FEATURE_Mediabay_floppy_enable */
 	{0x38,0,0},			/* FEATURE_BMac_reset */
 	{0x38,0,0},			/* FEATURE_BMac_IO_enable */
@@ -127,6 +164,8 @@
 	{0x38,0,0},			/* FEATURE_Sound_CLK_Enable */
 	{0x38,0,0},			/* FEATURE_IDE2_enable */
 	{0x3c,1,0x40000000},		/* FEATURE_IDE2_reset */
+	{0x34,0,0x00001000},		/* FEATURE_Mediabay_IDE_switch */
+	{0x34,0,0x00000100},		/* FEATURE_Mediabay_content */
 };
 
 /* definition of a feature controller object */
@@ -164,6 +203,8 @@
 		 */
 		if (device_is_compatible(np, "Keylargo")) {
 			feature_add_controller(np, feature_bits_keylargo);
+		} else if (device_is_compatible(np, "paddington")) {
+			feature_add_controller(np, feature_bits_paddington);
 		} else {
 			feature_add_controller(np, feature_bits_heathrow);
 		}
@@ -268,6 +309,8 @@
 	if (!controller)
 		return -ENODEV;
 	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
 #ifdef DEBUG_FEATURE
 	printk("feature: <%s> setting feature %d in controller @0x%x\n",
@@ -299,6 +342,8 @@
 	if (!controller)
 		return -ENODEV;
 	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
 #ifdef DEBUG_FEATURE
 	printk("feature: <%s> clearing feature %d in controller @0x%x\n",
@@ -329,6 +374,8 @@
 	if (!controller)
 		return -ENODEV;
 	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
 #ifdef DEBUG_FEATURE
 	printk("feature: <%s> clearing feature %d in controller @0x%x\n",
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/gemini_pci.c	Tue Jan 11 22:31:37 2000
+++ linux/arch/ppc/kernel/gemini_pci.c	Tue May  2 13:05:39 2000
@@ -77,178 +77,19 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-struct gemini_device {
-	unsigned short vendor, device;
-	unsigned char irq;
-	unsigned short cmd;
-	unsigned char cache_line, latency;
-	void (*init)(struct pci_dev *dev);
-};
-
-static struct gemini_device gemini_map[] = {
-	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885, 11, 0x15, 32, 248, NULL },
-	{ PCI_VENDOR_ID_NCR, 0x701, 10, 0, 0, 0, NULL },
-	{ PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 3, 0, 0, 0, NULL },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_MPIC, 0xff, 0, 0, 0, NULL },
-	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_670, 0xff, 0, 0, 0, NULL },
-	{ PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC106, 0xff, 0, 0, 0, NULL },
-};
-
-static int gemini_map_count = (sizeof( gemini_map ) /
-                               sizeof( gemini_map[0] ));
-
- 
-
-/*  This just sets up the known devices on the board. */
-static void __init mapin_device( struct pci_dev *dev )
-{
-	struct gemini_device *p;
-	unsigned short cmd;
-	int i;
-  
-
-	for( i=0; i < gemini_map_count; i++ ) {
-		p = &(gemini_map[i]);
-    
-		if ( p->vendor == dev->vendor && 
-		     p->device == dev->device ) {
-     
-			if (p->irq != 0xff) {
-				pci_write_config_byte( dev, PCI_INTERRUPT_LINE, p->irq );
-				dev->irq = p->irq;
-			}
-
-			if (p->cmd) {
-				pci_read_config_word( dev, PCI_COMMAND, &cmd );
-				pci_write_config_word( dev, PCI_COMMAND, (p->cmd|cmd));
-			}
-
-			if (p->cache_line)
-				pci_write_config_byte( dev, PCI_CACHE_LINE_SIZE, p->cache_line );
- 
-			if (p->latency)
-				pci_write_config_byte( dev, PCI_LATENCY_TIMER, p->latency );
-		}
-	}
-}
-
-#define KB 1024
-#define MB (KB*KB)
-
-#define ALIGN(val,align) (((val) + ((align) -1))&(~((align) -1)))
-#define MAX(a,b)   (((a) > (b)) ? (a) : (b))
-
-#define FIRST_IO_ADDR 0x10000
-#define FIRST_MEM_ADDR 0x02000000
-
-#define GEMINI_PCI_MEM_BASE (0xf0000000)
-#define GEMINI_PCI_IO_BASE  (0xfe800000)
-
-static unsigned long pci_mem_base = GEMINI_PCI_MEM_BASE;
-static unsigned long pci_io_base = GEMINI_PCI_IO_BASE;
-
-static unsigned int io_base = FIRST_IO_ADDR;
-static unsigned int mem_base = FIRST_MEM_ADDR;
-
-
-
-__init void layout_dev( struct pci_dev *dev )
+void __init gemini_pcibios_fixup(void)
 {
 	int i;
-	struct pci_bus *bus;
-	unsigned short cmd;
-	unsigned int reg, base, mask, size, alignto, type;
-
-	bus = dev->bus;
-
-	/* make any known settings happen */
-	mapin_device( dev );
-
-	gemini_pcibios_read_config_word( bus->number, dev->devfn, PCI_COMMAND, &cmd );
-
-	for( reg = PCI_BASE_ADDRESS_0, i=0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++ ) {
-    
-		/* MPIC already done */
-		if (dev->vendor == PCI_VENDOR_ID_IBM &&
-		    dev->device == PCI_DEVICE_ID_IBM_MPIC)
-			return;
-
-		gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 0xffffffff );
-		gemini_pcibios_read_config_dword( bus->number, dev->devfn, reg, &base );
-		if (!base) {
-			dev->resource[i].start = 0;
-			continue;
-		}
-
-		if (base & PCI_BASE_ADDRESS_SPACE_IO) {
-			cmd |= PCI_COMMAND_IO;
-			base &= PCI_BASE_ADDRESS_IO_MASK;
-			mask = (~base << 1) | 0x1;
-			size = (mask & base) & 0xffffffff;
-			alignto = MAX(0x400, size);
-			base = ALIGN(io_base, alignto);
-			io_base = base + size;
-			gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 
-							   ((pci_io_base + base) & 0x00ffffff) | 0x1);
-			dev->resource[i].start = (pci_io_base + base) | 0x1;
-		}
-
-		else {
-			cmd |= PCI_COMMAND_MEMORY;
-			type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
-			mask = (~base << 1) | 0x1;
-			size = (mask & base) & 0xffffffff;
-			switch( type ) {
-
-			case PCI_BASE_ADDRESS_MEM_TYPE_32:
-				break;
-			case PCI_BASE_ADDRESS_MEM_TYPE_64:
-				printk("Warning: Ignoring 64-bit device; slot %d, function %d.\n",
-				       PCI_SLOT( dev->devfn ), PCI_FUNC( dev->devfn ));
-				reg += 4;
-				continue;
+	struct pci_dev *dev;
+	
+	pci_for_each_dev(dev) {
+		for(i = 0; i < 6; i++) {
+			if (dev->resource[i].flags & IORESOURCE_IO) {
+				dev->resource[i].start |= (0xfe << 24);
+				dev->resource[i].end |= (0xfe << 24);
 			}
-
-			alignto = MAX(0x1000, size);
-			base = ALIGN(mem_base, alignto);
-			mem_base = base + size;
-			gemini_pcibios_write_config_dword( bus->number, dev->devfn,
-							   reg, (pci_mem_base + base));
-			dev->resource[i].start = pci_mem_base + base;
 		}
 	}
-
-	if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
-		cmd |= PCI_COMMAND_IO;
-
-	gemini_pcibios_write_config_word( bus->number, dev->devfn, PCI_COMMAND,
-					  (cmd|PCI_COMMAND_MASTER));
-}
-
-__init void layout_bus( struct pci_bus *bus )
-{
-	struct pci_dev *dev;
-
-	io_base = ALIGN(io_base, 4*KB);
-	mem_base = ALIGN(mem_base, 4*KB);
-
-	pci_for_each_dev(dev)
-	{
-		if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) ||
-		    ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER))
-			layout_dev( dev );
-	}
-}
-
-void __init gemini_pcibios_fixup(void)
-{
-	unsigned long orig_mem_base, orig_io_base;
-	
-	orig_mem_base = pci_mem_base;
-	orig_io_base = pci_io_base;
-
-	pci_mem_base = orig_mem_base;
-	pci_io_base = orig_io_base;
 }
 
 decl_config_access_method(gemini);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/gemini_setup.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/gemini_setup.c	Tue May  2 13:05:39 2000
@@ -35,15 +35,14 @@
 #include "open_pic.h"
 
 void gemini_setup_pci_ptrs(void);
+static int gemini_get_clock_speed(void);
+extern void gemini_pcibios_fixup(void);
 
-static unsigned char gemini_switch_map = 0;
 static char *gemini_board_families[] = {
-	"VGM", "VSS", "KGM", "VGR", "KSS"
-};
-
-static char *gemini_memtypes[] = {
-	"EDO DRAM, 60nS", "SDRAM, 15nS, CL=2", "SDRAM, 15nS, CL=2 with ECC"
+  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
 };
+static int gemini_board_count = sizeof(gemini_board_families) /
+                                 sizeof(gemini_board_families[0]);
 
 static unsigned int cpu_7xx[16] = {
 	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
@@ -66,14 +65,14 @@
 int
 gemini_get_cpuinfo(char *buffer)
 {
-	int i, len;
+	int len;
 	unsigned char reg, rev;
 	char *family;
 	unsigned int type;
 
 	reg = readb(GEMINI_FEAT);
 	family = gemini_board_families[((reg>>4) & 0xf)];
-	if (((reg>>4) & 0xf) > 2)
+	if (((reg>>4) & 0xf) > gemini_board_count)
 		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
 
 	reg = readb(GEMINI_BREV);
@@ -85,18 +84,17 @@
 	len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
 		       family, type, (rev + 'A'), (reg & 0xf));
 
-	len += sprintf( buffer+len, "vendor\t\t: %s\n", 
-			(_get_PVR() & (1<<15)) ? "IBM" : "Motorola");
+	len = sprintf(buffer, "board\t\t: Gemini %s", family);
+	if (type > 9)
+		len += sprintf(buffer+len, "%c", (type - 10) + 'A');
+	else
+		len += sprintf(buffer+len, "%d", type);
 
-	reg = readb(GEMINI_MEMCFG);
-	len += sprintf( buffer+len, "memory type\t: %s\n", 
-			gemini_memtypes[(reg & 0xc0)>>6]);
-	len += sprintf( buffer+len, "switches on\t: ");
-	for( i=0; i < 8; i++ ) {
-		if ( gemini_switch_map & (1<<i))
-			len += sprintf(buffer+len, "%d ", i);
-	}
-	len += sprintf(buffer+len, "\n");
+	len += sprintf(buffer+len, ", rev %c, eco %d\n",
+		       (rev + 'A'), (reg & 0xf));
+
+	len += sprintf(buffer+len, "clock\t\t: %dMhz\n", 
+		       gemini_get_clock_speed());
 
 	return len;
 }
@@ -116,11 +114,16 @@
 
 void __init gemini_openpic_init(void)
 {
+
+	OpenPIC = (volatile struct OpenPIC *)
+		grackle_read(0x80005800 + 0x10);
+#if 0	
 	grackle_write(GEMINI_MPIC_PCI_CFG + PCI_BASE_ADDRESS_0, 
 		      GEMINI_MPIC_ADDR);
 	grackle_write(GEMINI_MPIC_PCI_CFG + PCI_COMMAND, PCI_COMMAND_MEMORY);
 
 	OpenPIC = (volatile struct OpenPIC *) GEMINI_MPIC_ADDR;
+#endif
 	OpenPIC_InitSenses = gemini_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
 
@@ -148,7 +151,6 @@
 
 void __init gemini_setup_arch(void)
 {
-	unsigned int cpu;
 	extern char cmd_line[];
 
 
@@ -165,29 +167,8 @@
 	/* nothing but serial consoles... */  
 	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
 
-
-	/* The user switches on the front panel can be used as follows:
-
-	   Switch 0 - adds "debug" to the command line for verbose boot info,
-	   Switch 7 - boots in single-user mode 
-
-	*/
-
-	gemini_switch_map = readb( GEMINI_USWITCH );
-  
-	if ( gemini_switch_map & (1<<GEMINI_SWITCH_VERBOSE))
-		sprintf(cmd_line, "%s debug", cmd_line);
-
-	if ( gemini_switch_map & (1<<GEMINI_SWITCH_SINGLE_USER))
-		sprintf(cmd_line, "%s single", cmd_line);
-
 	printk("Boot arguments: %s\n", cmd_line);
 
-	/* mutter some kind words about who made the CPU */
-	cpu = _get_PVR();
-	printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" :
-	       "Motorola", (cpu & 0xffff));
-
 	ppc_md.heartbeat = gemini_heartbeat;
 	ppc_md.heartbeat_reset = HZ/8;
 	ppc_md.heartbeat_count = 1;
@@ -202,19 +183,17 @@
 int
 gemini_get_clock_speed(void)
 {
-	unsigned long hid1;
+	unsigned long hid1, pvr = _get_PVR();
 	int clock;
-	unsigned char reg;
-  
-	hid1 = _get_HID1();
-	if ((_get_PVR()>>16) == 8)
+
+	hid1 = (_get_HID1() >> 28) & 0xf;
+	if (PVR_VER(pvr) == 8 ||
+	    PVR_VER(pvr) == 12)
 		hid1 = cpu_7xx[hid1];
 	else
 		hid1 = cpu_6xx[hid1];
 
-	reg = readb(GEMINI_BSTAT) & 0xc0;
-
-	switch( reg >> 2 ) {
+	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
 
 	case 0:
 	default:
@@ -226,7 +205,7 @@
 		break;
   
 	case 2:
-		clock = (hid1*50)/3;
+		clock = (hid1*50);
 		break;
 	}
 
@@ -242,83 +221,72 @@
 
 void __init gemini_init_l2(void)
 {
-	unsigned char reg;
-	unsigned long cache;
-	int speed;
+        unsigned char reg, brev, fam, creg;
+        unsigned long cache;
+        unsigned long pvr = _get_PVR();
+
+        reg = readb(GEMINI_L2CFG);
+        brev = readb(GEMINI_BREV);
+        fam = readb(GEMINI_FEAT);
+
+        switch(PVR_VER(pvr)) {
+
+        case 8:
+                if (reg & 0xc0)
+                        cache = (((reg >> 6) & 0x3) << 28);
+                else
+                        cache = 0x3 << 28;
 
-	reg = readb(GEMINI_L2CFG);
-
-	/* 750's L2 initializes differently from a 604's.  Also note that a Grackle
-	   bug will hang a dual-604 board, so make sure that doesn't happen by not
-	   turning on the L2 */
-	if ( _get_PVR() >> 16 != 8 ) {
-     
-		/* check for dual cpus and cry sadly about the loss of an L2... */
-		if ((( readb(GEMINI_CPUSTAT) & 0x0c ) >> 2) != 1) 
-			printk("Sorry. Your dual-604 does not allow the L2 to be enabled due "
-			       "to a Grackle bug.\n");
-		else if ( reg & GEMINI_L2_SIZE_MASK ) {
-			printk("Enabling 604 L2 cache: %dKb\n", 
-			       (128<<((reg & GEMINI_L2_SIZE_MASK)>>6)));
-			writeb( 1, GEMINI_L2CFG );
-		}
-	}
-
-	/* do a 750 */
-	else {
-		/* Synergy's first round of 750 boards had the L2 size stuff into the
-		   board register above.  If it's there, it's used; if not, the
-		   standard default is 1Mb.  The L2 type, I'm told, is "most likely
-		   probably always going to be late-write".  --Dan */
-
-		if (reg & 0xc0) {
-			printk("Enabling 750 L2 cache: %dKb\n", 
-			       (128 << ((reg & 0xc0)>>6)));
-			/* take the size given */
-			cache = (((reg>>6) & 0x3)<<28);
-		}
-		else
-		{
-			printk("Enabling 750 L2 cache: 1M\n");
-			/* default of 1Mb */
-			cache = 0x3<<28;
-		}
- 
-		reg &= 0x3;
-
-		/* a cache ratio of 1:1 and CPU clock speeds in excess of 300Mhz are bad
-		   things.  If found, tune it down to 1:1.5.  -- Dan */
-		if (!reg) {
-
-printk("3\n");
-			speed = gemini_get_clock_speed();
-   
-			if (speed >= 300) {
-				printk("Warning:  L2 ratio is 1:1 on a %dMhz processor.  Dropping to 1:1.5.\n",
-				       speed );
-				printk("Contact Synergy Microsystems for an ECO to fix this problem\n");
-				reg = 0x1;
-			}
-		}
-
-		/* standard stuff */
-		cache |= ((1<<reg)<<25);
 #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
-		   write-through.  This is fixed in IBM's 3.1 rev (I'm told), but
-		   for now, always make 2.x versions use L2 write-through. --Dan */
-		if (((_get_PVR()>>8) & 0xf) <= 2)
-		{
-			cache |= L2CR_L2WT;
-			printk("L2 cache: Enabling Write-Through due to 750 Errata.\n");
-		}
-#endif
-		cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE;
-		_set_L2CR(0);
-		_set_L2CR(cache|L2CR_L2I|L2CR_L2E);
+                /* Pre-3.0 processor revs had snooping errata.  Leave
+                   their L2's disabled with SMP. -- Dan */
+                if (PVR_CFG(pvr) < 3) {
+                        printk("Pre-3.0 750; L2 left disabled!\n");
+                        return;
+                }
+#endif /* CONFIG_SMP */
+
+                /* Special case: VGM5-B's came before L2 ratios were set on
+                   the board.  Processor speed shouldn't be too high, so
+                   set L2 ratio to 1:1.5.  */
+                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
+                        reg |= 1;
+
+                /* determine best cache ratio based upon what the board
+                   tells us (which sometimes _may_ not be true) and
+                   the processor speed. */
+                else {
+                        if (gemini_get_clock_speed() > 250)
+                                reg = 2;
+                }
+                break;
+        case 12:
+	{
+		static unsigned long l2_size_val = 0;
+		
+		if (!l2_size_val)
+			l2_size_val = _get_L2CR();
+		cache = l2_size_val;
+                break;
 	}
+        case 4:
+        case 9:
+                creg = readb(GEMINI_CPUSTAT);
+                if (((creg & 0xc) >> 2) != 1)
+                        printk("Dual-604 boards don't support the use of L2\n");
+                else
+                        writeb(1, GEMINI_L2CFG);
+                return;
+        default:
+                printk("Unknown processor; L2 left disabled\n");
+                return;
+        }
+
+        cache |= ((1<<reg) << 25);
+        cache |= (L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE);
+        _set_L2CR(0);
+        _set_L2CR(cache | L2CR_L2I | L2CR_L2E);
+
 }
 
 void
@@ -540,8 +508,11 @@
 void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
 			unsigned long r6, unsigned long r7)
 {
+	int i;
 	int chrp_get_irq( struct pt_regs * );
-	void layout_bus( struct pci_bus * );
+
+	for(i = 0; i < GEMINI_LEDS; i++)
+		gemini_led_off(i);
  
 	gemini_setup_pci_ptrs();
 
@@ -585,5 +556,5 @@
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate = NULL;
 #endif
-	ppc_md.pcibios_fixup_bus = layout_bus;
+	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.99-pre6/linux/arch/ppc/kernel/head.S	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/head.S	Tue May  2 13:05:39 2000
@@ -1274,6 +1274,7 @@
 	ori	r3,r3,start_secondary@l
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
+	SYNC
 	rfi
 #endif /* CONFIG_SMP */
 
@@ -1436,7 +1437,7 @@
 	tlbsync			/* ... on all CPUs */
 	sync
 #endif
-	
+
 	bl	load_up_mmu
 
 /* Set up for using our exception vectors */
@@ -1543,6 +1544,28 @@
 	mtspr	DBAT1U,r3
 	mtspr	IBAT1U,r3
 	blr
+#endif
+
+#ifdef CONFIG_8260
+/* Jump into the system reset for the rom.
+ * We first disable the MMU, and then jump to the ROM reset address.
+ *
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
+ */
+       .globl  m8260_gorom
+m8260_gorom:
+       li      r5,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+       lis     r6,2f@h
+       addis   r6,r6,-KERNELBASE@h
+       ori     r6,r6,2f@l
+       mtspr   SRR0,r6
+       mtspr   SRR1,r5
+       rfi
+2:
+       mtlr    r4
+       blr
 #endif
 	
 /*
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.3.99-pre6/linux/arch/ppc/kernel/head_8xx.S	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/head_8xx.S	Tue May  2 13:05:39 2000
@@ -136,7 +136,7 @@
 	mtspr	DC_CST, r8
 	lis	r8, IDC_ENABLE@h
 	mtspr	IC_CST, r8
-#if 0
+#ifdef CONFIG_8xx_COPYBACK
 	mtspr	DC_CST, r8
 #else
 	/* For a debug option, I left this here to easily enable
@@ -356,15 +356,26 @@
  * only perform the attribute functions.
  */
 InstructionTLBMiss:
+#ifdef CONFIG_8xx_CPU6
+	stw	r3, 8(r0)
+	li	r3, 0x3f80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	M_TW, r20	/* Save a couple of working registers */
 	mfcr	r20
 	stw	r20, 0(r0)
 	stw	r21, 4(r0)
 	mfspr	r20, SRR0	/* Get effective address of fault */
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3780
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_EPN, r20	/* Have to use MD_EPN for walk, MI_EPN can't */
 	mfspr	r20, M_TWB	/* Get level 1 table entry address */
 	lwz	r21, 0(r20)	/* Get the level 1 entry */
-	rlwinm.	r20, r21,0,0,20	/* Extract page descriptor page address */
+	rlwinm.	r20, r21,0,0,19	/* Extract page descriptor page address */
 	beq	2f		/* If zero, don't try to find a pte */
 
 	/* We have a pte table, so load the MI_TWC with the attributes
@@ -372,88 +383,131 @@
 	 */
 	tophys(r21,r21)
 	ori	r21,r21,1		/* Set valid bit */
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x2b80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MI_TWC, r21	/* Set page attributes */
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3b80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_TWC, r21	/* Load pte table base address */
 	mfspr	r21, MD_TWC	/* ....and get the pte address */
-	lwz	r21, 0(r21)	/* Get the pte */
+	lwz	r20, 0(r21)	/* Get the pte */
+#if 0
+	ori	r20, r20, _PAGE_ACCESSED
+	stw	r20, 0(r21)
+#endif
 
 	/* Set four subpage valid bits (24, 25, 26, and 27).
-	 * Since we currently run MI_CTR.PPCS = 0, the manual says,
-	 *	"If the page size is larger than 4k byte, then all the
-	 *	 4 bits should have the same value."
-	 * I don't really know what to do if the page size is 4k Bytes,
-	 * but I know setting them all to 0 does not work, and setting them
-	 * all to 1 does, so that is the way it is right now.
-	 * BTW, these four bits map to the software only bits in the
-	 * linux page table.  I used to turn them all of, but now just
-	 * set them all for the hardware.
-	li	r20, 0x00f0
-	andc	r20, r21, r20
-	ori	r20, r20, 0x0080
+	 * Clear bit 28 (which should be in the PTE, but we do this anyway).
 	 */
-	ori	r20, r21, 0x00f0
-
+	li	r21, 0x00f0
+	rlwimi	r20, r21, 0, 24, 28
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x2d80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MI_RPN, r20	/* Update TLB entry */
 
 	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	rfi
 
 2:	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	b	InstructionAccess
 
 	. = 0x1200
 DataStoreTLBMiss:
+#ifdef CONFIG_8xx_CPU6
+	stw	r3, 8(r0)
+	li	r3, 0x3f80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	M_TW, r20	/* Save a couple of working registers */
 	mfcr	r20
 	stw	r20, 0(r0)
 	stw	r21, 4(r0)
 	mfspr	r20, M_TWB	/* Get level 1 table entry address */
 	lwz	r21, 0(r20)	/* Get the level 1 entry */
-	rlwinm.	r20, r21,0,0,20	/* Extract page descriptor page address */
+	rlwinm.	r20, r21,0,0,19	/* Extract page descriptor page address */
 	beq	2f		/* If zero, don't try to find a pte */
 
 	/* We have a pte table, so load fetch the pte from the table.
 	 */
 	tophys(r21, r21)
 	ori	r21, r21, 1	/* Set valid bit in physical L2 page */
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3b80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_TWC, r21	/* Load pte table base address */
-	mfspr	r21, MD_TWC	/* ....and get the pte address */
-	lwz	r21, 0(r21)	/* Get the pte */
+	mfspr	r20, MD_TWC	/* ....and get the pte address */
+	lwz	r20, 0(r20)	/* Get the pte */
 
-	/* Set four subpage valid bits (24, 25, 26, and 27).
-	 * Since we currently run MD_CTR.PPCS = 0, the manual says,
-	 *	"If the page size is larger than 4k byte, then all the
-	 *	 4 bits should have the same value."
-	 * I don't really know what to do if the page size is 4k Bytes,
-	 * but I know setting them all to 0 does not work, and setting them
-	 * all to 1 does, so that is the way it is right now.
-	 * BTW, these four bits map to the software only bits in the
-	 * linux page table.  I used to turn them all of, but now just
-	 * set them all for the hardware.
-	li	r20, 0x00f0
-	andc	r20, r21, r20
-	ori	r20, r20, 0x0080
+	/* Insert the Guarded flag into the TWC from the Linux PTE.
+	 * It is bit 27 of both the Linux PTE and the TWC (at least
+	 * I got that right :-).  It will be better when we can put
+	 * this into the Linux pgd/pmd and load it in the operation
+	 * above.
 	 */
-	ori	r20, r21, 0x00f0
+	rlwimi	r21, r20, 0, 27, 27
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3b80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
+	mtspr	MD_TWC, r21
 
+	/* Set four subpage valid bits (24, 25, 26, and 27).
+	 * Clear bit 28 (which should be in the PTE, but we do this anyway).
+	 */
+#if 0
+	ori	r20, r20, 0x00f0
+#else
+	li	r21, 0x00f0
+	rlwimi	r20, r21, 0, 24, 28
+#endif
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3d80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_RPN, r20	/* Update TLB entry */
 
 	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	rfi
 
 2:	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	b	DataAccess
 
 /* This is an instruction TLB error on the MPC8xx.  This could be due
@@ -474,6 +528,12 @@
  */
 	. = 0x1400
 DataTLBError:
+#ifdef CONFIG_8xx_CPU6
+	stw	r3, 8(r0)
+	li	r3, 0x3f80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	M_TW, r20	/* Save a couple of working registers */
 	mfcr	r20
 	stw	r20, 0(r0)
@@ -487,52 +547,59 @@
 
 	mfspr	r20, M_TWB	/* Get level 1 table entry address */
 	lwz	r21, 0(r20)	/* Get the level 1 entry */
-	rlwinm.	r20, r21,0,0,20	/* Extract page descriptor page address */
+	rlwinm.	r20, r21,0,0,19	/* Extract page descriptor page address */
 	beq	2f		/* If zero, bail */
 
 	/* We have a pte table, so fetch the pte from the table.
 	 */
 	tophys(r21, r21)
 	ori	r21, r21, 1		/* Set valid bit in physical L2 page */
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3b80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_TWC, r21		/* Load pte table base address */
 	mfspr	r21, MD_TWC		/* ....and get the pte address */
-	lwz	r21, 0(r21)		/* Get the pte */
+	lwz	r20, 0(r21)		/* Get the pte */
 
-	andi.	r20, r21, _PAGE_RW	/* Is it writeable? */
+	andi.	r21, r20, _PAGE_RW	/* Is it writeable? */
 	beq	2f			/* Bail out if not */
 
-	ori	r21, r21, _PAGE_DIRTY	/* Update changed bit */
-	mfspr	r20, MD_TWC		/* Get pte address again */
-	stw	r21, 0(r20)		/* and update pte in table */
+	/* Update 'changed', among others.
+	*/
+	ori	r20, r20, _PAGE_DIRTY|_PAGE_HWWRITE|_PAGE_ACCESSED
+	mfspr	r21, MD_TWC		/* Get pte address again */
+	stw	r20, 0(r21)		/* and update pte in table */
 
 	/* Set four subpage valid bits (24, 25, 26, and 27).
-	 * Since we currently run MD_CTR.PPCS = 0, the manual says,
-	 *	"If the page size is larger than 4k byte, then all the
-	 *	 4 bits should have the same value."
-	 * I don't really know what to do if the page size is 4k Bytes,
-	 * but I know setting them all to 0 does not work, and setting them
-	 * all to 1 does, so that is the way it is right now.
-	 * BTW, these four bits map to the software only bits in the
-	 * linux page table.  I used to turn them all of, but now just
-	 * set them all for the hardware.
-	li	r20, 0x00f0
-	andc	r20, r21, r20
-	ori	r20, r20, 0x0080
+	 * Clear bit 28 (which should be in the PTE, but we do this anyway).
 	 */
-	ori	r20, r21, 0x00f0
-
+	li	r21, 0x00f0
+	rlwimi	r20, r21, 0, 24, 28
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3d80
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
 	mtspr	MD_RPN, r20	/* Update TLB entry */
 
 	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	rfi
 2:
 	mfspr	r20, M_TW	/* Restore registers */
 	lwz	r21, 0(r0)
 	mtcr	r21
 	lwz	r21, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
 	b	DataAccess
 
 	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
@@ -542,6 +609,7 @@
 	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
 	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
 	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+
 /* On the MPC8xx, these next four traps are used for development
  * support of breakpoints and such.  Someday I will get around to
  * using them.
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/irq.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/irq.c	Tue May  2 13:05:39 2000
@@ -117,9 +117,9 @@
 	kfree(ptr);
 }
 
-#ifdef CONFIG_8xx
+#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
 /* Name change so we can catch standard drivers that potentially mess up
- * the internal interrupt controller on 8xx and 82xx.  Just bear with me,
+ * the internal interrupt controller on 8xx and 8260.  Just bear with me,
  * I don't like this either and I am searching a better solution.  For
  * now, this is what I need. -- Dan
  */
@@ -194,10 +194,10 @@
 #else
 void free_irq(unsigned int irq, void *dev_id)
 {
-#ifndef CONFIG_8xx
-	request_irq(irq, NULL, 0, NULL, dev_id);
-#else
+#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
 	request_8xxirq(irq, NULL, 0, NULL, dev_id);
+#else
+	request_irq(irq, NULL, 0, NULL, dev_id);
 #endif
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/m8260_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/m8260_setup.c	Tue May  2 13:05:39 2000
@@ -0,0 +1,303 @@
+/*
+ * $Id: m8xx_setup.c,v 1.4 1999/09/18 18:40:36 dmalek Exp $
+ *
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ *  Further modified for generic 8xx and 8260 by Dan.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/mpc8260.h>
+#include <asm/immap_8260.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "ppc8260_pic.h"
+
+static int m8260_set_rtc_time(unsigned long time);
+unsigned long m8260_get_rtc_time(void);
+void m8260_calibrate_decr(void);
+
+#if 0
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+#endif
+
+extern unsigned long loops_per_sec;
+
+unsigned char __res[sizeof(bd_t)];
+unsigned long empty_zero_page[1024];
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;	/* starting block # of image */
+#endif
+
+extern char saved_command_line[256];
+
+extern unsigned long find_available_memory(void);
+extern void m8260_cpm_reset(void);
+
+void __init adbdev_init(void)
+{
+}
+
+void __init
+m8260_setup_arch(void)
+{
+	extern char cmd_line[];
+	
+	printk("Boot arguments: %s\n", cmd_line);
+
+	/* Reset the Communication Processor Module.
+	*/
+	m8260_cpm_reset();
+}
+
+void
+abort(void)
+{
+#ifdef CONFIG_XMON
+	extern void xmon(void *);
+	xmon(0);
+#endif
+	machine_restart(NULL);
+}
+
+/* The decrementer counts at the system (internal) clock frequency
+ * divided by four.
+ */
+void __init m8260_calibrate_decr(void)
+{
+	bd_t	*binfo = (bd_t *)__res;
+	int freq, divisor;
+
+	freq = (binfo->bi_intfreq * 1000000);
+        divisor = 16;
+        decrementer_count = freq / HZ / divisor;
+        count_period_num = divisor;
+        count_period_den = freq / 1000000;
+}
+
+/* The 8260 has an internal 1-second timer update register that
+ * we should use for this purpose.
+ */
+static uint	rtc_time;
+static int
+m8260_set_rtc_time(unsigned long time)
+{
+	rtc_time = time;
+	return(0);
+}
+
+unsigned long __init
+m8260_get_rtc_time(void)
+{
+
+	/* Get time from the RTC.
+	*/
+	return((unsigned long)rtc_time);
+}
+
+void
+m8260_restart(char *cmd)
+{
+	extern void m8260_gorom(bd_t *bi, uint addr);
+
+	m8260_gorom(NULL, 0xff000100);
+}
+
+void
+m8260_power_off(void)
+{
+   m8260_restart(NULL);
+}
+
+void
+m8260_halt(void)
+{
+   m8260_restart(NULL);
+}
+
+
+int m8260_setup_residual(char *buffer)
+{
+        int     len = 0;
+	bd_t	*bp;
+
+	bp = (bd_t *)__res;
+			
+	len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+		       "bus clock\t: %dMHz\n",
+		       bp->bi_intfreq /*/ 1000000*/,
+		       bp->bi_busfreq /*/ 1000000*/);
+
+	return len;
+}
+
+/* Initialize the internal interrupt controller.  The number of
+ * interrupts supported can vary with the processor type, and the
+ * 8260 family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+void __init
+m8260_init_IRQ(void)
+{
+	int i;
+	void cpm_interrupt_init(void);
+
+#if 0
+        ppc8260_pic.irq_offset = 0;
+#endif
+        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
+                irq_desc[i].handler = &ppc8260_pic;
+	
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	immr->im_intctl.ic_sicr = 0;
+	immr->im_intctl.ic_siprr = 0x05309770;
+	immr->im_intctl.ic_scprrh = 0x05309770;
+	immr->im_intctl.ic_scprrl = 0x05309770;
+
+}
+
+
+void __init
+m8260_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	 unsigned long r6, unsigned long r7)
+{
+
+	if ( r3 )
+		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+	
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 )
+	{
+		
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = m8260_setup_arch;
+	ppc_md.setup_residual = m8260_setup_residual;
+	ppc_md.get_cpuinfo    = NULL;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = m8260_init_IRQ;
+	ppc_md.get_irq	      = m8260_get_irq;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = m8260_restart;
+	ppc_md.power_off      = m8260_power_off;
+	ppc_md.halt           = m8260_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = m8260_set_rtc_time;
+	ppc_md.get_rtc_time   = m8260_get_rtc_time;
+	ppc_md.calibrate_decr = m8260_calibrate_decr;
+
+#if 0
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_pretranslate  = pckbd_pretranslate;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#else
+	ppc_md.kbd_setkeycode    = NULL;
+	ppc_md.kbd_getkeycode    = NULL;
+	ppc_md.kbd_translate     = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds          = NULL;
+	ppc_md.kbd_init_hw       = NULL;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = NULL;
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = m8xx_ide_insw;
+        ppc_ide_md.outsw = m8xx_ide_outsw;
+        ppc_ide_md.default_irq = m8xx_ide_default_irq;
+        ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
+        ppc_ide_md.check_region = m8xx_ide_check_region;
+        ppc_ide_md.request_region = m8xx_ide_request_region;
+        ppc_ide_md.release_region = m8xx_ide_release_region;
+        ppc_ide_md.fix_driveid = m8xx_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
+        ppc_ide_md.ide_request_irq = m8xx_ide_request_irq;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
+}
+
+void
+prom_init(uint r3, uint r4, uint r5, uint r6)
+{
+	/* Nothing to do now, but we are called immediatedly upon
+	 * kernel start up with MMU disabled, so if there is
+	 * anything we need to do......
+	 */
+}
+
+/* Mainly for ksyms.
+*/
+int
+request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flag, const char *naem, void *dev)
+{
+	panic("request IRQ\n");
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/m8xx_setup.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/kernel/m8xx_setup.c	Tue May  2 13:05:39 2000
@@ -130,7 +130,6 @@
 abort(void)
 {
 #ifdef CONFIG_XMON
-	extern void xmon(void *);
 	xmon(0);
 #endif
 	machine_restart(NULL);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.99-pre6/linux/arch/ppc/kernel/misc.S	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/misc.S	Tue May  2 13:05:39 2000
@@ -18,6 +18,7 @@
 #include <asm/errno.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/cache.h>
 #include "ppc_asm.h"
 
 #if defined(CONFIG_4xx) || defined(CONFIG_8xx)
@@ -165,6 +166,11 @@
  * This is a no-op on the 601.
  */
 _GLOBAL(flush_instruction_cache)
+#ifdef CONFIG_8xx
+	isync
+	lis	r5, IDC_INVALL@h
+	mtspr	IC_CST, r5
+#else
 	mfspr	r3,PVR
 	rlwinm	r3,r3,16,16,31
 	cmpi	0,r3,1
@@ -173,6 +179,7 @@
 	mfspr	r3,HID0
 	ori	r3,r3,HID0_ICFI
 	mtspr	HID0,r3
+#endif /* CONFIG_8xx */
 	SYNC
 	blr
 
@@ -241,8 +248,7 @@
 	rlwinm	r5,r5,16,16,31
 	cmpi	0,r5,1
 	beqlr				/* for 601, do nothing */
-	li	r4,0x0FFF
-	andc	r3,r3,r4		/* Get page base address */
+	rlwinm	r3,r3,0,0,19		/* Get page base address */
 	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
@@ -373,6 +379,7 @@
  * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
  * void atomic_set_mask(atomic_t mask, atomic_t *addr);
  */
+#if 0 /* now inline - paulus */
 _GLOBAL(atomic_add)
 10:	lwarx	r5,0,r4		/* Fetch old value & reserve */
 	add	r5,r5,r3	/* Perform 'add' operation */
@@ -423,11 +430,10 @@
 	subi	r5,r5,1		/* Perform 'add' operation */
 	stwcx.	r5,0,r3		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	cmpi	0,r5,0		/* Return 'true' IFF 0 */
-	li	r3,1
-	beqlr
-	li	r3,0
+	cntlzw	r3,r5
+	srwi	r3,r3,5		
 	blr
+#endif /* 0 */
 _GLOBAL(atomic_clear_mask)
 10:	lwarx	r5,0,r4
 	andc	r5,r5,r3
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/pmac_nvram.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pmac_nvram.c	Tue May  2 13:05:39 2000
@@ -7,14 +7,18 @@
 #include <linux/nvram.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
+#include <asm/nvram.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 
+#undef DEBUG
+
 /*
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
  */
@@ -23,9 +27,191 @@
 static volatile unsigned char *nvram_data;
 static int nvram_mult, is_core_99;
 static char* nvram_image;
+static int core99_bank = 0;
+
+extern int pmac_newworld;
  
 #define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
  
+#define CORE99_SIGNATURE	0x5a
+#define CORE99_ADLER_START	0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE	0x80
+#define CORE99_FLASH_STATUS_ERR		0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
+#define CORE99_FLASH_CMD_RESET		0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8		signature;
+  u8		cksum;
+  u16		len;
+  char          name[12];
+  u8		data[0];
+};
+
+struct core99_header {
+  struct chrp_header	hdr;
+  u32			adler;
+  u32			generation;
+  u32			reserved[2];
+};
+
+static int nvram_partitions[3];
+
+static u8
+chrp_checksum(struct chrp_header* hdr)
+{
+	u8 *ptr;
+	u16 sum = hdr->signature;
+	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+		sum += *ptr;
+	while (sum > 0xFF)
+		sum = (sum & 0xFF) + (sum>>8);
+	return sum;
+}
+
+static u32
+core99_calc_adler(u8 *buffer)
+{
+	int cnt;
+	u32 low, high;
+
+   	buffer += CORE99_ADLER_START;
+	low = 1;
+	high = 0;
+	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+		if ((cnt % 5000) == 0) {
+			high  %= 65521UL;
+			high %= 65521UL;
+		}
+		low += buffer[cnt];
+		high += low;
+	}
+	low  %= 65521UL;
+	high %= 65521UL;
+  
+	return (high << 16) | low;
+}
+
+static u32
+core99_check(u8* datas)
+{
+	struct core99_header* hdr99 = (struct core99_header*)datas;
+
+	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+		printk("Invalid signature\n");
+#endif		
+		return 0;
+	}
+	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+		printk("Invalid checksum\n");
+#endif
+		return 0;
+	}
+	if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+		printk("Invalid adler\n");
+#endif
+		return 0;
+	}
+	return hdr99->generation;
+}
+
+static int
+core99_erase_bank(int bank)
+{
+	int stat, i;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+	do { stat = in_8(base); }
+	while(!(stat & CORE99_FLASH_STATUS_DONE));
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on erase !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk("nvram: flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int
+core99_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	for (i=0; i<NVRAM_SIZE; i++) {
+		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+		out_8(base+i, datas[i]);
+		do { stat = in_8(base); }
+		while(!(stat & CORE99_FLASH_STATUS_DONE));
+		if (stat & CORE99_FLASH_STATUS_ERR)
+			break;
+	}
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on write !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk("nvram: flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;	
+}
+
+static void
+lookup_partitions(void)
+{
+	u8 buffer[17];
+	int i, offset;
+	struct chrp_header* hdr;
+
+	if (pmac_newworld) {
+		nvram_partitions[pmac_nvram_OF] = -1;
+		nvram_partitions[pmac_nvram_XPRAM] = -1;
+		nvram_partitions[pmac_nvram_NR] = -1;
+		hdr = (struct chrp_header *)buffer;
+	
+		offset = 0;
+		do {
+			for (i=0;i<16;i++)
+				buffer[i] = nvram_read_byte(offset+i);
+			if (!strcmp(hdr->name, "common"))
+				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+			if (!strcmp(hdr->name, "APL,MacOS75")) {
+				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+			}
+			offset += (hdr->len * 0x10);
+		} while(offset < NVRAM_SIZE);
+	} else {
+		nvram_partitions[pmac_nvram_OF] = 0x1800;
+		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+		nvram_partitions[pmac_nvram_NR] = 0x1400;
+	}	
+#ifdef DEBUG
+	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif	
+}
+
 __init
 void pmac_nvram_init(void)
 {
@@ -40,17 +226,32 @@
 	}
 	nvram_naddrs = dp->n_addrs;
 	is_core_99 = device_is_compatible(dp, "nvram,flash");
-	if (is_core_99)
-	{
+	if (is_core_99) {
 		int i;
-		if (nvram_naddrs < 1)
+		u32 gen_bank0, gen_bank1;
+		
+		if (nvram_naddrs < 1) {
+			printk(KERN_ERR "nvram: no address\n");
 			return;
-		nvram_image = kmalloc(dp->addrs[0].size, GFP_KERNEL);
-		if (!nvram_image)
+		}
+		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+		if (!nvram_image) {
+			printk(KERN_ERR "nvram: can't allocate image\n");
 			return;
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		for (i=0; i<dp->addrs[0].size; i++)
-			nvram_image[i] = in_8(nvram_data + i);
+		}
+		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+		printk("nvram: Checking bank 0...\n");
+#endif
+		gen_bank0 = core99_check((u8 *)nvram_data);
+		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+		printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+		for (i=0; i<NVRAM_SIZE; i++)
+			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
 	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
 		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_mult = 1;
@@ -68,6 +269,33 @@
 	}
 }
 
+void
+pmac_nvram_update(void)
+{
+	struct core99_header* hdr99;
+	
+	if (!is_core_99 || !nvram_data || !nvram_image)
+		return;
+	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+		NVRAM_SIZE))
+		return;
+#ifdef DEBUG
+	printk("Updating nvram...\n");
+#endif
+	hdr99 = (struct core99_header*)nvram_image;
+	hdr99->generation++;
+	hdr99->hdr.signature = CORE99_SIGNATURE;
+	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+	hdr99->adler = core99_calc_adler(nvram_image);
+	core99_bank = core99_bank ? 0 : 1;
+	if (core99_erase_bank(core99_bank)) {
+		printk("nvram: Error erasing bank %d\n", core99_bank);
+		return;
+	}
+	if (core99_write_bank(core99_bank, nvram_image))
+		printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
 __openfirmware
 unsigned char nvram_read_byte(int addr)
 {
@@ -125,3 +353,33 @@
 	}
 	eieio();
 }
+
+int
+pmac_get_partition(int partition)
+{
+	return nvram_partitions[partition];
+}
+
+u8
+pmac_xpram_read(int xpaddr)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return 0;
+		
+	return nvram_read_byte(xpaddr + offset);
+}
+
+void
+pmac_xpram_write(int xpaddr, u8 data)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return;
+		
+	nvram_write_byte(xpaddr + offset, data);
+}
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/pmac_pci.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pmac_pci.c	Tue May  2 13:05:40 2000
@@ -525,7 +525,8 @@
 	       bp->io_base);
 }
 
-#define GRACKLE_STG_ENABLE 0x00000040
+#define GRACKLE_PICR1_STG		0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
 
 /* N.B. this is called before bridges is initialized, so we can't
    use grackle_pcibios_{read,write}_config_dword. */
@@ -535,11 +536,25 @@
 
 	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
 	val = in_le32((volatile unsigned int *)bp->cfg_data);
-	val = enable? (val | GRACKLE_STG_ENABLE): (val & ~GRACKLE_STG_ENABLE);
+	val = enable? (val | GRACKLE_PICR1_STG) :
+		(val & ~GRACKLE_PICR1_STG);
 	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
 	out_le32((volatile unsigned int *)bp->cfg_data, val);
 }
 
+static inline void grackle_set_loop_snoop(struct bridge_data *bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+		(val & ~GRACKLE_PICR1_LOOPSNOOP);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+
 void __init pmac_find_bridges(void)
 {
 	int bus;
@@ -620,7 +635,9 @@
 			bp->cfg_data = (volatile unsigned char *)
 				ioremap(0xfee00000, 0x1000);
                         bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
-#if 0 /* Disabled for now, HW problems */
+                        if (machine_is_compatible("AAPL,PowerBook1998"))
+                        	grackle_set_loop_snoop(bp, 1);
+#if 0 			/* Disabled for now, HW problems ??? */
 			grackle_set_stg(bp, 1);
 #endif
 		} else {
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/pmac_pic.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Tue May  2 13:05:40 2000
@@ -158,13 +158,13 @@
 {
 	int irq, bits;
 	
-	for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
 		int i = irq >> 5;
 		bits = ld_le32(&pmac_irq_hw[i]->flag)
 			| ppc_lost_interrupts[i];
 		if (bits == 0)
 			continue;
-		irq -= cntlzw(bits);
+		irq += __ilog2(bits);
 		break;
 	}
 	/* The previous version of this code allowed for this case, we
@@ -213,13 +213,13 @@
 	}
 	else
 	{
-		for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+		for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
 			int i = irq >> 5;
 			bits = ld_le32(&pmac_irq_hw[i]->flag)
 				| ppc_lost_interrupts[i];
 			if (bits == 0)
 				continue;
-			irq -= cntlzw(bits);
+			irq += __ilog2(bits);
 			break;
 		}
 	}
@@ -489,11 +489,9 @@
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
 	(void)in_le32(&pmac_irq_hw[0]->flag);
-        do {
-                /* make sure mask gets to controller before we
-                   return to user */
-                mb();
-        } while(in_le32(&pmac_irq_hw[0]->enable) != ppc_cached_irq_mask[0]);
+	/* make sure mask gets to controller before we return to caller */
+	mb();
+        (void)in_le32(&pmac_irq_hw[0]->enable);
 }
 
 void
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/pmac_setup.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/pmac_setup.c	Tue May  2 13:05:40 2000
@@ -100,6 +100,8 @@
 
 extern char saved_command_line[];
 
+extern int pmac_newworld;
+
 #define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
 
 extern void zs_kgdb_hook(int tty_num);
@@ -198,6 +200,11 @@
 		}
 	}
 	
+	/* Indicate newworld/oldworld */
+	len += sprintf(buffer+len, "pmac-generation\t: %s\n",
+		pmac_newworld ? "NewWorld" : "OldWorld");		
+	
+
 	return len;
 }
 
@@ -499,6 +506,8 @@
 	struct adb_request req;
 #endif /* CONFIG_ADB_CUDA */
 
+	pmac_nvram_update();
+	
 	switch (sys_ctrler) {
 #ifdef CONFIG_ADB_CUDA
 	case SYS_CTRLER_CUDA:
@@ -524,6 +533,8 @@
 	struct adb_request req;
 #endif /* CONFIG_ADB_CUDA */
 
+	pmac_nvram_update();
+	
 	switch (sys_ctrler) {
 #ifdef CONFIG_ADB_CUDA
 	case SYS_CTRLER_CUDA:
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc-stub.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/ppc-stub.c	Wed May  3 01:47:57 2000
@@ -99,6 +99,7 @@
  *
  ****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -123,6 +124,7 @@
 
 static int initialized = 0;
 static int kgdb_active = 0;
+static int kgdb_started = 0;
 static u_int fault_jmp_buf[100];
 static int kdebug;
 
@@ -342,7 +344,7 @@
 	flush_instruction_cache();
 }
 
-static inline int get_msr()
+static inline int get_msr(void)
 {
 	int msr;
 	asm volatile("mfmsr %0" : "=r" (msr):);
@@ -460,6 +462,9 @@
 	return SIGHUP;         /* default for things we don't know about */
 }
 
+#define PC_REGNUM 64
+#define SP_REGNUM 1
+
 /*
  * This function does all command processing for interfacing to gdb.
  */
@@ -481,6 +486,7 @@
 		return;
 	}
 	kgdb_active = 1;
+	kgdb_started = 1;
 
 #ifdef KGDB_DEBUG
 	printk("kgdb: entering handle_exception; trap [0x%x]\n",
@@ -501,9 +507,25 @@
 	sigval = computeSignal(regs->trap);
 	ptr = remcomOutBuffer;
 
+#if 0
 	*ptr++ = 'S';
 	*ptr++ = hexchars[sigval >> 4];
 	*ptr++ = hexchars[sigval & 0xf];
+#else
+	*ptr++ = 'T';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+	*ptr++ = hexchars[PC_REGNUM >> 4];
+	*ptr++ = hexchars[PC_REGNUM & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&regs->nip, ptr, 4);
+	*ptr++ = ';';
+	*ptr++ = hexchars[SP_REGNUM >> 4];
+	*ptr++ = hexchars[SP_REGNUM & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex(((char *)&regs) + SP_REGNUM*4, ptr, 4);
+	*ptr++ = ';';
+#endif
 
 	*ptr++ = 0;
 
@@ -639,6 +661,7 @@
 				} else {
 					strcpy(remcomOutBuffer, "E03");
 				}
+				flush_icache_range(addr, addr+length);
 			} else {
 				strcpy(remcomOutBuffer, "E02");
 			}
@@ -668,7 +691,9 @@
 		case 's':
 			kgdb_flush_cache_all();
 			regs->msr |= MSR_SE;
+#if 0
 			set_msr(msr | MSR_SE);
+#endif
 			unlock_kernel();
 			kgdb_active = 0;
 			return;
@@ -700,6 +725,37 @@
 	}
 
 	asm("	.globl breakinst
-	     breakinst: trap
+	     breakinst: .long 0x7d821008
             ");
 }
+
+/* Output string in GDB O-packet format if GDB has connected. If nothing
+   output, returns 0 (caller must then handle output). */
+int
+kgdb_output_string (const char* s, unsigned int count)
+{
+	char buffer[512];
+
+        if (!kgdb_started)
+            return 0;
+
+	count = (count <= (sizeof(buffer) / 2 - 2)) 
+		? count : (sizeof(buffer) / 2 - 2);
+
+	buffer[0] = 'O';
+	mem2hex (s, &buffer[1], count);
+	putpacket(buffer);
+
+        return 1;
+ }
+
+#ifndef CONFIG_8xx
+
+/* I don't know why other platforms don't need this.  The function for
+ * the 8xx is found in arch/ppc/8xx_io/uart.c.  -- Dan
+ */
+void
+kgdb_map_scc(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc8260_pic.c linux/arch/ppc/kernel/ppc8260_pic.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc8260_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8260_pic.c	Tue May  2 13:05:40 2000
@@ -0,0 +1,111 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/immap_8260.h>
+#include <asm/mpc8260.h>
+#include "ppc8260_pic.h"
+
+/* The 8260 internal interrupt controller.  It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+static	u_char	irq_to_siureg[] = {
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static	u_char	irq_to_siubit[] = {
+	31, 16, 17, 18, 19, 20, 21, 22,
+	23, 24, 25, 26, 27, 28, 29, 30,
+	29, 30, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 27, 28, 31,
+	 0,  1,  2,  3,  4,  5,  6,  7,
+	 8,  9, 10, 11, 12, 13, 14, 15,
+	15, 14, 13, 12, 11, 10,  9,  8,
+	 7,  6,  5,  4,  3,  2,  1,  0
+};
+
+static void m8260_mask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_unmask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_mask_and_ack(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr, *sipnr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	sipnr = &(immr->im_intctl.ic_sipnrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+	sipnr[word] = 1 << bit;
+}
+
+struct hw_interrupt_type ppc8260_pic = {
+	" 8260 SIU  ",
+	NULL,
+	NULL,
+	m8260_unmask_irq,
+	m8260_mask_irq,
+	m8260_mask_and_ack,
+	0
+};
+
+
+int
+m8260_get_irq(struct pt_regs *regs)
+{
+	int irq;
+        unsigned long bits;
+
+        /* For MPC8260, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = immr->im_intctl.ic_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8260_pic.irq_offset;
+#endif
+	return irq;
+}
+
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc8260_pic.h linux/arch/ppc/kernel/ppc8260_pic.h
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc8260_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8260_pic.h	Tue May  2 13:05:40 2000
@@ -0,0 +1,15 @@
+
+#ifndef _PPC_KERNEL_PPC8260_H
+#define _PPC_KERNEL_PPC8260_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type ppc8260_pic;
+
+void m8260_pic_init(void);
+void m8260_do_IRQ(struct pt_regs *regs,
+                 int            cpu,
+                 int            isfake);
+int m8260_get_irq(struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_PPC8260_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc8xx_pic.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Tue May  2 13:05:40 2000
@@ -8,7 +8,7 @@
 #include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
-/* The 8xx or 82xx internal interrupt controller.  It is usually
+/* The 8xx internal interrupt controller.  It is usually
  * the only interrupt controller.  Some boards, like the MBX and
  * Sandpoint have the 8259 as a secondary controller.  Depending
  * upon the processor type, the internal controller can have as
@@ -25,13 +25,8 @@
 	word = irq_nr >> 5;
 
 	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
-#ifdef CONFIG_82xx
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
-						ppc_cached_irq_mask[word];
-#else
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
 						ppc_cached_irq_mask[word];
-#endif
 }
 
 static void m8xx_unmask_irq(unsigned int irq_nr)
@@ -42,13 +37,8 @@
 	word = irq_nr >> 5;
 
 	ppc_cached_irq_mask[word] |= (1 << (31-bit));
-#ifdef CONFIG_82xx
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
-						ppc_cached_irq_mask[word];
-#else
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
 						ppc_cached_irq_mask[word];
-#endif
 }
 
 static void m8xx_mask_and_ack(unsigned int irq_nr)
@@ -59,15 +49,9 @@
 	word = irq_nr >> 5;
 
 	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
-#ifdef CONFIG_82xx
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
-						ppc_cached_irq_mask[word];
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend[word] = 1 << (31-bit);
-#else
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
 						ppc_cached_irq_mask[word];
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
-#endif
 }
 
 struct hw_interrupt_type ppc8xx_pic = {
@@ -129,7 +113,7 @@
 
 /* The MBX is the only 8xx board that uses the 8259.
 */
-#ifdef CONFIG_MBX
+#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
 void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
 	int bits, irq;
@@ -165,7 +149,7 @@
 	unsigned long irqflags, const char * devname, void *dev_id)
 {
 
-#ifdef CONFIG_MBX
+#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
 	irq += i8259_pic.irq_offset;
 	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc_htab.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/ppc_htab.c	Tue May  2 13:05:40 2000
@@ -502,7 +502,7 @@
 	#define TMPBUFLEN 256
 	char buf[TMPBUFLEN], *p;
 	static const char *sizestrings[4] = {
-		"unknown size", "256KB", "512KB", "1MB"
+		"2MB", "256KB", "512KB", "1MB"
 	};
 	static const char *clockstrings[8] = {
 		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/ppc_ksyms.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Tue May  2 13:05:40 2000
@@ -54,9 +54,10 @@
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
-asmlinkage long long __ashrdi3(long long, int);
-asmlinkage long long __lshrdi3(long long, int);
-asmlinkage int abs(int);
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int abs(int);
 
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
@@ -95,25 +96,12 @@
 #endif
 #endif
 
-EXPORT_SYMBOL(atomic_add);
-EXPORT_SYMBOL(atomic_sub);
-EXPORT_SYMBOL(atomic_inc);
-EXPORT_SYMBOL(atomic_inc_return);
-EXPORT_SYMBOL(atomic_dec);
-EXPORT_SYMBOL(atomic_dec_return);
-EXPORT_SYMBOL(atomic_dec_and_test);
-
 EXPORT_SYMBOL(set_bit);
 EXPORT_SYMBOL(clear_bit);
 EXPORT_SYMBOL(change_bit);
 EXPORT_SYMBOL(test_and_set_bit);
 EXPORT_SYMBOL(test_and_clear_bit);
 EXPORT_SYMBOL(test_and_change_bit);
-#if 0
-EXPORT_SYMBOL(ffz);
-EXPORT_SYMBOL(find_first_zero_bit);
-EXPORT_SYMBOL(find_next_zero_bit);
-#endif
 
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -254,6 +242,7 @@
 #endif /* CONFIG_NVRAM */
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
@@ -281,3 +270,17 @@
 EXPORT_SYMBOL(xmon);
 #endif
 EXPORT_SYMBOL(down_read_failed);
+
+extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger_bpt)(struct pt_regs *regs);
+extern int (*debugger_sstep)(struct pt_regs *regs);
+extern int (*debugger_iabr_match)(struct pt_regs *regs);
+extern int (*debugger_dabr_match)(struct pt_regs *regs);
+extern void (*debugger_fault_handler)(struct pt_regs *regs);
+
+EXPORT_SYMBOL(debugger);
+EXPORT_SYMBOL(debugger_bpt);
+EXPORT_SYMBOL(debugger_sstep);
+EXPORT_SYMBOL(debugger_iabr_match);
+EXPORT_SYMBOL(debugger_dabr_match);
+EXPORT_SYMBOL(debugger_fault_handler);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/process.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/process.c	Tue May  2 13:05:40 2000
@@ -489,7 +489,7 @@
 {
 	int error;
 	char * filename;
-	lock_kernel();
+
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
@@ -503,8 +503,6 @@
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 	putname(filename);
 out:
-	unlock_kernel();
-
 	return error;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/prom.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/kernel/prom.c	Tue May  2 13:05:40 2000
@@ -106,7 +106,10 @@
 unsigned int rtas_size = 0;
 unsigned int old_rtas = 0;
 
+/* Set for a newworld machine */
 int use_of_interrupt_tree = 0;
+int pmac_newworld = 0;
+
 static struct device_node *allnodes = 0;
 
 #ifdef CONFIG_BOOTX_TEXT
@@ -802,7 +805,6 @@
 static void
 setup_disp_fake_bi(ihandle dp)
 {
-	unsigned int len;
 	int width = 640, height = 480, depth = 8, pitch;
 	unsigned address;
 	boot_infos_t* bi;
@@ -982,15 +984,17 @@
 finish_device_tree(void)
 {
 	unsigned long mem = (unsigned long) klimit;
-	char* model;
-	
-	/* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
-	 * This code was only tested with Core99 machines so far, but should be easily
-	 * adapted to older newworld machines (iMac, B&W G3, Lombard).
-	 */
-	model = get_property(allnodes, "model", 0);
-	if ((boot_infos == 0) && model && (strcmp(model, "PowerBook2,1") == 0
-	    || strcmp(model, "PowerMac2,1") == 0 || strcmp(model, "PowerMac3,1") == 0))
+
+	/* All newworld machines now use the interrupt tree */
+	struct device_node *np = allnodes;
+	while(np) {
+		if (get_property(np, "interrupt-parent", 0)) {
+			pmac_newworld = 1;
+			break;
+		}
+		np = np->allnext;
+	}
+	if (boot_infos == 0 && pmac_newworld)
 		use_of_interrupt_tree = 1;
 
 	mem = finish_node(allnodes, mem, NULL);
@@ -1827,7 +1831,8 @@
 #ifdef CONFIG_XMON
 	xmon(NULL);
 #endif
-	prom_exit();
+	for (;;)
+		prom_exit();
 }
 
 #ifdef CONFIG_BOOTX_TEXT
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/qspan_pci.c linux/arch/ppc/kernel/qspan_pci.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/qspan_pci.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/ppc/kernel/qspan_pci.c	Tue May  2 13:05:40 2000
@@ -84,7 +84,7 @@
 		"	.align 2\n"			\
 		"	.long 1b,3b\n"			\
 		".text"					\
-		: "=r"(x) : "r"(addr))
+		: "=r"(x) : "r"(addr) : " %0")
 
 #define QS_CONFIG_ADDR	((volatile uint *)(PCI_CSR_ADDR + 0x500))
 #define QS_CONFIG_DATA	((volatile uint *)(PCI_CSR_ADDR + 0x504))
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/setup.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/kernel/setup.c	Tue May  2 13:05:40 2000
@@ -27,6 +27,10 @@
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #endif
+#ifdef CONFIG_8260
+#include <asm/mpc8260.h>
+#include <asm/immap_8260.h>
+#endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/feature.h>
@@ -109,8 +113,10 @@
  * on pmac as well so we don't need the ifdef's.
  * Until we get multiple-console support in here
  * that is.  -- Cort
+ * Maybe tie it to serial consoles, since this is really what
+ * these processors use on existing boards.  -- Dan
  */ 
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260)
 struct screen_info screen_info = {
 	0, 25,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -283,10 +289,10 @@
 			}
 			break;
 		case 0x0050:
-			len += sprintf(len+buffer, "821\n");
+			len += sprintf(len+buffer, "8xx\n");
 			break;
 		case 0x0081:
-			len += sprintf(len+buffer, "8240\n");
+			len += sprintf(len+buffer, "82xx\n");
 			break;
 		case 0x4011:
 			len += sprintf(len+buffer, "405GP\n");
@@ -300,7 +306,7 @@
 		 * Assume here that all clock rates are the same in a
 		 * smp system.  -- Cort
 		 */
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260)
 		if ( have_of )
 		{
 			struct device_node *cpu_node;
@@ -418,10 +424,10 @@
 		 unsigned long r6, unsigned long r7)
 {
 	parse_bootinfo();
-	
+
 	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
 	
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260)
 #ifndef CONFIG_MACH_SPECIFIC
 	/* if we didn't get any bootinfo telling us what we are... */
 	if ( _machine == 0 )
@@ -540,6 +546,8 @@
 	oak_init(r3, r4, r5, r6, r7);
 #elif defined(CONFIG_8xx)
         m8xx_init(r3, r4, r5, r6, r7);
+#elif defined(CONFIG_8260)
+        m8260_init(r3, r4, r5, r6, r7);
 #else
 #error "No board type has been defined for identify_machine()!"
 #endif /* CONFIG_4xx */
@@ -659,13 +667,19 @@
 	map_bootx_text();
 #endif
 
+#ifdef CONFIG_ALL_PPC
+	feature_init();
+#endif
+
 #ifdef CONFIG_XMON
 	xmon_map_scc();
 	if (strstr(cmd_line, "xmon"))
 		xmon(0);
 #endif /* CONFIG_XMON */
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
+
 #if defined(CONFIG_KGDB)
+	kgdb_map_scc();
 	set_debug_traps();
 	breakpoint();
 #endif
@@ -688,6 +702,7 @@
 
 	ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+
 	paging_init();
 }
 
@@ -696,7 +711,6 @@
         int i;
 	unsigned short *stringcast;
 
-
 	id->config         = __le16_to_cpu(id->config);
 	id->cyls           = __le16_to_cpu(id->cyls);
 	id->reserved2      = __le16_to_cpu(id->reserved2);
@@ -708,16 +722,16 @@
 	id->vendor1        = __le16_to_cpu(id->vendor1);
 	id->vendor2        = __le16_to_cpu(id->vendor2);
 	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i=0; i<(20/2); i++)
+	for (i = 0; i < (20/2); i++)
 	        stringcast[i] = __le16_to_cpu(stringcast[i]);
 	id->buf_type       = __le16_to_cpu(id->buf_type);
 	id->buf_size       = __le16_to_cpu(id->buf_size);
 	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
 	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i=0; i<(8/2); i++)
+	for (i = 0; i < (8/2); i++)
 	        stringcast[i] = __le16_to_cpu(stringcast[i]);
 	stringcast = (unsigned short *)&id->model[0];
-	for (i=0; i<(40/2); i++)
+	for (i = 0; i < (40/2); i++)
 	        stringcast[i] = __le16_to_cpu(stringcast[i]);
 	id->dword_io       = __le16_to_cpu(id->dword_io);
 	id->reserved50     = __le16_to_cpu(id->reserved50);
@@ -735,12 +749,12 @@
 	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
 	id->eide_pio       = __le16_to_cpu(id->eide_pio);
 	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i=0; i<2; i++)
+	for (i = 0; i < 2; i++)
 		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i=0; i<4; i++)
+        for (i = 0; i < 4; i++)
                 id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
 	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i=0; i<4; i++)
+	for (i = 0; i < 4; i++)
 		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
 	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
 	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
@@ -756,14 +770,14 @@
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
 	id->word92         = __le16_to_cpu(id->word92);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
-	for (i=0; i<32; i++)
+	for (i = 0; i < 32; i++)
 		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
 	id->last_lun       = __le16_to_cpu(id->last_lun);
 	id->word127        = __le16_to_cpu(id->word127);
 	id->dlf            = __le16_to_cpu(id->dlf);
 	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i=0; i<31; i++)
+	for (i = 0; i < 30; i++)
 		id->words130_159[i] = __le16_to_cpu(id->words130_159[i]);
-	for (i=0; i<97; i++)
+	for (i = 0; i < 96; i++)
 		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/totalmp.c linux/arch/ppc/kernel/totalmp.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/totalmp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/totalmp.c	Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-/*
- * $Id: totalmp.c,v 1.6 1999/08/31 06:54:10 davem Exp $
- *
- * Support for Total Impact's TotalMP PowerPC accelerator board.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/openpic.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-
-extern void totalmp_init(void);
-
-extern inline void openpic_writefield(volatile u_int *addr, u_int mask,
-				      u_int field);
-void __init totalmp_init(void)
-{
-	struct pci_dev *dev;
-	u32 val;
-	unsigned long ctl_area, ctl_area_phys;
-
-	/* it's a pci card */
-	if ( !pci_present() ) return;
-
-	/* search for a MPIC.  For now, we assume
-	 * only one TotalMP card installed. -- Cort
-	 */
-	for(dev=pci_devices; dev; dev=dev->next)
-	{
-		if ( (dev->vendor == PCI_VENDOR_ID_IBM)
-		     && ((dev->device == PCI_DEVICE_ID_IBM_MPIC)
-			 || (dev->device==PCI_DEVICE_ID_IBM_MPIC_2)) )
-		{
-			break;
-		}
-	}
-
-	if ( !dev ) return;
-
-	OpenPIC = (struct OpenPIC *)bus_to_virt(dev->base_address[0]);
-#if 0	
-	if ( (ulong)OpenPIC > 0x10000000 )
-	{
-		printk("TotalMP: relocating base %lx -> %lx\n",
-		       (ulong)OpenPIC, ((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000);
-		OpenPIC = (struct OpenPIC *)(((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000);
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, (ulong)OpenPIC);
-	}*/
-#endif	
-	OpenPIC = (struct OpenPIC *)((ulong)OpenPIC + _IO_BASE);
-
-	openpic_init(0);
-
-	/* put openpic in 8259-cascade mode */
-	openpic_writefield(&OpenPIC->Global.Global_Configuration0, 0, 0x20000000);
-	/* set ipi to highest priority */
-	openpic_writefield(&OpenPIC->Global._IPI_Vector_Priority[0].Reg, 0, 0x000f0000);
-
-	/* allocate and remap the control area to be no-cache */
-	ctl_area = __get_free_pages(GFP_ATOMIC, 3);
-	ctl_area_phys = (unsigned long) virt_to_phys((void *)ctl_area);
-	ctl_area = (unsigned long)ioremap(ctl_area, 0x8000);
-	
-	/* soft reset cpu 0 */
-	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val);
-	openpic_writefield(&OpenPIC->Global._Processor_Initialization.Reg, 0, 0x1);
-
-	/* wait for base address reg to change, signaling that cpu 0 is done */
-#define wait_for(where) { 					\
-	udelay(100);						\
-	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val); 	\
-	if ( val != 0x77700000 ) 				\
-	{ 							\
-		printk("TotalMP: CPU0 did not respond: val %x %d\n", val, where); \
-		/*free_pages((ulong)phys_to_virt(ctl_area_phys),1);*/ \
-		return;						\
-	} }
-	
-	/* tell cpu0 where the control area is */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,(~val) >> 16);
-	wait_for(0);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
-			       ((ulong)ctl_area & 0xff000000)>>20);
-	wait_for(1);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
-			       ((ulong)ctl_area & 0x00ff0000)>>12);
-	wait_for(2);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
-			       ((ulong)ctl_area & 0x0000ff00)>>4);
-	wait_for(3);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
-			       ((ulong)ctl_area & 0x000000ff)<<4);
-	wait_for(4);
-#undef wait_for
-	/* wait for cpu0 to "sign-on" */
-}
-
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.3.99-pre6/linux/arch/ppc/kernel/traps.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ppc/kernel/traps.c	Tue May  2 13:05:40 2000
@@ -119,10 +119,10 @@
 			printk("Unknown values in msr\n");
 		}
 		show_regs(regs);
-		print_backtrace((unsigned long *)regs->gpr[1]);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		debugger(regs);
 #endif
+		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("machine check");
 	}
 	_exception(SIGSEGV, regs);	
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/Makefile linux/arch/ppc/mbxboot/Makefile
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/Makefile	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/mbxboot/Makefile	Tue May  2 13:05:40 2000
@@ -25,11 +25,20 @@
 IOFF = 0
 ISZ = 0
 
-TFTPIMAGE=/tftpboot/zImage.mbx
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000
+TFTPIMAGE=/tftpboot/zImage.embedded
 
+ifdef CONFIG_8xx
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000
 OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
+endif
+
+ifdef CONFIG_8260
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000
+OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260
+endif
+
 OBJCOPY_ARGS = -O elf32-powerpc
 
 ifeq ($(CONFIG_MBX),y)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/embed_config.c linux/arch/ppc/mbxboot/embed_config.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/embed_config.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/mbxboot/embed_config.c	Wed May  3 01:47:57 2000
@@ -3,7 +3,13 @@
  * not have boot monitor support for board information.
  */
 #include <sys/types.h>
-#include "asm/mpc8xx.h"
+#include <linux/config.h>
+#ifdef CONFIG_8xx
+#include <asm/mpc8xx.h>
+#endif
+#ifdef CONFIG_8260
+#include <asm/mpc8260.h>
+#endif
 
 
 /* IIC functions.
@@ -13,6 +19,14 @@
 extern void	iic_read(uint devaddr, u_char *buf, uint offset, uint count);
 extern u_char	aschex_to_byte(u_char *cp);
 
+/* Supply a default Ethernet address for those eval boards that don't
+ * ship with one.  This is an address from the MBX board I have, so
+ * it is unlikely you will find it on your network.
+ */
+static	ushort	def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+
 static void	rpx_eth(bd_t *bd, u_char *cp);
 static void	rpx_brate(bd_t *bd, u_char *cp);
 static void	rpx_memsize(bd_t *bd, u_char *cp);
@@ -89,8 +103,10 @@
 	bd->bi_memstart = 0;
 
 #else
+	/* For boards without initialized EEPROM.
+	*/
 	bd->bi_memstart = 0;
-	bd->bi_memsize = (4 * 1024 * 1024);
+	bd->bi_memsize = (8 * 1024 * 1024);
 	bd->bi_intfreq = 48;
 	bd->bi_busfreq = 48;
 	bd->bi_baudrate = 9600;
@@ -174,7 +190,9 @@
 	if (num > 50)
 		bd->bi_busfreq /= 2;
 }
+#endif /* RPXLITE || RPXCLASSIC */
 
+#ifdef CONFIG_BSEIP
 /* Build a board information structure for the BSE ip-Engine.
  * There is more to come since we will add some environment
  * variables and a function to read them.
@@ -204,4 +222,31 @@
 	bd->bi_intfreq = 48;
 	bd->bi_busfreq = 48;
 }
+#endif /* BSEIP */
 
+#ifdef CONFIG_EST8260
+void
+embed_config(bd_t *bd)
+{
+	u_char	*cp;
+	int	i;
+
+#if 1
+	/* This is actually provided by my boot rom.  I have it
+	 * here for those people that may load the kernel with
+	 * a JTAG/COP tool and not the rom monitor.
+	 */
+	bd->bi_baudrate = 115200;
+	bd->bi_intfreq = 200;
+	bd->bi_busfreq = 66;
+	bd->bi_cpmfreq = 66;
+	bd->bi_brgfreq = 33;
+	bd->bi_memsize = 16 * 1024 * 1024;
+#endif
+
+	cp = (u_char *)def_enet_addr;
+	for (i=0; i<6; i++) {
+		bd->bi_enetaddr[i] = *cp++;
+	}
+}
+#endif /* EST8260 */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/head_8260.S linux/arch/ppc/mbxboot/head_8260.S
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/head_8260.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/head_8260.S	Tue May  2 13:05:40 2000
@@ -0,0 +1,246 @@
+#include "../kernel/ppc_defs.h"
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+	.text
+
+/*
+ * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $
+ *	
+ * Boot loader philosophy:
+ *      ROM loads us to some arbitrary location
+ *      Move the boot code to the link address (8M)
+ *      Call decompress_kernel()
+ *         Relocate the initrd, zimage and residual data to 8M
+ *         Decompress the kernel to 0
+ *      Jump to the kernel entry
+ *            -- Cort
+ */
+	.globl	start
+start:
+	bl	start_
+start_:
+	mr	r11,r3		/* Save pointer to residual/board data */
+	mr      r25,r5          /* Save OFW pointer */
+	li	r3,MSR_IP	/* Establish default MSR value */
+	mtmsr	r3
+
+/* check if we need to relocate ourselves to the link addr or were we
+   loaded there to begin with -- Cort */
+	lis	r4,start@h
+	ori	r4,r4,start@l
+	mflr	r3
+	subi	r3,r3,4		/* we get the nip, not the ip of the branch */
+	mr	r8,r3
+	cmp	0,r3,r4
+	bne	1010f
+/* compute size of whole image in words.  this should be moved to
+ * start_ldr() -- Cort
+ */
+	lis	r4,start@h
+	ori	r4,r4,start@l
+	lis	r5,end@h
+	ori	r5,r5,end@l
+	addi	r5,r5,3		/* round up */
+	sub	r5,r5,r4
+	srwi	r5,r5,2
+	mr	r7,r5
+	b	start_ldr
+1010:
+/* 
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
+relocate:
+	mflr	r3		/* Compute code bias */
+	subi	r3,r3,4
+	mr	r8,r3
+	lis	r4,start@h
+	ori	r4,r4,start@l
+	lis	r5,end@h
+	ori	r5,r5,end@l
+	addi	r5,r5,3			/* Round up - just in case */
+	sub	r5,r5,r4		/* Compute # longwords to move */
+	srwi	r5,r5,2
+	mtctr	r5
+	mr	r7,r5
+	li	r6,0
+	subi	r3,r3,4			/* Set up for loop */
+	subi	r4,r4,4
+00:	lwzu	r5,4(r3)
+	stwu	r5,4(r4)
+	xor	r6,r6,r5
+	bdnz	00b
+  	lis	r3,start_ldr@h
+	ori	r3,r3,start_ldr@l
+	mtlr	r3			/* Easiest way to do an absolute jump */
+	blr
+start_ldr:
+/* Clear all of BSS */
+	lis	r3,edata@h
+	ori	r3,r3,edata@l
+	lis	r4,end@h
+	ori	r4,r4,end@l
+	subi	r3,r3,4
+	subi	r4,r4,4
+	li	r0,0
+50:	stwu	r0,4(r3)
+	cmp	0,r3,r4
+	bne	50b
+90:	mr	r9,r1			/* Save old stack pointer (in case it matters) */
+	lis	r1,.stack@h
+	ori	r1,r1,.stack@l
+	addi	r1,r1,4096*2
+	subi	r1,r1,256
+	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
+	andc	r1,r1,r2
+/* Run loader */
+	mr	r3,r8			/* Load point */
+	mr	r4,r7			/* Program length */
+	mr	r5,r6			/* Checksum */
+	mr	r6,r11			/* Residual data */
+	mr      r7,r25                  /* OFW interfaces */
+	bl	decompress_kernel
+	
+	/* changed to use r3 (as firmware does) for kernel
+	   as ptr to residual -- Cort*/
+	lis	r6,cmd_line@h
+	ori	r6,r6,cmd_line@l
+	lwz	r6, 0(r6)
+	subi	r7,r6,1
+00:	lbzu	r2,1(r7)
+	cmpi	0,r2,0
+	bne	00b
+
+	/* r4,r5 have initrd_start, size */
+	lis	r2,initrd_start@h
+	ori	r2,r2,initrd_start@l
+	lwz	r4,0(r2)
+	lis	r2,initrd_end@h
+	ori	r2,r2,initrd_end@l
+	lwz	r5,0(r2)
+	
+	/* tell kernel we're prep */
+	/* 
+	 * get start address of kernel code which is stored as a coff
+	 * entry.  see boot/head.S -- Cort 
+	 */
+	li	r9,0x4
+	mtlr	r9
+	lis	r10,0xdeadc0de@h
+	ori	r10,r10,0xdeadc0de@l
+	li	r9,0
+	stw	r10,0(r9)
+/*
+ * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
+ * so disable BATs before setting this to avoid a clash
+ */
+	li      r8,0
+	mtspr   DBAT0U,r8
+	mtspr   DBAT1U,r8
+	mtspr   DBAT2U,r8
+	mtspr   DBAT3U,r8
+	mtspr   IBAT0U,r8
+	mtspr   IBAT1U,r8
+	mtspr   IBAT2U,r8
+	mtspr   IBAT3U,r8
+
+	blr
+hang:
+	b	hang	
+
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+	.globl	udelay
+udelay:		
+	mfspr	r4,PVR
+	srwi	r4,r4,16
+	cmpi	0,r4,1		/* 601 ? */
+	bne	.udelay_not_601
+00:	li	r0,86	/* Instructions / microsecond? */
+	mtctr	r0
+10:	addi	r0,r0,0 /* NOP */
+	bdnz	10b
+	subic.	r3,r3,1
+	bne	00b
+	blr
+
+.udelay_not_601:		
+	mulli	r4,r3,1000	/* nanoseconds */
+	addi	r4,r4,59
+	li	r5,60
+	divw	r4,r4,r5	/* BUS ticks */
+1:	mftbu	r5
+	mftb	r6
+	mftbu	r7
+	cmp	0,r5,r7
+	bne	1b		/* Get [synced] base time */
+	addc	r9,r6,r4	/* Compute end time */
+	addze	r8,r5
+2:	mftbu	r5
+	cmp	0,r5,r8
+	blt	2b
+	bgt	3f
+	mftb	r6
+	cmp	0,r6,r9
+	blt	2b
+3:	blr		
+
+.globl _get_HID0
+_get_HID0:		
+	mfspr	r3,HID0
+	blr
+
+.globl _put_HID0
+_put_HID0:		
+	mtspr	HID0,r3
+	blr
+		
+.globl _get_MSR
+_get_MSR:		
+	mfmsr	r3
+	blr
+	
+.globl _put_MSR
+_put_MSR:		
+	mtmsr	r3
+	blr
+
+/*
+ * Flush instruction cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_instruction_cache)
+	mflr	r5
+	bl	flush_data_cache
+	mfspr	r3,HID0	/* Caches are controlled by this register */
+	li	r4,0
+	ori	r4,r4,(HID0_ICE|HID0_ICFI)
+	or	r3,r3,r4	/* Need to enable+invalidate to clear */
+	mtspr	HID0,r3
+	andc	r3,r3,r4
+	ori	r3,r3,HID0_ICE	/* Enable cache */
+	mtspr	HID0,r3
+	mtlr	r5
+	blr
+	
+#define NUM_CACHE_LINES 128*8
+#define CACHE_LINE_SIZE 32 
+#define cache_flush_buffer 0x1000
+
+/*
+ * Flush data cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_data_cache)
+	lis	r3,cache_flush_buffer@h
+	ori	r3,r3,cache_flush_buffer@l
+	li	r4,NUM_CACHE_LINES
+	mtctr	r4
+00:	lwz	r4,0(r3)
+	addi	r3,r3,CACHE_LINE_SIZE	/* Next line, please */
+	bdnz	00b	
+10:	blr
+	.comm	.stack,4096*2,4
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/iic.c linux/arch/ppc/mbxboot/iic.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/iic.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/mbxboot/iic.c	Tue May  2 13:05:40 2000
@@ -43,6 +43,15 @@
 	*/
 	while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG));
 
+	/* Remove any microcode patches.  We will install our own
+	 * later.
+	 */
+	cp->cp_cpmcr1 = 0;
+	cp->cp_cpmcr2 = 0;
+	cp->cp_cpmcr3 = 0;
+	cp->cp_cpmcr4 = 0;
+	cp->cp_rccr = 0;
+
 	iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
 	i2c = (i2c8xx_t *)&(immap->im_i2c);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/m8260_tty.c linux/arch/ppc/mbxboot/m8260_tty.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/m8260_tty.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mbxboot/m8260_tty.c	Wed May  3 01:47:57 2000
@@ -0,0 +1,201 @@
+
+
+/* Minimal serial functions needed to send messages out the serial
+ * port on SMC1.
+ */
+#include <linux/types.h>
+#include "asm/mpc8260.h"
+#include "asm/cpm_8260.h"
+
+uint	no_print;
+extern char	*params[];
+extern int	nparams;
+static		u_char	cons_hold[128], *sgptr;
+static		int	cons_hold_cnt;
+
+void
+serial_init(bd_t *bd)
+{
+	volatile smc_t		*sp;
+	volatile smc_uart_t	*up;
+	volatile cbd_t	*tbdf, *rbdf;
+	volatile immap_t	*ip;
+	volatile iop8260_t	*io;
+	volatile cpm8260_t	*cp;
+	uint	dpaddr, memaddr;
+
+	ip = (immap_t *)IMAP_ADDR;
+
+	sp = (smc_t*)&(ip->im_smc[0]);
+	*(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
+	up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1];
+
+	cp = &ip->im_cpm;
+	io = &ip->im_ioport;
+
+	/* Disable transmitter/receiver.
+	*/
+	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+	/* Use Port D for SMC1 instead of other functions.
+	*/
+	io->iop_ppard |= 0x00c00000;
+	io->iop_pdird |= 0x00400000;
+	io->iop_pdird &= ~0x00800000;
+	io->iop_psord &= ~0x00c00000;
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	 * For now, this address seems OK, but it may have to
+	 * change with newer versions of the firmware.
+	 */
+	dpaddr = 0x0800;
+
+	/* Grab a few bytes from the top of memory.
+	 */
+#if 1
+	memaddr = (bd->bi_memsize - 256) & ~15;
+#else
+	memaddr = 0x0f002c00;
+#endif
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	rbdf = (cbd_t *)&ip->im_dprambase[dpaddr];
+	rbdf->cbd_bufaddr = memaddr;
+	rbdf->cbd_sc = 0;
+	tbdf = rbdf + 1;
+	tbdf->cbd_bufaddr = memaddr+128;
+	tbdf->cbd_sc = 0;
+
+	/* Set up the uart parameters in the parameter ram.
+	*/
+	up->smc_rbase = dpaddr;
+	up->smc_tbase = dpaddr+sizeof(cbd_t);
+	up->smc_rfcr = SMC_EB;
+	up->smc_tfcr = SMC_EB;
+	up->smc_brklen = 0;
+	up->smc_brkec = 0;
+	up->smc_brkcr = 0;
+
+	/* Set UART mode, 8 bit, no parity, one stop.
+	 * Enable receive and transmit.
+	 */
+	sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+	/* Mask all interrupts and remove anything pending.
+	*/
+	sp->smc_smcm = 0;
+	sp->smc_smce = 0xff;
+
+	/* Set up the baud rate generator.
+	 */
+	ip->im_clkrst.car_sccr = 0;	/* DIV 4 BRG */
+	ip->im_cpmux.cmx_smr = 0;
+	ip->im_brgc1 =
+		((((bd->bi_brgfreq * 1000000)/16) / bd->bi_baudrate) << 1) |
+								CPM_BRG_EN;
+
+	/* Make the first buffer the only buffer.
+	*/
+	tbdf->cbd_sc |= BD_SC_WRAP;
+	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+#if 0
+	/* Single character receive.
+	*/
+	up->smc_mrblr = 1;
+	up->smc_maxidl = 0;
+#else
+	up->smc_mrblr = 128;
+	up->smc_maxidl = 8;
+#endif
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+	while (cp->cp_cpcr & CPM_CR_FLG);
+
+	/* Enable transmitter/receiver.
+	*/
+	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+}
+
+void
+serial_putchar(const char c)
+{
+	volatile cbd_t		*tbdf;
+	volatile char		*buf;
+	volatile smc_uart_t	*up;
+	volatile immap_t	*ip;
+	extern bd_t		*board_info;
+
+	ip = (immap_t *)IMAP_ADDR;
+	up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
+	tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase];
+
+	/* Wait for last character to go.
+	*/
+	buf = (char *)tbdf->cbd_bufaddr;
+	while (tbdf->cbd_sc & BD_SC_READY);
+
+	*buf = c;
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc |= BD_SC_READY;
+}
+
+char
+serial_getc()
+{
+	char	c;
+
+	if (cons_hold_cnt <= 0) {
+		cons_hold_cnt = serial_readbuf(cons_hold);
+		sgptr = cons_hold;
+	}
+	c = *sgptr++;
+	cons_hold_cnt--;
+
+	return(c);
+}
+
+int
+serial_readbuf(u_char *cbuf)
+{
+	volatile cbd_t		*rbdf;
+	volatile char		*buf;
+	volatile smc_uart_t	*up;
+	volatile immap_t	*ip;
+	int	i, nc;
+
+	ip = (immap_t *)IMAP_ADDR;
+
+	up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
+	rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
+
+	/* Wait for character to show up.
+	*/
+	buf = (char *)rbdf->cbd_bufaddr;
+	while (rbdf->cbd_sc & BD_SC_EMPTY);
+	nc = rbdf->cbd_datlen;
+	for (i=0; i<nc; i++)
+		*cbuf++ = *buf++;
+	rbdf->cbd_sc |= BD_SC_EMPTY;
+
+	return(nc);
+}
+
+int
+serial_tstc()
+{
+	volatile cbd_t		*rbdf;
+	volatile smc_uart_t	*up;
+	volatile immap_t	*ip;
+
+	ip = (immap_t *)IMAP_ADDR;
+	up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
+	rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
+
+	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/misc.c linux/arch/ppc/mbxboot/misc.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/misc.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/mbxboot/misc.c	Tue May  2 13:05:40 2000
@@ -20,6 +20,9 @@
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #endif
+#ifdef CONFIG_8260
+#include <asm/mpc8260.h>
+#endif
 
 /*
  * Please send me load/board info and such data for hardware not
@@ -230,6 +233,13 @@
 	char *cp, ch;
 	unsigned long i;
 	char	*dp;
+
+#ifdef CONFIG_8260
+	/* I don't know why I didn't do it this way on the 8xx.......
+	*/
+	embed_config(bp);
+	serial_init(bp);
+#endif
 
 	/* These values must be variables.  If not, the compiler optimizer
 	 * will remove some code, causing the size of the code to vary
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/pci.c linux/arch/ppc/mbxboot/pci.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/mbxboot/pci.c	Tue May  2 13:05:40 2000
@@ -1,6 +1,7 @@
 /* Stand alone funtions for QSpan Tundra support.
  */
-#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/mpc8xx.h>
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mbxboot/qspan_pci.c linux/arch/ppc/mbxboot/qspan_pci.c
--- v2.3.99-pre6/linux/arch/ppc/mbxboot/qspan_pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/mbxboot/qspan_pci.c	Tue May  2 13:05:40 2000
@@ -9,7 +9,8 @@
  * I don't know what to do about interrupts (yet).
  */
 
-#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/mpc8xx.h>
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.3.99-pre6/linux/arch/ppc/mm/fault.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/mm/fault.c	Tue May  2 13:05:40 2000
@@ -216,7 +216,7 @@
 	
 	pte = find_pte(current->mm, address);
 	if (pte)
-		return((unsigned long)(pte_page(*pte)) | (address & ~(PAGE_MASK-1)));
+		return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK-1)));
 	return (0);
 }
 
@@ -237,7 +237,7 @@
                                 printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
                                         (long)pgd, (long)pte, (long)pte_val(*pte));
 #define pp ((long)pte_val(*pte))				
-				printk(" RPN: %05x PP: %x SPS: %x SH: %lx "
+				printk(" RPN: %05lx PP: %lx SPS: %lx SH: %lx "
 				       "CI: %lx v: %lx\n",
 				       pp>>12,    /* rpn */
 				       (pp>>10)&3, /* pp */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.99-pre6/linux/arch/ppc/mm/init.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/ppc/mm/init.c	Tue May  2 13:05:40 2000
@@ -48,8 +48,14 @@
 #include <asm/mmu.h>
 #include <asm/residual.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
+#endif
+#ifdef CONFIG_8260
+#include <asm/immap_8260.h>
+#include <asm/mpc8260.h>
+#endif
 #include <asm/smp.h>
 #include <asm/bootx.h>
 #include <asm/machdep.h>
@@ -104,6 +110,9 @@
 #ifdef CONFIG_4xx
 unsigned long *oak_find_end_of_memory(void);
 #endif
+#ifdef CONFIG_8260
+unsigned long *m8260_find_end_of_memory(void);
+#endif /* CONFIG_8260 */
 static void mapin_ram(void);
 void map_page(unsigned long va, unsigned long pa, int flags);
 extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -725,7 +734,7 @@
                          * don't get ASID compares on kernel space.
                          */
 			f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
-#ifdef CONFIG_KGDB
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
  			/* Allows stub to set breakpoints everywhere */
  			f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
 #else
@@ -896,6 +905,9 @@
         mtspr(SPRN_ICCR, 0x80000000);	/* 128 MB of instr. space at 0x0. */
 }
 #else
+	/* How about ppc_md.md_find_end_of_memory instead of these
+	 * ifdefs?  -- Dan.
+	 */
 void __init MMU_init(void)
 {
 	if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
@@ -910,8 +922,13 @@
 	else if ( _machine == _MACH_gemini )
 		end_of_DRAM = gemini_find_end_of_memory();
 #endif /* CONFIG_GEMINI	*/
+#if defined(CONFIG_8260)
+	else
+		end_of_DRAM = m8260_find_end_of_memory();
+#else
 	else /* prep */
 		end_of_DRAM = prep_find_end_of_memory();
+#endif
 
 	if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300);
         hash_init();
@@ -960,11 +977,6 @@
 			setbat(0, base, base, 0x100000, IO_PAGE);
 		}
 #endif
-#if 0
-// This is bogus, BAT must be aligned.
-//		setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE);
-//		disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase;
-#endif		
 		ioremap_base = 0xf0000000;
 		break;
 	case _MACH_apus:
@@ -977,6 +989,16 @@
 		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
 		setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
 		break;
+	case _MACH_8260:
+		/* Map the IMMR, plus anything else we can cover
+		 * in that upper space according to the memory controller
+		 * chip select mapping.  Grab another bunch of space
+		 * below that for stuff we can't cover in the upper.
+		 */
+		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
+		setbat(1, 0xe0000000, 0xe0000000, 0x10000000, IO_PAGE);
+		ioremap_base = 0xe0000000;
+		break;
 	}
 	ioremap_bot = ioremap_base;
 #else /* CONFIG_8xx */
@@ -1295,6 +1317,28 @@
 }
 #endif /* defined(CONFIG_GEMINI) */
 
+#ifdef CONFIG_8260
+/*
+ * Same hack as 8xx.
+ */
+unsigned long __init *m8260_find_end_of_memory(void)
+{
+	bd_t	*binfo;
+	unsigned long *ret;
+	extern unsigned char __res[];
+	
+	binfo = (bd_t *)__res;
+
+	phys_mem.regions[0].address = 0;
+	phys_mem.regions[0].size = binfo->bi_memsize;	
+	phys_mem.n_regions = 1;
+	
+	ret = __va(phys_mem.regions[0].size);
+	set_phys_avail(&phys_mem);
+	return ret;
+}
+#endif /* CONFIG_8260 */
+
 #ifdef CONFIG_APUS
 #define HARDWARE_MAPPED_SIZE (512*1024)
 unsigned long __init *apus_find_end_of_memory(void)
@@ -1396,6 +1440,7 @@
 	case 3: /* 603 */
 	case 6: /* 603e */
 	case 7: /* 603ev */
+	case 0x0081: /* 82xx */
 		Hash_size = 0;
 		Hash_mask = 0;
 		break;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/xmon/Makefile linux/arch/ppc/xmon/Makefile
--- v2.3.99-pre6/linux/arch/ppc/xmon/Makefile	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/xmon/Makefile	Tue May  2 13:05:40 2000
@@ -1,6 +1,10 @@
 # Makefile for xmon
 
 O_TARGET = x.o
+ifeq ($(CONFIG_8xx),y)
+O_OBJS = start_8xx.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
+else
 O_OBJS = start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/xmon/privinst.h linux/arch/ppc/xmon/privinst.h
--- v2.3.99-pre6/linux/arch/ppc/xmon/privinst.h	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/xmon/privinst.h	Wed May  3 01:47:57 2000
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 1996 Paul Mackerras.
  */
+#include <linux/config.h>
 
 #define GETREG(reg)		\
     static inline int get_ ## reg (void)	\
@@ -38,6 +39,7 @@
 GSETSPR(275, sprg3)
 GSETSPR(282, ear)
 GSETSPR(287, pvr)
+#ifndef CONFIG_8xx
 GSETSPR(528, bat0u)
 GSETSPR(529, bat0l)
 GSETSPR(530, bat1u)
@@ -51,6 +53,13 @@
 GSETSPR(1010, iabr)
 GSETSPR(1013, dabr)
 GSETSPR(1023, pir)
+#else
+GSETSPR(144, cmpa)
+GSETSPR(145, cmpb)
+GSETSPR(146, cmpc)
+GSETSPR(147, cmpd)
+GSETSPR(158, ictrl)
+#endif
 
 static inline int get_sr(int n)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.99-pre6/linux/arch/ppc/xmon/start.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/xmon/start.c	Tue May  2 13:05:40 2000
@@ -43,6 +43,8 @@
 		sccd[3] &= ~0x80;	/* reset DLAB */
 }
 
+extern int adb_init(void);
+
 void
 xmon_map_scc(void)
 {
@@ -59,12 +61,13 @@
 
 		/* needs to be hacked if xmon_printk is to be used
  		   from within find_via_pmu() */
+#ifdef CONFIG_ADB_PMU
 		if (!via_modem && disp_bi && find_via_pmu()) {
 			prom_drawstring("xmon uses screen and keyboard\n");
 			use_screen = 1;
-			return;
 		}
 #endif
+#endif
 
 #ifdef CHRP_ESCC
 		addr = 0xc1013020;
@@ -77,18 +80,11 @@
 		np = find_devices("mac-io");
 		if (np && np->n_addrs) {
 			macio_node = np;
-			addr = np->addrs[0].address + 0x13000;
-			/* use the B channel on the iMac */
-			if (!xmon_use_sccb)
-				addr += 0x20; /* use A channel */
+			addr = np->addrs[0].address + 0x13020;
 		}
 		base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
 		sccc = base + (addr & ~PAGE_MASK);
-#ifdef CHRP_ESCC
-		sccd = sccc + (0xc1013030 - 0xc1013020);
-#else
-		sccd = sccc + (0xf3013030 - 0xf3013020);
-#endif
+		sccd = sccc + 0x10;
 	}
 	else if ( _machine & _MACH_gemini )
 	{
@@ -133,10 +129,10 @@
 	ct = 0;
 	for (i = 0; i < nb; ++i) {
 		while ((*sccc & TXRDY) == 0) {
-#ifdef CONFIG_ADB	    
+#ifdef CONFIG_ADB_PMU
 			if (sys_ctrler == SYS_CTRLER_PMU)
 				pmu_poll();
-#endif /* CONFIG_ADB */
+#endif /* CONFIG_ADB_PMU */
 		}
 		c = p[i];
 		if (c == '\n' && !ct) {
@@ -144,7 +140,6 @@
 			ct = 1;
 			--i;
 		} else {
-			prom_drawchar(c);
 			if (console)
 				printk("%c", c);
 			ct = 0;
@@ -156,10 +151,10 @@
 }
 
 int xmon_wants_key;
-int xmon_pmu_keycode;
+int xmon_adb_keycode;
 
 #ifdef CONFIG_BOOTX_TEXT
-static int xmon_pmu_shiftstate;
+static int xmon_adb_shiftstate;
 
 static unsigned char xmon_keytab[128] =
 	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
@@ -178,13 +173,13 @@
 	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
 
 static int
-xmon_get_pmu_key(void)
+xmon_get_adb_key(void)
 {
 	int k, t, on;
 
 	xmon_wants_key = 1;
 	for (;;) {
-		xmon_pmu_keycode = -1;
+		xmon_adb_keycode = -1;
 		t = 0;
 		on = 0;
 		do {
@@ -194,20 +189,22 @@
 				prom_drawchar('\b');
 				t = 200000;
 			}
+#ifdef CONFIG_ADB_PMU
 			pmu_poll();
-		} while (xmon_pmu_keycode == -1);
-		k = xmon_pmu_keycode;
+#endif /* CONFIG_ADB_PMU */
+		} while (xmon_adb_keycode == -1);
+		k = xmon_adb_keycode;
 		if (on)
 			prom_drawstring(" \b");
 
 		/* test for shift keys */
 		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
-			xmon_pmu_shiftstate = (k & 0x80) == 0;
+			xmon_adb_shiftstate = (k & 0x80) == 0;
 			continue;
 		}
 		if (k >= 0x80)
 			continue;	/* ignore up transitions */
-		k = (xmon_pmu_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
+		k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
 		if (k != 0)
 			break;
 	}
@@ -225,7 +222,7 @@
 #ifdef CONFIG_BOOTX_TEXT
     if (use_screen) {
 	for (i = 0; i < nb; ++i)
-	    *p++ = xmon_get_pmu_key();
+	    *p++ = xmon_get_adb_key();
 	return i;
     }
 #endif
@@ -233,12 +230,12 @@
 	xmon_init_scc();
     for (i = 0; i < nb; ++i) {
 	while ((*sccc & RXRDY) == 0)
-#ifdef CONFIG_ADB	    
+#ifdef CONFIG_ADB_PMU
 	    if (sys_ctrler == SYS_CTRLER_PMU)
 		pmu_poll();
 #else
 		;
-#endif /* CONFIG_ADB */
+#endif /* CONFIG_ADB_PMU */
 	buf_access();
 		*p++ = *sccd;
     }
@@ -249,12 +246,10 @@
 xmon_read_poll(void)
 {
 	if ((*sccc & RXRDY) == 0) {
-#ifdef CONFIG_ADB	    
+#ifdef CONFIG_ADB_PMU
 		if (sys_ctrler == SYS_CTRLER_PMU)
 			pmu_poll();
-#else
-			;
-#endif			
+#endif /* CONFIG_ADB_PMU */
 		return -1;
 	}
 	buf_access();
@@ -296,6 +291,12 @@
 			t0 = readtb();
 			while (readtb() - t0 < 3*TB_SPEED)
 				eieio();
+		}
+		/* use the B channel if requested */
+		if (xmon_use_sccb) {
+			sccc = (volatile unsigned char *)
+				((unsigned long)sccc & ~0x20);
+			sccd = sccc + 0x10;
 		}
 		for (i = 20000; i != 0; --i) {
 			x = *sccc; eieio();
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/xmon/start_8xx.c linux/arch/ppc/xmon/start_8xx.c
--- v2.3.99-pre6/linux/arch/ppc/xmon/start_8xx.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/xmon/start_8xx.c	Wed May  3 01:47:57 2000
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ * Copyright (C) 2000 Dan Malek.
+ * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
+ * of assumptions, like the SMC1 is used, it has been initialized by the
+ * loader at some point, and we can just stuff and suck bytes.
+ * We rely upon the 8xx uart driver to support us, as the interface
+ * changes between boot up and operational phases of the kernel.
+ */
+#include <linux/string.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <linux/kernel.h>
+#include <asm/processor.h>
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+#include "commproc.h"
+
+extern void xmon_printf(const char *fmt, ...);
+extern int xmon_8xx_write(char *str, int nb);
+extern int xmon_8xx_read_poll(void);
+extern int xmon_8xx_read_char(void);
+void prom_drawhex(uint);
+void prom_drawstring(const char *str);
+
+static int use_screen = 1; /* default */
+
+#define TB_SPEED	25000000
+
+static inline unsigned int readtb(void)
+{
+	unsigned int ret;
+
+	asm volatile("mftb %0" : "=r" (ret) :);
+	return ret;
+}
+
+void buf_access(void)
+{
+}
+
+void
+xmon_map_scc(void)
+{
+
+	cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+	use_screen = 0;
+	
+	prom_drawstring("xmon uses serial port\n");
+}
+
+static int scc_initialized = 0;
+
+void xmon_init_scc(void);
+
+int
+xmon_write(void *handle, void *ptr, int nb)
+{
+	char *p = ptr;
+	int i, c, ct;
+
+	if (!scc_initialized)
+		xmon_init_scc();
+
+	return(xmon_8xx_write(ptr, nb));
+}
+
+int xmon_wants_key;
+
+int
+xmon_read(void *handle, void *ptr, int nb)
+{
+	char *p = ptr;
+	int i;
+
+	if (!scc_initialized)
+		xmon_init_scc();
+
+	for (i = 0; i < nb; ++i) {
+		*p++ = xmon_8xx_read_char();
+	}
+	return i;
+}
+
+int
+xmon_read_poll(void)
+{
+	return(xmon_8xx_read_poll());
+}
+
+void
+xmon_init_scc()
+{
+	scc_initialized = 1;
+}
+
+#if 0
+extern int (*prom_entry)(void *);
+
+int
+xmon_exit(void)
+{
+    struct prom_args {
+	char *service;
+    } args;
+
+    for (;;) {
+	args.service = "exit";
+	(*prom_entry)(&args);
+    }
+}
+#endif
+
+void *xmon_stdin;
+void *xmon_stdout;
+void *xmon_stderr;
+
+void
+xmon_init(void)
+{
+}
+
+int
+xmon_putc(int c, void *f)
+{
+    char ch = c;
+
+    if (c == '\n')
+	xmon_putc('\r', f);
+    return xmon_write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+xmon_putchar(int c)
+{
+    return xmon_putc(c, xmon_stdout);
+}
+
+int
+xmon_fputs(char *str, void *f)
+{
+    int n = strlen(str);
+
+    return xmon_write(f, str, n) == n? 0: -1;
+}
+
+int
+xmon_readchar(void)
+{
+    char ch;
+
+    for (;;) {
+	switch (xmon_read(xmon_stdin, &ch, 1)) {
+	case 1:
+	    return ch;
+	case -1:
+	    xmon_printf("read(stdin) returned -1\r\n", 0, 0);
+	    return -1;
+	}
+    }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+#if 0
+int xmon_expect(const char *str, unsigned int timeout)
+{
+	int c;
+	unsigned int t0;
+
+	timeout *= TB_SPEED;
+	t0 = readtb();
+	do {
+		lineptr = line;
+		for (;;) {
+			c = xmon_read_poll();
+			if (c == -1) {
+				if (readtb() - t0 > timeout)
+					return 0;
+				continue;
+			}
+			if (c == '\n')
+				break;
+			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+				*lineptr++ = c;
+		}
+		*lineptr = 0;
+	} while (strstr(line, str) == NULL);
+	return 1;
+}
+#endif
+
+int
+xmon_getchar(void)
+{
+    int c;
+
+    if (lineleft == 0) {
+	lineptr = line;
+	for (;;) {
+	    c = xmon_readchar();
+	    if (c == -1 || c == 4)
+		break;
+	    if (c == '\r' || c == '\n') {
+		*lineptr++ = '\n';
+		xmon_putchar('\n');
+		break;
+	    }
+	    switch (c) {
+	    case 0177:
+	    case '\b':
+		if (lineptr > line) {
+		    xmon_putchar('\b');
+		    xmon_putchar(' ');
+		    xmon_putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    case 'U' & 0x1F:
+		while (lineptr > line) {
+		    xmon_putchar('\b');
+		    xmon_putchar(' ');
+		    xmon_putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    default:
+		if (lineptr >= &line[sizeof(line) - 1])
+		    xmon_putchar('\a');
+		else {
+		    xmon_putchar(c);
+		    *lineptr++ = c;
+		}
+	    }
+	}
+	lineleft = lineptr - line;
+	lineptr = line;
+    }
+    if (lineleft == 0)
+	return -1;
+    --lineleft;
+    return *lineptr++;
+}
+
+char *
+xmon_fgets(char *str, int nb, void *f)
+{
+    char *p;
+    int c;
+
+    for (p = str; p < str + nb - 1; ) {
+	c = xmon_getchar();
+	if (c == -1) {
+	    if (p == str)
+		return 0;
+	    break;
+	}
+	*p++ = c;
+	if (c == '\n')
+	    break;
+    }
+    *p = 0;
+    return str;
+}
+
+void
+prom_drawhex(uint val)
+{
+	unsigned char buf[10];
+
+	int i;
+	for (i = 7;  i >= 0;  i--)
+	{
+		buf[i] = "0123456789abcdef"[val & 0x0f];
+		val >>= 4;
+	}
+	buf[8] = '\0';
+	xmon_fputs(buf, xmon_stdout);
+}
+
+void
+prom_drawstring(const char *str)
+{
+	xmon_fputs(str, xmon_stdout);
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- v2.3.99-pre6/linux/arch/ppc/xmon/xmon.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/xmon/xmon.c	Wed May  3 01:47:57 2000
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1996 Paul Mackerras.
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <asm/ptrace.h>
@@ -120,8 +121,7 @@
 xmon(struct pt_regs *excp)
 {
 	struct pt_regs regs;
-	int msr, cmd, i;
-	unsigned *sp;
+	int msr, cmd;
 
 	if (excp == NULL) {
 		asm volatile ("stw	0,0(%0)\n\
@@ -137,29 +137,6 @@
 		excp = &regs;
 	}
 
-	prom_drawstring("xmon pc="); prom_drawhex(excp->nip);
-	prom_drawstring(" lr="); prom_drawhex(excp->link);
-	prom_drawstring(" msr="); prom_drawhex(excp->msr);
-	prom_drawstring(" trap="); prom_drawhex(excp->trap);
-	prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]);
-	sp = (unsigned *)&excp->gpr[0];
-	for (i = 0; i < 32; ++i) {
-		if ((i & 7) == 0)
-			prom_drawstring("\n");
-		prom_drawstring(" ");
-		prom_drawhex(sp[i]);
-	}
-	sp = (unsigned *) excp->gpr[1];
-	for (i = 0; i < 64; ++i) {
-		if ((i & 7) == 0) {
-			prom_drawstring("\n");
-			prom_drawhex(sp);
-			prom_drawstring(" ");
-		}
-		prom_drawstring(" ");
-		prom_drawhex(sp[i]);
-	}
-	prom_drawstring("\n");
 	msr = get_msr();
 	set_msr(msr & ~0x8000);	/* disable interrupts */
 	remove_bpts();
@@ -284,10 +261,12 @@
 			bp->enabled = 0;
 		}
 	}
+#ifndef CONFIG_8xx
 	if (dabr.enabled)
 		set_dabr(dabr.address);
 	if (iabr.enabled)
 		set_iabr(iabr.address);
+#endif
 }
 
 static void
@@ -297,8 +276,10 @@
 	struct bpt *bp;
 	unsigned instr;
 
+#ifndef CONFIG_8xx
 	set_dabr(0);
 	set_iabr(0);
+#endif
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
 		if (!bp->enabled)
@@ -412,6 +393,7 @@
 
 	cmd = inchar();
 	switch (cmd) {
+#ifndef CONFIG_8xx
 	case 'd':
 		mode = 7;
 		cmd = inchar();
@@ -436,6 +418,7 @@
 			iabr.address |= 3;
 		scanhex(&iabr.count);
 		break;
+#endif
 	case 'c':
 		if (!scanhex(&a)) {
 			/* clear all breakpoints */
@@ -1406,6 +1389,7 @@
 return NULL;	
 #if 0
 	cmp = simple_strtoul(c, &c, 8);
+	/* XXX crap, we don't want the whole of the rest of the map - paulus */
 	strcpy( last, strsep( &c, "\n"));
 	while ( c < (sysmap+sysmap_size) )
 	{
@@ -1414,7 +1398,7 @@
 			break;
 		strcpy( last, strsep( &c, "\n"));
 	}
-	return NULLlast;
+	return last;
 #endif	
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.3.99-pre6/linux/arch/sh/defconfig	Wed Apr 26 16:34:07 2000
+++ linux/arch/sh/defconfig	Mon May  8 22:00:41 2000
@@ -145,6 +145,7 @@
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.99-pre6/linux/arch/sparc/defconfig	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/defconfig	Mon May  8 22:00:41 2000
@@ -268,6 +268,7 @@
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.3.99-pre6/linux/arch/sparc/kernel/entry.S	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/kernel/entry.S	Mon May  8 22:00:01 2000
@@ -294,7 +294,7 @@
 real_irq_entry:
 	SAVE_ALL
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	.globl	patchme_maybe_smp_msg
 
 	cmp	%l7, 12
@@ -319,7 +319,7 @@
 
 	RESTORE_ALL
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* SMP per-cpu ticker interrupts are handled specially. */
 smp4m_ticker:
 	bne	real_irq_continue+4
@@ -479,7 +479,7 @@
 	/* FIXME */
 1:	b,a	1b
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	/* This routine handles illegal instructions and privileged
 	 * instruction attempts from user code.
@@ -1462,7 +1462,7 @@
 	b	C_LABEL(ret_sys_call)
 	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	.globl	C_LABEL(ret_from_smpfork)
 C_LABEL(ret_from_smpfork):
 	wr	%l0, PSR_ET, %psr
@@ -1806,7 +1806,7 @@
 	sethi	%hi(0x10c6), %o1
 	call	.umul
 	 or	%o1, %lo(0x10c6), %o1
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	sethi	%hi(C_LABEL(loops_per_sec)), %o3
 	call	.umul
 	 ld	[%o3 + %lo(C_LABEL(loops_per_sec))], %o1
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.3.99-pre6/linux/arch/sparc/kernel/head.S	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc/kernel/head.S	Mon May  8 22:00:01 2000
@@ -92,7 +92,7 @@
 _stext:
 start:
 C_LABEL(trapbase):
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 C_LABEL(trapbase_cpu0):
 #endif
 /* We get control passed to us here at t_zero. */
@@ -124,7 +124,7 @@
 t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
 t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
 	.globl	t_nmi
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 t_nmi:	NMI_TRAP                            /* Level 15 (NMI)                */
 #else
 t_nmi:	TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
@@ -203,7 +203,7 @@
 	.globl	C_LABEL(end_traptable)
 C_LABEL(end_traptable):
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Trap tables for the other cpus. */
 	.globl	C_LABEL(trapbase_cpu1), C_LABEL(trapbase_cpu2), C_LABEL(trapbase_cpu3)
 C_LABEL(trapbase_cpu1):
@@ -885,7 +885,7 @@
 	or	%g5, %g3, %g5
 	st	%g5, [%g4]
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Get our CPU id out of bootbus */
 	set     SUN4D_BOOTBUS_CPUID, %g3
 	lduba   [%g3] ASI_M_CTL, %g3
@@ -1030,7 +1030,7 @@
 		 */
 		set	C_LABEL(init_task_union), %g6
 		set	C_LABEL(current_set), %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		sethi	%hi(C_LABEL(boot_cpu_id4)), %g3
 		ldub	[%g3 + %lo(C_LABEL(boot_cpu_id4))], %g3
 		st	%g6, [%g2]
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/irq.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/sparc/kernel/irq.c	Mon May  8 22:00:01 2000
@@ -101,7 +101,7 @@
 {
 	int i, len = 0;
 	struct irqaction * action;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int j;
 #endif
 
@@ -115,7 +115,7 @@
 		if (!action) 
 		        continue;
 		len += sprintf(buf+len, "%3d: ", i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		len += sprintf(buf+len, "%10u ", kstat_irqs(i));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
@@ -195,7 +195,7 @@
         restore_flags(flags);
 }
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 unsigned int local_bh_count;
 unsigned int local_irq_count;
 
@@ -427,7 +427,7 @@
 	}
 }
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
@@ -456,13 +456,13 @@
 {
 	struct irqaction * action;
 	int cpu = smp_processor_id();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	extern void smp4m_irq_rotate(int cpu);
 #endif
 
 	irq_enter(cpu, irq);
 	disable_pil_irq(irq);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
 	if(irq < 10)
 		smp4m_irq_rotate(cpu);
@@ -505,7 +505,7 @@
 	struct irqaction *action;
 	unsigned long flags;
 	unsigned int cpu_irq;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	struct tt_entry *trap_table;
 	extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
 #endif
@@ -559,7 +559,7 @@
 	table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
 
 	INSTANTIATE(sparc_ttable)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	trap_table = &trapbase_cpu1; INSTANTIATE(trap_table)
 	trap_table = &trapbase_cpu2; INSTANTIATE(trap_table)
 	trap_table = &trapbase_cpu3; INSTANTIATE(trap_table)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/process.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc/kernel/process.c	Mon May  8 22:00:01 2000
@@ -45,7 +45,7 @@
 struct task_struct *last_task_used_math = NULL;
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define SUN4C_FAULT_HIGH 100
 
@@ -229,7 +229,7 @@
 	__show_backtrace(fp);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 void smp_show_backtrace_all_cpus(void)
 {
 	xc0((smpfunc_t) show_backtrace);
@@ -320,7 +320,7 @@
  */
 void exit_thread(void)
 {
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
 	if(current->flags & PF_USEDFPU) {
@@ -329,7 +329,7 @@
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
 		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		last_task_used_math = NULL;
 #else
 		current->flags &= ~PF_USEDFPU;
@@ -343,7 +343,7 @@
 
 	/* No new signal delivery by default */
 	current->thread.new_signal = 0;
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
 	if(current->flags & PF_USEDFPU) {
@@ -352,7 +352,7 @@
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
 		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		last_task_used_math = NULL;
 #else
 		current->flags &= ~PF_USEDFPU;
@@ -453,7 +453,7 @@
  *       allocate the task_struct and kernel stack in
  *       do_fork().
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern void ret_from_smpfork(void);
 #else
 extern void ret_from_syscall(void);
@@ -466,7 +466,7 @@
 	struct reg_window *new_stack;
 	unsigned long stack_offset;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
 	if(current->flags & PF_USEDFPU) {
@@ -474,7 +474,7 @@
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&p->thread.float_regs[0], &p->thread.fsr,
 		       &p->thread.fpqueue[0], &p->thread.fpqdepth);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		current->flags &= ~PF_USEDFPU;
 #endif
 	}
@@ -490,7 +490,7 @@
 	copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
 
 	p->thread.ksp = (unsigned long) new_stack;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	p->thread.kpc = (((unsigned long) ret_from_smpfork) - 0x8);
 	p->thread.kpsr = current->thread.fork_kpsr | PSR_PIL;
 #else
@@ -604,7 +604,7 @@
 		fpregs->pr_q_entrysize = 8;
 		return 1;
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (current->flags & PF_USEDFPU) {
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/setup.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/kernel/setup.c	Mon May  8 22:00:01 2000
@@ -80,7 +80,7 @@
 {
 	unsigned long prom_tbr, flags;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	global_irq_holder = NO_PROC_ID;
 	*((unsigned char *)&global_irq_lock) = 0;
 	*((unsigned char *)&global_bh_lock) = 0;
@@ -478,7 +478,7 @@
             "type\t\t: %s\n"
 	    "ncpus probed\t: %d\n"
 	    "ncpus active\t: %d\n"
-#ifndef __SMP__
+#ifndef CONFIG_SMP
             "BogoMips\t: %lu.%02lu\n"
 #endif
 	    ,
@@ -487,15 +487,15 @@
             romvec->pv_romvers, prom_rev, romvec->pv_printrev >> 16, (short)romvec->pv_printrev,
             &cputypval,
 	    linux_num_cpus, smp_num_cpus
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	    , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
 	    );
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len += smp_bogo_info(buffer + len);
 #endif
 	len += mmu_info(buffer + len);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len += smp_info(buffer + len);
 #endif
 	return len;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/signal.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/kernel/signal.c	Mon May  8 22:00:01 2000
@@ -7,6 +7,7 @@
  *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -197,7 +198,7 @@
 restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
 	int err;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (current->flags & PF_USEDFPU)
 		regs->psr &= ~PSR_EF;
 #else
@@ -554,7 +555,7 @@
 save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
 	int err = 0;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (current->flags & PF_USEDFPU) {
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/sparc_ksyms.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon May  8 22:00:01 2000
@@ -73,7 +73,7 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern spinlock_t kernel_flag;
 #endif
 
@@ -108,7 +108,7 @@
 EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
 EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 #endif
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(__global_sti);
@@ -135,7 +135,7 @@
 EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
 
 /* IRQ implementation. */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(global_irq_lock);
@@ -158,7 +158,7 @@
 /* EXPORT_SYMBOL(iounit_map_dma_page); */
 
 /* Btfixup stuff cannot have versions, it would be complicated too much */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(___xchg32));
 #else
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__smp_processor_id));
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/sun4c_irq.c	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/kernel/sun4c_irq.c	Mon May  8 22:00:01 2000
@@ -182,7 +182,7 @@
 	claim_ticker14(NULL, PROFILE_IRQ, 0);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static void sun4c_nop(void) {}
 #endif
 
@@ -222,7 +222,7 @@
 	BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
 	init_timers = sun4c_init_timers;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/sun4d_irq.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/kernel/sun4d_irq.c	Mon May  8 22:00:01 2000
@@ -6,6 +6,7 @@
  *  Heavily based on arch/sparc/kernel/irq.c.
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -47,7 +48,7 @@
 extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
 unsigned char cpu_leds[32];
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 unsigned char sbus_tid[32];
 #endif
 
@@ -67,7 +68,7 @@
 };
 
 static int nsbi;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 spinlock_t sun4d_imsk_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
@@ -75,7 +76,7 @@
 {
 	int i, j = 0, k = 0, len = 0, sbusl;
 	struct irqaction * action;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int x;
 #endif
 
@@ -94,7 +95,7 @@
 			continue;
 		}
 found_it:	len += sprintf(buf+len, "%3d: ", i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		len += sprintf(buf+len, "%10u ", kstat_irqs(i));
 #else
 		for (x = 0; x < smp_num_cpus; x++)
@@ -320,13 +321,13 @@
 
 static void sun4d_disable_irq(unsigned int irq)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int tid = sbus_tid[(irq >> 5) - 1];
 	unsigned long flags;
 #endif	
 	
 	if (irq < NR_IRQS) return;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	spin_lock_irqsave(&sun4d_imsk_lock, flags);
 	cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
 	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
@@ -337,13 +338,13 @@
 
 static void sun4d_enable_irq(unsigned int irq)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int tid = sbus_tid[(irq >> 5) - 1];
 	unsigned long flags;
 #endif	
 	
 	if (irq < NR_IRQS) return;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	spin_lock_irqsave(&sun4d_imsk_lock, flags);
 	cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
 	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
@@ -352,7 +353,7 @@
 #endif
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static void sun4d_set_cpu_int(int cpu, int level)
 {
 	sun4d_send_ipi(cpu, level);
@@ -441,7 +442,7 @@
 
 	/* Map the User Timer registers. */
 	memset(&r, 0, sizeof(r));
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
 #else
 	r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
@@ -469,7 +470,7 @@
 	for(cpu = 0; cpu < linux_num_cpus; cpu++)
 		sun4d_load_profile_irq((linux_cpus[cpu].mid >> 3), 0);
 		
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	{
 		unsigned long flags;
 		extern unsigned long lvl14_save[4];
@@ -507,7 +508,7 @@
 	sbus_actions = (struct sbus_action *)kmalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
 	memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
 	for_each_sbus(sbus) {
-#ifdef __SMP__	
+#ifdef CONFIG_SMP	
 		extern unsigned char boot_cpu_id;
 		
 		set_sbi_tid(sbus->devid, boot_cpu_id << 3);
@@ -544,7 +545,7 @@
 	BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM);
 	init_timers = sun4d_init_timers;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/sun4m_irq.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/kernel/sun4m_irq.c	Mon May  8 22:00:01 2000
@@ -9,6 +9,7 @@
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -167,7 +168,7 @@
 	sun4m_interrupts->clear = cpu_pil_to_imask[pil];
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static void sun4m_send_ipi(int cpu, int level)
 {
 	unsigned long mask;
@@ -286,7 +287,7 @@
 	} else {
 		sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	{
 		unsigned long flags;
 		extern unsigned long lvl14_save[4];
@@ -374,7 +375,7 @@
 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
 	init_timers = sun4m_init_timers;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/sys_sunos.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.121 2000/04/13 00:55:48 davem Exp $
+/* $Id: sys_sunos.c,v 1.122 2000/04/27 02:49:03 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/time.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/kernel/time.c	Mon May  8 22:00:01 2000
@@ -113,7 +113,7 @@
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(!user_mode(regs))
 		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/traps.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/traps.c	Mon May  8 22:00:01 2000
@@ -9,6 +9,7 @@
  * I hate traps on the sparc, grrr...
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -243,7 +244,7 @@
 
 	put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
 	regs->psr |= PSR_EF;
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(last_task_used_math == current)
 		goto out;
 	if(last_task_used_math) {
@@ -269,7 +270,7 @@
 	}
 	current->flags |= PF_USEDFPU;
 #endif
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 out:
 #endif
 	unlock_kernel();
@@ -289,7 +290,7 @@
 	siginfo_t info;
 	unsigned long fsr;
 	int ret = 0;
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	struct task_struct *fpt = last_task_used_math;
 #else
 	struct task_struct *fpt = current;
@@ -300,7 +301,7 @@
 	 * error into our fake static buffer and hope it don't
 	 * happen again.  Thank you crashme...
 	 */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if(!fpt) {
 #else
         if(!(fpt->flags & PF_USEDFPU)) {
@@ -345,7 +346,7 @@
 	}
 	/* nope, better SIGFPE the offending process... */
 	       
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	fpt->flags &= ~PF_USEDFPU;
 #endif
 	if(psr & PSR_PS) {
@@ -382,7 +383,7 @@
 			info.si_code = FPE_FLTRES;
 	}
 	send_sig_info(SIGFPE, &info, fpt);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	last_task_used_math = NULL;
 #endif
 	regs->psr &= ~PSR_EF;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c
--- v2.3.99-pre6/linux/arch/sparc/kernel/unaligned.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/unaligned.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.21 2000/03/15 08:50:16 anton Exp $
+/* $Id: unaligned.c,v 1.22 2000/04/29 08:05:21 anton Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -351,10 +351,12 @@
         	} else
                 	printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
 	        printk(KERN_ALERT " at virtual address %08lx\n",address);
-        	printk(KERN_ALERT "current->mm->context = %08lx\n",
-	               (unsigned long) current->mm->context);
-	        printk(KERN_ALERT "current->mm->pgd = %08lx\n",
-        	       (unsigned long) current->mm->pgd);
+		printk(KERN_ALERT "current->{mm,active_mm}->context = %08lx\n",
+			(current->mm ? current->mm->context :
+			current->active_mm->context));
+		printk(KERN_ALERT "current->{mm,active_mm}->pgd = %08lx\n",
+			(current->mm ? (unsigned long) current->mm->pgd :
+			(unsigned long) current->active_mm->pgd));
 	        die_if_kernel("Oops", regs);
 		/* Not reached */
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S
--- v2.3.99-pre6/linux/arch/sparc/lib/atomic.S	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/lib/atomic.S	Mon May  8 22:00:01 2000
@@ -3,6 +3,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
@@ -13,7 +14,7 @@
 	.globl  __atomic_begin
 __atomic_begin:
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	.globl	___xchg32_sun4c
 ___xchg32_sun4c:
 	rd	%psr, %g3
@@ -51,7 +52,7 @@
 	or	%g3, PSR_PIL, %g7	! Disable interrupts
 	wr	%g7, 0x0, %psr		! Set %psr
 	nop; nop; nop;			! Let the bits set
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub	[%g1 + 3], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
 	bne	1b			! Nope...
@@ -77,7 +78,7 @@
 	or	%g3, PSR_PIL, %g7	! Disable interrupts
 	wr	%g7, 0x0, %psr		! Set %psr
 	nop; nop; nop;			! Let the bits set
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub	[%g1 + 3], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
 	bne	1b			! Nope...
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S
--- v2.3.99-pre6/linux/arch/sparc/lib/bitops.S	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/lib/bitops.S	Mon May  8 22:00:01 2000
@@ -3,6 +3,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
@@ -27,7 +28,7 @@
 	or	%g3, PSR_PIL, %g5
 	wr	%g5, 0x0, %psr
 	nop; nop; nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	set	C_LABEL(bitops_spinlock), %g5
 2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
@@ -36,7 +37,7 @@
 	 ld	[%g1], %g7
 	or	%g7, %g2, %g5
 	and	%g7, %g2, %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	st	%g5, [%g1]
 	set	C_LABEL(bitops_spinlock), %g5
 	stb	%g0, [%g5]
@@ -56,7 +57,7 @@
 	or	%g3, PSR_PIL, %g5
 	wr	%g5, 0x0, %psr
 	nop; nop; nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	set	C_LABEL(bitops_spinlock), %g5
 2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
@@ -65,7 +66,7 @@
 	 ld	[%g1], %g7
 	andn	%g7, %g2, %g5
 	and	%g7, %g2, %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	st	%g5, [%g1]
 	set	C_LABEL(bitops_spinlock), %g5
 	stb	%g0, [%g5]
@@ -85,7 +86,7 @@
 	or	%g3, PSR_PIL, %g5
 	wr	%g5, 0x0, %psr
 	nop; nop; nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	set	C_LABEL(bitops_spinlock), %g5
 2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
@@ -94,7 +95,7 @@
 	 ld	[%g1], %g7
 	xor	%g7, %g2, %g5
 	and	%g7, %g2, %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	st	%g5, [%g1]
 	set	C_LABEL(bitops_spinlock), %g5
 	stb	%g0, [%g5]
@@ -114,7 +115,7 @@
 	or	%g3, PSR_PIL, %g5
 	wr	%g5, 0x0, %psr
 	nop; nop; nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	set	C_LABEL(bitops_spinlock), %g5
 2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
@@ -123,7 +124,7 @@
 	 ldub	[%g1], %g7
 	or	%g7, %g2, %g5
 	and	%g7, %g2, %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	stb	%g5, [%g1]
 	set	C_LABEL(bitops_spinlock), %g5
 	stb	%g0, [%g5]
@@ -142,7 +143,7 @@
 	or	%g3, PSR_PIL, %g5
 	wr	%g5, 0x0, %psr
 	nop; nop; nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	set	C_LABEL(bitops_spinlock), %g5
 2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
 	orcc	%g7, 0x0, %g0		! Did we get it?
@@ -151,7 +152,7 @@
 	 ldub	[%g1], %g7
 	andn	%g7, %g2, %g5
 	and	%g7, %g2, %g2
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	stb	%g5, [%g1]
 	set	C_LABEL(bitops_spinlock), %g5
 	stb	%g0, [%g5]
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/lib/rwsem.S linux/arch/sparc/lib/rwsem.S
--- v2.3.99-pre6/linux/arch/sparc/lib/rwsem.S	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc/lib/rwsem.S	Mon May  8 22:00:01 2000
@@ -4,6 +4,7 @@
  * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 
@@ -21,7 +22,7 @@
 	nop
 	nop
 	nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub		[%g1 + 4], %g7
 	tst		%g7
 	bne		1b
@@ -72,7 +73,7 @@
 	sethi		%hi(0x01000000), %g2
 	nop
 	nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub		[%g1 + 4], %g7
 	tst		%g7
 	bne		1b
@@ -123,7 +124,7 @@
 	nop
 	nop
 	nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub		[%g1 + 4], %g7
 	tst		%g7
 	bne		1b
@@ -168,7 +169,7 @@
 	sethi		%hi(0x01000000), %g2
 	nop
 	nop
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 1:	ldstub		[%g1 + 4], %g7
 	tst		%g7
 	bne		1b
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/btfixup.c linux/arch/sparc/mm/btfixup.c
--- v2.3.99-pre6/linux/arch/sparc/mm/btfixup.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/mm/btfixup.c	Mon May  8 22:00:01 2000
@@ -322,7 +322,7 @@
 		} else
 			p = q + count;
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all);
 #else
 	flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.99-pre6/linux/arch/sparc/mm/fault.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/mm/fault.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.115 2000/04/25 04:13:25 davem Exp $
+/* $Id: fault.c,v 1.116 2000/05/03 06:37:03 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -249,12 +249,17 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	{
-		int fault = handle_mm_fault(mm, vma, address, write);
-		if (fault < 0)
-			goto out_of_memory;
-		if (!fault)
-			goto do_sigbus;
+	switch (handle_mm_fault(mm, vma, address, write)) {
+	case 1:
+		current->min_flt++;
+		break;
+	case 2:
+		current->maj_flt++;
+		break;
+	case 0:
+		goto do_sigbus;
+	default:
+		goto out_of_memory;
 	}
 	up(&mm->mmap_sem);
 	return;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S
--- v2.3.99-pre6/linux/arch/sparc/mm/hypersparc.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/hypersparc.S	Mon May  8 22:00:01 2000
@@ -9,6 +9,7 @@
 #include <asm/asi.h>
 #include <asm/page.h>
 #include <asm/pgtsrmmu.h>
+#include <linux/config.h>
 #include <linux/init.h>
 
 #define WINDOW_FLUSH(tmp1, tmp2)					\
@@ -47,7 +48,7 @@
 
 	/* We expand the window flush to get maximum performance. */
 hypersparc_flush_cache_mm:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
 	be	hypersparc_flush_cache_mm_out
@@ -84,7 +85,7 @@
 
 	/* The things we do for performance... */
 hypersparc_flush_cache_range:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
 	be	hypersparc_flush_cache_range_out
@@ -174,7 +175,7 @@
 hypersparc_flush_cache_page:
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 	ld	[%o0 + AOFF_mm_context], %g2
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%g2, -1
 	be	hypersparc_flush_cache_page_out
 #endif
@@ -282,7 +283,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o1
 	lda	[%g1] ASI_M_MMUREGS, %g5
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o1, -1
 	be	hypersparc_flush_tlb_mm_out
 #endif
@@ -297,7 +298,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	hypersparc_flush_tlb_range_out
 #endif
@@ -320,7 +321,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	hypersparc_flush_tlb_page_out
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.3.99-pre6/linux/arch/sparc/mm/init.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/mm/init.c	Mon May  8 22:00:01 2000
@@ -86,7 +86,7 @@
 	printk("%ld pages of RAM\n", totalram_pages);
 	printk("%d free pages\n", nr_free_pages());
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
 		printk("%ld entries in page dir cache\n",pgd_cache_size);
 #endif	
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.99-pre6/linux/arch/sparc/mm/srmmu.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc/mm/srmmu.c	Mon May  8 22:00:01 2000
@@ -57,7 +57,7 @@
 
 extern unsigned long last_valid_pfn;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define FLUSH_BEGIN(mm)
 #define FLUSH_END
 #else
@@ -77,7 +77,7 @@
 #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
 int flush_page_for_dma_global = 1;
 #define flush_chunk(chunk) BTFIXUP_CALL(flush_chunk)(chunk)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 BTFIXUPDEF_CALL(void, local_flush_page_for_dma, unsigned long)
 
 #define local_flush_page_for_dma(page) BTFIXUP_CALL(local_flush_page_for_dma)(page)
@@ -513,7 +513,7 @@
 
 static void srmmu_quick_kernel_fault(unsigned long address)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	printk("CPU[%d]: Kernel faults at addr=0x%08lx\n",
 	       smp_processor_id(), address);
 	while (1) ;
@@ -1464,7 +1464,7 @@
 {
 	int nd, cache_lines;
 	char node_str[128];
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int cpu = 0;
 	unsigned long max_size = 0;
 	unsigned long min_line_size = 0x10000000;
@@ -1488,7 +1488,7 @@
 
 			vac_cache_size = cache_lines * vac_line_size;
 			vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 			if(vac_cache_size > max_size)
 				max_size = vac_cache_size;
 			if(vac_line_size < min_line_size)
@@ -1505,7 +1505,7 @@
 		prom_printf("No CPU nodes found, halting.\n");
 		prom_halt();
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	vac_cache_size = max_size;
 	vac_line_size = min_line_size;
 	vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
@@ -1998,7 +1998,7 @@
 	mreg &= ~(VIKING_ACENABLE);
 	srmmu_set_mmureg(mreg);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Avoid unnecessary cross calls. */
 	BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all);
 	BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm);
@@ -2052,7 +2052,7 @@
 	BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NORM);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (sparc_cpu_model == sun4d) {
 		BTFIXUPSET_CALL(flush_tlb_all, sun4dsmp_flush_tlb_all, BTFIXUPCALL_NORM);
 		BTFIXUPSET_CALL(flush_tlb_mm, sun4dsmp_flush_tlb_mm, BTFIXUPCALL_NORM);
@@ -2263,7 +2263,7 @@
 	PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /* Local cross-calls. */
 static void smp_flush_page_for_dma(unsigned long page)
 {
@@ -2299,7 +2299,7 @@
 	pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
 	
 	/* Functions */
-#ifndef __SMP__	
+#ifndef CONFIG_SMP	
 	BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2);
 #endif
 	BTFIXUPSET_CALL(get_pte_fast, srmmu_get_pte_fast, BTFIXUPCALL_RETINT(0));
@@ -2383,7 +2383,7 @@
 	get_srmmu_type();
 	patch_window_trap_handlers();
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* El switcheroo... */
 
 	BTFIXUPCOPY_CALL(local_flush_cache_all, flush_cache_all);
@@ -2417,7 +2417,7 @@
 		ld_mmu_iounit();
 	else
 		ld_mmu_iommu();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (sparc_cpu_model == sun4d)
 		sun4d_init_smp();
 	else
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.99-pre6/linux/arch/sparc/mm/sun4c.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc/mm/sun4c.c	Mon May  8 22:00:01 2000
@@ -2625,7 +2625,7 @@
 		    _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 	
 	/* Functions */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
 #endif
 	BTFIXUPSET_CALL(get_pte_fast, sun4c_pte_get, BTFIXUPCALL_NORM);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S
--- v2.3.99-pre6/linux/arch/sparc/mm/swift.S	Sun Feb 13 19:29:03 2000
+++ linux/arch/sparc/mm/swift.S	Mon May  8 22:00:01 2000
@@ -4,6 +4,7 @@
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  */
 
+#include <linux/config.h>
 #include <asm/psr.h>
 #include <asm/asi.h>
 #include <asm/page.h>
@@ -64,7 +65,7 @@
 
 	.globl	swift_flush_cache_mm
 swift_flush_cache_mm:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_mm_out
@@ -131,7 +132,7 @@
 swift_flush_cache_page:
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 70:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_page_out
@@ -237,7 +238,7 @@
 	.globl	swift_flush_tlb_all
 swift_flush_tlb_mm:
 swift_flush_tlb_range:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_tlb_all_out
@@ -255,7 +256,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	swift_flush_tlb_page_out
 	 nop
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S
--- v2.3.99-pre6/linux/arch/sparc/mm/tsunami.S	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/mm/tsunami.S	Mon May  8 22:00:01 2000
@@ -4,6 +4,7 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 #include <asm/asi.h>
@@ -37,7 +38,7 @@
 tsunami_flush_cache_mm:
 tsunami_flush_cache_range:
 	ld	[%o0 + AOFF_mm_context], %g2
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%g2, -1
 	be	tsunami_flush_cache_out
 #endif
@@ -60,7 +61,7 @@
 	/* More slick stuff... */
 tsunami_flush_tlb_mm:
 tsunami_flush_tlb_range:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	tsunami_flush_tlb_out
@@ -83,7 +84,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	tsunami_flush_tlb_page_out
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S
--- v2.3.99-pre6/linux/arch/sparc/mm/viking.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc/mm/viking.S	Mon May  8 22:00:01 2000
@@ -6,6 +6,7 @@
  * Copyright (C) 1999  Pavel Semerad  (semerad@ss1000.ms.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 #include <asm/asi.h>
@@ -16,7 +17,7 @@
 #include <asm/cprefix.h>
 #include <asm/btfixup.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	.data
 	.align	4
 sun4dsmp_flush_tlb_spin:
@@ -124,12 +125,12 @@
 	 restore %g0, %g0, %g0;
 
 viking_flush_cache_page:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 #endif
 viking_flush_cache_mm:
 viking_flush_cache_range:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
 	bne	viking_flush_cache_all
@@ -151,7 +152,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o1
 	lda	[%g1] ASI_M_MMUREGS, %g5
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o1, -1
 	be	1f
 #endif
@@ -160,7 +161,7 @@
 	sta	%g0, [%g2] ASI_M_FLUSH_PROBE
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 1:	retl
 	 nop
 #endif
@@ -169,7 +170,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	2f
 #endif
@@ -184,7 +185,7 @@
 	 sta	%g0, [%o1] ASI_M_FLUSH_PROBE
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 2:	retl
 	 nop
 #endif
@@ -194,7 +195,7 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	1f
 #endif
@@ -203,7 +204,7 @@
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 1:	retl
 	 nop
 #endif
@@ -214,7 +215,7 @@
 	retl
 	 nop
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	.globl	sun4dsmp_flush_tlb_all, sun4dsmp_flush_tlb_mm
 	.globl	sun4dsmp_flush_tlb_range, sun4dsmp_flush_tlb_page
 sun4dsmp_flush_tlb_all:
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.99-pre6/linux/arch/sparc64/config.in	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/config.in	Mon May  8 22:21:58 2000
@@ -210,6 +210,9 @@
          dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
          dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
          dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
+         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+            dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+         fi
       fi
       tristate '  SLIP (serial line) support' CONFIG_SLIP
       if [ "$CONFIG_SLIP" != "n" ]; then
@@ -280,6 +283,12 @@
       dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
    fi
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'XFree86 DRI support'
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+# dep_tristate '  Creator/Creator3D/Elite3D' CONFIG_DRM_FFB $CONFIG_DRM
 endmenu
 
 source fs/Config.in
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.99-pre6/linux/arch/sparc64/defconfig	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/defconfig	Mon May  8 22:21:58 2000
@@ -324,6 +324,7 @@
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -366,6 +367,11 @@
 # CONFIG_VIDEO_BT848 is not set
 
 #
+# XFree86 DRI support
+#
+CONFIG_DRM=y
+
+#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -391,6 +397,7 @@
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/cpu.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/kernel/cpu.c	Mon May  8 22:00:01 2000
@@ -4,6 +4,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -48,7 +49,7 @@
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 char *sparc_cpu_type[64] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
 char *sparc_fpu_type[64] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.3.99-pre6/linux/arch/sparc64/kernel/head.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/sparc64/kernel/head.S	Mon May  8 22:00:01 2000
@@ -366,7 +366,7 @@
 
 	/* Setup Interrupt globals */
 	wrpr	%o1, (PSTATE_IG|PSTATE_IE), %pstate
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	sethi	%hi(__up_workvec), %g5
 	or	%g5, %lo(__up_workvec), %g6
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/ioctl32.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon May  8 22:21:58 2000
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.88 2000/04/14 10:10:34 davem Exp $
+/* $Id: ioctl32.c,v 1.89 2000/05/06 10:38:42 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -31,6 +31,7 @@
 #include <linux/fd.h>
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
 #include <linux/loop.h>
@@ -2763,6 +2764,9 @@
 COMPATIBLE_IOCTL(PPPIOCCONNECT)
 COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD);
+COMPATIBLE_IOCTL(PPPOEIOCDFWD);
 /* CDROM stuff */
 COMPATIBLE_IOCTL(CDROMPAUSE)
 COMPATIBLE_IOCTL(CDROMRESUME)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/irq.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/irq.c	Mon May  8 22:00:01 2000
@@ -36,7 +36,7 @@
 #define SA_IMAP_MASKED		0x100
 #define SA_DMA_SYNC		0x200
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static void distribute_irqs(void);
 #endif
 
@@ -55,7 +55,7 @@
 
 struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
 #define irq_work(__cpu, __pil)	&(__up_workvec[(void)(__cpu), (__pil)])
 #else
@@ -79,7 +79,7 @@
 {
 	int i, len = 0;
 	struct irqaction *action;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int j;
 #endif
 
@@ -87,7 +87,7 @@
 		if(!(action = *(i + irq_action)))
 			continue;
 		len += sprintf(buf + len, "%3d: ", i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		len += sprintf(buf + len, "%10u ", kstat_irqs(i));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
@@ -409,7 +409,7 @@
 	}
 	restore_flags(flags);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	distribute_irqs();
 #endif
 	return 0;
@@ -540,7 +540,7 @@
 /* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
  * lives in the brlock table for cache reasons.
  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 unsigned int local_irq_count;
 unsigned int local_bh_count;
 #else
@@ -679,7 +679,7 @@
 	}
 }
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 void catch_disabled_ivec(struct pt_regs *regs)
 {
@@ -709,7 +709,7 @@
 {
 	struct ino_bucket *bp, *nbp;
 	int cpu = smp_processor_id();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	extern int this_is_starfire;
 	int should_forward = (this_is_starfire == 0	&&
 			      irq < 10			&&
@@ -732,7 +732,7 @@
 	}
 #endif
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	/*
 	 * Check for TICK_INT on level 14 softint.
 	 */
@@ -745,7 +745,7 @@
 	kstat.irqs[cpu][irq]++;
 
 	/* Sliiiick... */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	bp = ((irq != 0) ?
 	      __bucket(xchg32(irq_work(cpu, irq), 0)) :
 	      &pil0_dummy_bucket);
@@ -771,7 +771,7 @@
 			}
 			/* Only the dummy bucket lacks IMAP/ICLR. */
 			if(bp->pil != 0) {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 				/* Ok, here is what is going on:
 				 * 1) Retargeting IRQs on Starfire is very
 				 *    expensive so just forget about it on them.
@@ -915,7 +915,7 @@
 
 	restore_flags(flags);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	distribute_irqs();
 #endif
 	return 0;
@@ -941,14 +941,14 @@
 	unsigned long pstate;
 	extern unsigned long timer_tick_offset;
 	int node, err;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	extern void smp_tick_init(void);
 #endif
 
 	node = linux_cpus[0].prom_node;
 	*clock = prom_getint(node, "clock-frequency");
 	timer_tick_offset = *clock / HZ;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_tick_init();
 #endif
 
@@ -1015,7 +1015,7 @@
 	sti();
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
 	extern int this_is_starfire;
@@ -1142,7 +1142,7 @@
 		map_prom_timers();
 		kill_prom_timer();
 		memset(&ivector_table[0], 0, sizeof(ivector_table));
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		memset(&__up_workvec[0], 0, sizeof(__up_workvec));
 #endif
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/pci_common.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/pci_common.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.11 2000/04/26 10:48:02 davem Exp $
+/* $Id: pci_common.c,v 1.12 2000/05/01 06:32:49 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -497,10 +497,10 @@
 		       pwalk->bus->number != pbm->pci_first_busno)
 			pwalk = pwalk->bus->self;
 
-		bus_pcp = pwalk->bus->self->sysdata;
-
+		bus_pcp = pwalk->sysdata;
 		pregs = bus_pcp->prom_regs;
-		offset = prom_getint(bus_pcp->prom_node,
+
+		offset = prom_getint(dev_pcp->prom_node,
 				     "fcode-rom-offset");
 
 		/* Did PROM know better and assign an interrupt other
@@ -509,8 +509,8 @@
 		 * correct 'interrupts' property, unless it is quadhme.
 		 */
 		if (offset == -1 ||
-		    !strcmp(bus_pcp->prom_name, "SUNW,qfe") ||
-		    !strcmp(bus_pcp->prom_name, "qfe")) {
+		    !strcmp(dev_pcp->prom_name, "SUNW,qfe") ||
+		    !strcmp(dev_pcp->prom_name, "qfe")) {
 			/*
 			 * No, use low slot number bits of child as IRQ line.
 			 */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/process.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/process.c	Mon May  8 22:00:01 2000
@@ -42,7 +42,7 @@
 
 /* #define VERBOSE_SHOWREGS */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 /*
  * the idle loop on a Sparc... ;)
@@ -259,13 +259,13 @@
 	} while ((size -= sizeof(unsigned)));
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
 void __show_regs(struct pt_regs * regs)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	unsigned long flags;
 
 	spin_lock_irqsave(&regdump_lock, flags);
@@ -287,7 +287,7 @@
 	       regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
 	       regs->u_regs[15]);
 	show_regwindow(regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	spin_unlock_irqrestore(&regdump_lock, flags);
 #endif
 }
@@ -317,7 +317,7 @@
 	extern long etrap, etraptl1;
 #endif
 	__show_regs(regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	{
 		extern void smp_report_regs(void);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/setup.c	Mon May  8 22:00:01 2000
@@ -603,7 +603,7 @@
             "type\t\t: sun4u\n"
 	    "ncpus probed\t: %d\n"
 	    "ncpus active\t: %d\n"
-#ifndef __SMP__
+#ifndef CONFIG_SMP
             "BogoMips\t: %lu.%02lu\n"
 #endif
 	    ,
@@ -611,15 +611,15 @@
             sparc_fpu_type[cpuid],
             prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
 	    linux_num_cpus, smp_num_cpus
-#ifndef __SMP__
+#ifndef CONFIG_SMP
             , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
 	    );
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len += smp_bogo(buffer + len);
 #endif
 	len += mmu_info(buffer + len);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len += smp_info(buffer + len);
 #endif
 #undef ZS_LOG
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/sparc64_ksyms.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon May  8 22:00:01 2000
@@ -89,7 +89,7 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
 #ifdef SPIN_LOCK_DEBUG
@@ -117,7 +117,7 @@
 { (unsigned long) &__sparc_priv_ ## sym, "__" #sym }
 
 /* used by various drivers */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #ifndef SPIN_LOCK_DEBUG
 /* Out of line rw-locking implementation. */
 EXPORT_SYMBOL_PRIVATE(read_lock);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sparc.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.38 2000/04/13 07:30:34 jj Exp $
+/* $Id: sys_sparc.c,v 1.39 2000/04/27 02:49:03 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon May  8 22:21:57 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.145 2000/04/13 07:30:34 jj Exp $
+/* $Id: sys_sparc32.c,v 1.146 2000/05/09 04:48:34 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1584,25 +1584,23 @@
 
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode *inode = dentry->d_inode;
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		struct inode *inode = nd.dentry->d_inode;
 
 		if (inode->i_op &&
 		    inode->i_op->revalidate)
-			error = inode->i_op->revalidate(dentry);
+			error = inode->i_op->revalidate(nd.dentry);
 		else
 			error = 0;
 		if (!error)
 			error = cp_new_stat32(inode, statbuf);
 
-		dput(dentry);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -1610,25 +1608,23 @@
 
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	struct dentry *dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode *inode = dentry->d_inode;
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		struct inode *inode = nd.dentry->d_inode;
 
 		if (inode->i_op &&
 		    inode->i_op->revalidate)
-			error = inode->i_op->revalidate(dentry);
+			error = inode->i_op->revalidate(nd.dentry);
 		else
 			error = 0;
 		if (!error)
 			error = cp_new_stat32(inode, statbuf);
 
-		dput(dentry);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/sys_sunos32.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.45 2000/04/13 00:55:49 davem Exp $
+/* $Id: sys_sunos32.c,v 1.46 2000/04/27 02:49:03 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/time.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/kernel/time.c	Mon May  8 22:00:01 2000
@@ -102,7 +102,7 @@
 	write_lock(&xtime_lock);
 
 	do {
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		if ((regs->tstate & TSTATE_PRIV) != 0)
 			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
 #endif
@@ -155,7 +155,7 @@
 	write_unlock(&xtime_lock);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 void timer_tick_interrupt(struct pt_regs *regs)
 {
 	write_lock(&xtime_lock);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/traps.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/traps.c	Mon May  8 22:00:01 2000
@@ -688,7 +688,7 @@
 		instruction_dump ((unsigned int *) regs->tpc);
 	} else
 		user_instruction_dump ((unsigned int *) regs->tpc);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_report_regs();
 #endif
                                                 	
@@ -854,7 +854,7 @@
 #ifdef CONFIG_EC_FLUSH_TRAP
 void cache_flush_trap(struct pt_regs *regs)
 {
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	unsigned node = linux_cpus[get_cpuid()].prom_node;
 #else
 #error cache_flush_trap not supported on sparc64/SMP yet
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.3.99-pre6/linux/arch/sparc64/kernel/ttable.S	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/ttable.S	Mon May  8 22:00:01 2000
@@ -45,7 +45,7 @@
 tl0_irq9:	TRAP_IRQ(handler_irq, 9)  TRAP_IRQ(handler_irq, 10)
 tl0_irq11:	TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
 tl0_irq13:	TRAP_IRQ(handler_irq, 13)
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 tl0_irq14:	TRAP_IRQ(handler_irq, 14)
 #else
 tl0_irq14:	TICK_SMP_IRQ
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c
--- v2.3.99-pre6/linux/arch/sparc64/kernel/unaligned.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/unaligned.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.19 2000/03/16 11:53:05 jj Exp $
+/* $Id: unaligned.c,v 1.20 2000/04/29 08:05:21 anton Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -360,10 +360,12 @@
         	} else
                 	printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
 	        printk(KERN_ALERT " at virtual address %016lx\n",address);
-        	printk(KERN_ALERT "current->mm->context = %016lx\n",
-	               (unsigned long) current->mm->context);
-	        printk(KERN_ALERT "current->mm->pgd = %016lx\n",
-        	       (unsigned long) current->mm->pgd);
+		printk(KERN_ALERT "current->{mm,active_mm}->context = %016lx\n",
+			(current->mm ? current->mm->context :
+			current->active_mm->context));
+		printk(KERN_ALERT "current->{mm,active_mm}->pgd = %016lx\n",
+			(current->mm ? (unsigned long) current->mm->pgd :
+			(unsigned long) current->active_mm->pgd));
 	        die_if_kernel("Oops", regs);
 		/* Not reached */
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- v2.3.99-pre6/linux/arch/sparc64/lib/debuglocks.c	Tue Feb  1 01:35:43 2000
+++ linux/arch/sparc64/lib/debuglocks.c	Mon May  8 22:00:01 2000
@@ -4,12 +4,13 @@
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <asm/system.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 /* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
 #ifdef SPIN_LOCK_DEBUG
@@ -275,4 +276,4 @@
 }
 
 #endif /* SPIN_LOCK_DEBUG */
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.99-pre6/linux/arch/sparc64/mm/fault.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/mm/fault.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.47 2000/04/25 04:13:25 davem Exp $
+/* $Id: fault.c,v 1.48 2000/05/03 06:37:03 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)
@@ -295,15 +295,19 @@
 			goto bad_area;
 	}
 
-	{
-		int fault = handle_mm_fault(mm, vma,
-					    address, (fault_code & FAULT_CODE_WRITE));
-
-		if (fault < 0)
-			goto out_of_memory;
-		if (!fault)
-			goto do_sigbus;
+	switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) {
+	case 1:
+		current->min_flt++;
+		break;
+	case 2:
+		current->maj_flt++;
+		break;
+	case 0:
+		goto do_sigbus;
+	default:
+		goto out_of_memory;
 	}
+
 	up(&mm->mmap_sem);
 	goto fault_done;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.99-pre6/linux/arch/sparc64/mm/init.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/mm/init.c	Mon May  8 22:00:01 2000
@@ -58,7 +58,7 @@
 
 	if(pgtable_cache_size > high) {
 		do {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 			if(pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
 #endif
@@ -68,7 +68,7 @@
 				free_pte_slow(get_pte_fast(1)), freed++;
 		} while(pgtable_cache_size > low);
 	}
-#ifndef __SMP__ 
+#ifndef CONFIG_SMP 
         if (pgd_cache_size > high / 4) {
 		struct page *page, *page2;
                 for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
@@ -129,7 +129,7 @@
 	printk("%ld pages of RAM\n", num_physpages);
 	printk("%d free pages\n", nr_free_pages());
 	printk("%d pages in page table cache\n",pgtable_cache_size);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	printk("%d entries in page dir cache\n",pgd_cache_size);
 #endif	
 	show_buffers();
@@ -701,7 +701,7 @@
 	mm->context = new_ctx;
 }
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 struct pgtable_cache_struct pgt_quicklists;
 #endif
 
@@ -1207,7 +1207,7 @@
 	initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
 	initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	{
 		/* Put empty_pg_dir on pgd_quicklist */
 		extern pgd_t empty_pg_dir[1024];
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.99-pre6/linux/arch/sparc64/mm/ultra.S	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/mm/ultra.S	Mon May  8 22:00:01 2000
@@ -1,9 +1,10 @@
-/* $Id: ultra.S,v 1.41 2000/03/27 10:38:51 davem Exp $
+/* $Id: ultra.S,v 1.42 2000/05/05 18:47:41 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
  */
 
+#include <linux/config.h>
 #include <asm/asi.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -38,7 +39,7 @@
 		    */
 #define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
 /*IC3*/	cmp		%o5, %o4
-	be,pt		%xcc, __flush_tlb_page
+	bleu,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, 13, %g5
 	cmp		%g5, TLB_MAGIC
 	bgeu,pn		%icc, __flush_tlb_range_constant_time
@@ -242,7 +243,7 @@
 1:	retl
 	 nop
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
 	 *
@@ -431,4 +432,4 @@
 	 nop
 	flush		%g6
 	retry
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.3.99-pre6/linux/arch/sparc64/prom/misc.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/prom/misc.c	Mon May  8 22:00:01 2000
@@ -39,7 +39,7 @@
 extern int serial_console;
 #endif
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern void smp_capture(void);
 extern void smp_release(void);
 #endif
@@ -63,7 +63,7 @@
 	 * So in order for everything to work reliably, even
 	 * on SMP, we need to drop the IRQ locks we hold.
 	 */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	irq_exit(smp_processor_id(), 0);
 	smp_capture();
 #else
@@ -72,7 +72,7 @@
 
 	p1275_cmd ("enter", P1275_INOUT(0,0));
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_release();
 	irq_enter(smp_processor_id(), 0);
 	spin_unlock_wait(&__br_write_locks[BR_GLOBALIRQ_LOCK].lock);
@@ -88,7 +88,7 @@
 	__restore_flags(flags);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern void smp_promstop_others(void);
 #endif
 
@@ -98,7 +98,7 @@
 void
 prom_halt(void)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_promstop_others();
 	udelay(8000);
 #endif
@@ -328,7 +328,7 @@
 	return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
 {
 	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.3.99-pre6/linux/arch/sparc64/solaris/fs.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/solaris/fs.c	Mon May  8 22:21:57 2000
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.18 2000/04/08 02:11:54 davem Exp $
+/* $Id: fs.c,v 1.19 2000/05/09 04:48:35 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -477,17 +477,15 @@
 
 asmlinkage int solaris_statvfs(u32 path, u32 buf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei((const char *)A(path));
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode * inode = dentry->d_inode;
-
+	error = user_path_walk((const char *)A(path),&nd);
+	if (!error) {
+		struct inode * inode = nd.dentry->d_inode;
 		error = report_statvfs(inode, buf);
-		dput(dentry);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -512,17 +510,15 @@
 
 asmlinkage int solaris_statvfs64(u32 path, u32 buf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei((const char *)A(path));
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode * inode = dentry->d_inode;
-
+	error = user_path_walk((const char *)A(path), &nd);
+	if (!error) {
+		struct inode * inode = nd.dentry->d_inode;
 		error = report_statvfs64(inode, buf);
-		dput(dentry);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.99-pre6/linux/arch/sparc64/solaris/misc.c	Wed Apr 26 16:34:07 2000
+++ linux/arch/sparc64/solaris/misc.c	Mon May  8 22:00:01 2000
@@ -4,6 +4,7 @@
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/module.h> 
 #include <linux/types.h>
 #include <linux/smp_lock.h>
@@ -368,7 +369,7 @@
 	case SOLARIS_CONFIG_PROF_TCK:
 		return prom_getintdefault(prom_cpu_nodes[smp_processor_id()],
 					  "clock-frequency", 167000000);
-#ifdef __SMP__	
+#ifdef CONFIG_SMP	
 	case SOLARIS_CONFIG_NPROC_CONF:	return NR_CPUS;
 	case SOLARIS_CONFIG_NPROC_ONLN:	return smp_num_cpus;
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.3.99-pre6/linux/drivers/acorn/block/fd1772.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/acorn/block/fd1772.c	Fri Apr 28 22:50:13 2000
@@ -303,11 +303,9 @@
         timer_active |= (1 << FLOPPY_TIMER);			\
 	} while(0)
 
-#define	START_TIMEOUT()					\
-    do {						\
-        del_timer( &timeout_timer );			\
-        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;	\
-        add_timer( &timeout_timer );			\
+#define	START_TIMEOUT()					     \
+    do {						     \
+        mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \
 	} while(0)
 
 #define	STOP_TIMEOUT()					\
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c
--- v2.3.99-pre6/linux/drivers/atm/ambassador.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/atm/ambassador.c	Fri Apr 28 23:00:04 2000
@@ -2372,8 +2372,8 @@
     
     // read resources from PCI configuration space
     u8 irq = pci_dev->irq;
-    u32 * membase = bus_to_virt (pci_dev->resource[0].start);
-    u32 iobase = pci_dev->resource[1].start;
+    u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0));
+    u32 iobase = pci_resource_start (pci_dev, 1);
     
     void setup_dev (void) {
       unsigned char pool;
@@ -2419,6 +2419,9 @@
     void setup_pci_dev (void) {
       unsigned char lat;
       
+      /* XXX check return value */
+      pci_enable_device (pci_dev);
+
       // enable bus master accesses
       pci_set_master (pci_dev);
       
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- v2.3.99-pre6/linux/drivers/atm/fore200e.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/atm/fore200e.c	Fri Apr 28 23:00:04 2000
@@ -647,6 +647,9 @@
 	if (pci_dev == NULL)
 	    return NULL;
     } while (count--);
+
+    if (pci_enable_device(pci_dev))
+	return NULL;
     
     fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
     if (fore200e == NULL)
@@ -655,7 +658,7 @@
     fore200e->bus       = bus;
     fore200e->bus_dev   = pci_dev;    
     fore200e->irq       = pci_dev->irq;
-    fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK);
+    fore200e->phys_base = pci_resource_start (pci_dev, 0);
 
 #if defined(__powerpc__)
     fore200e->phys_base += KERNELBASE;
@@ -663,7 +666,6 @@
 
     sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
 
-    pci_enable_device(pci_dev);
     pci_set_master(pci_dev);
 
     return fore200e;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c
--- v2.3.99-pre6/linux/drivers/atm/horizon.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/atm/horizon.c	Fri Apr 28 23:00:04 2000
@@ -2759,9 +2759,6 @@
   
   PRINTD (DBG_FLOW, "hrz_probe");
   
-  if (!pci_present())
-    return 0;
-  
   devs = 0;
   pci_dev = NULL;
   while ((pci_dev = pci_find_device
@@ -2770,8 +2767,8 @@
     hrz_dev * dev;
     
     // adapter slot free, read resources from PCI configuration space
-    u32 iobase = pci_dev->resource[0].start;
-    u32 * membase = bus_to_virt (pci_dev->resource[1].start);
+    u32 iobase = pci_resource_start (pci_dev, 0);
+    u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1));
     u8 irq = pci_dev->irq;
     
     // check IO region
@@ -2779,7 +2776,10 @@
       PRINTD (DBG_WARN, "IO range already in use");
       continue;
     }
-    
+
+    if (pci_enable_device (pci_dev))
+      continue;
+
     dev = kmalloc (sizeof(hrz_dev), GFP_KERNEL);
     if (!dev) {
       // perhaps we should be nice: deregister all adapters and abort?
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/iphase.c linux/drivers/atm/iphase.c
--- v2.3.99-pre6/linux/drivers/atm/iphase.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/iphase.c	Fri May  5 12:37:52 2000
@@ -81,7 +81,8 @@
 static IADEV *ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 static struct atm_dev *_ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 static int iadev_count = 0;
-static struct timer_list ia_timer;
+static void ia_led_timer(unsigned long arg);
+static struct timer_list ia_timer = { function: ia_led_timer };
 struct atm_vcc *vcc_close_que[100];
 static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ;
 static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ;
@@ -2728,11 +2729,7 @@
         {
            static u8 first = 1; 
            if (first) {
-              ia_timer.next = NULL;
-              ia_timer.prev = NULL;
               ia_timer.expires = jiffies + 3*HZ;
-              ia_timer.data = 0UL;
-              ia_timer.function = ia_led_timer;
               add_timer(&ia_timer);
               first = 0;
            }           
@@ -3206,6 +3203,7 @@
 		IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
                      iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), 
                                                  PCI_FUNC(iadev->pci->devfn));)  
+		if (pci_enable_device(iadev->pci)) break;
 		dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
 		if (!dev) break;  
 		IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", 
@@ -3254,11 +3252,7 @@
 		return -ENXIO;  
 	}  
 	// MOD_INC_USE_COUNT; 
-        ia_timer.next = NULL;
-       	ia_timer.prev = NULL;
    	ia_timer.expires = jiffies + 3*HZ;
-   	ia_timer.data = 0UL;
-   	ia_timer.function = ia_led_timer;
    	add_timer(&ia_timer); 
    
 	return 0;  
@@ -3319,4 +3313,4 @@
 }  
 
 #endif  
-  
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- v2.3.99-pre6/linux/drivers/atm/nicstar.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/nicstar.c	Fri Apr 28 23:00:04 2000
@@ -452,6 +452,14 @@
 
    error = 0;
 
+   if (pci_enable_device(pcidev))
+   {
+      printk("nicstar%d: can't enable PCI device\n", i);
+      error = 2;
+      ns_init_card_error(card, error);
+      return error;
+   }
+
    if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
    {
       printk("nicstar%d: can't allocate memory for device structure.\n", i);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/suni.c linux/drivers/atm/suni.c
--- v2.3.99-pre6/linux/drivers/atm/suni.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/suni.c	Fri May  5 12:37:52 2000
@@ -254,8 +254,8 @@
 		poll_timer.function = suni_hz;
 		poll_timer.data = 1;
 #if 0
-printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
-    (unsigned long) poll_timer.next);
+printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.list.prev,
+    (unsigned long) poll_timer.list.next);
 #endif
 		add_timer(&poll_timer);
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c
--- v2.3.99-pre6/linux/drivers/atm/zatm.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/zatm.c	Fri Apr 28 23:00:04 2000
@@ -1811,6 +1811,7 @@
 		while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
 		    PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
 		    pci_dev))) {
+			if (pci_enable_device(pci_dev)) break;
 			dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
 			if (!dev) break;
 			zatm_dev->pci_dev = pci_dev;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.3.99-pre6/linux/drivers/block/DAC960.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/block/DAC960.c	Wed May  3 01:45:18 2000
@@ -465,28 +465,30 @@
       unsigned char Device = DeviceFunction >> 3;
       unsigned char Function = DeviceFunction & 0x7;
       unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = PCI_Device->resource[0].start;
-      unsigned long BaseAddress1 = PCI_Device->resource[1].start;
+      unsigned long BaseAddress0 = pci_resource_start (PCI_Device, 0);
+      unsigned long BaseAddress1 = pci_resource_start (PCI_Device, 1);
       unsigned short SubsystemVendorID, SubsystemDeviceID;
       int CommandIdentifier;
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID,
-			   &SubsystemVendorID);
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID,
-			   &SubsystemDeviceID);
+
+      if (pci_enable_device(PCI_Device))
+	  goto Ignore;
+
+      SubsystemVendorID = PCI_Device->subsystem_vendor;
+      SubsystemDeviceID = PCI_Device->subsystem_device;
       switch (ControllerType)
 	{
 	case DAC960_V5_Controller:
 	  if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
 		SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5))
 	    goto Ignore;
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  PCI_Address = BaseAddress0;
 	  break;
 	case DAC960_V4_Controller:
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  PCI_Address = BaseAddress0;
 	  break;
 	case DAC960_V3_Controller:
-	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+	  IO_Address = BaseAddress0;
+	  PCI_Address = BaseAddress1;
 	  break;
 	}
       if (DAC960_ControllerCount == DAC960_MaxControllers)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.3.99-pre6/linux/drivers/block/amiflop.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/amiflop.c	Fri May  5 12:37:52 2000
@@ -1824,19 +1824,16 @@
 	}
 
 	/* initialize variables */
-	motor_on_timer.next = NULL;
-	motor_on_timer.prev = NULL;
+	init_timer(&motor_on_timer);
 	motor_on_timer.expires = 0;
 	motor_on_timer.data = 0;
 	motor_on_timer.function = motor_on_callback;
 	for (i = 0; i < FD_MAX_UNITS; i++) {
-		motor_off_timer[i].next = NULL;
-		motor_off_timer[i].prev = NULL;
+		init_timer(&motor_off_timer[i]);
 		motor_off_timer[i].expires = 0;
 		motor_off_timer[i].data = i|0x80000000;
 		motor_off_timer[i].function = fd_motor_off;
-		flush_track_timer[i].next = NULL;
-		flush_track_timer[i].prev = NULL;
+		init_timer(&flush_track_timer[i]);
 		flush_track_timer[i].expires = 0;
 		flush_track_timer[i].data = i;
 		flush_track_timer[i].function = flush_track_callback;
@@ -1844,8 +1841,7 @@
 		unit[i].track = -1;
 	}
 
-	post_write_timer.next = NULL;
-	post_write_timer.prev = NULL;
+	init_timer(&post_write_timer);
 	post_write_timer.expires = 0;
 	post_write_timer.data = 0;
 	post_write_timer.function = post_write;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.99-pre6/linux/drivers/block/cpqarray.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/cpqarray.c	Wed May  3 01:45:18 2000
@@ -312,7 +312,6 @@
 /* This is a bit of a hack... */
 int __init init_module(void)
 {
-	int i, j;
 	cpqarray_init();
 	if (nr_ctlr == 0)
 		return -EIO;
@@ -627,16 +626,15 @@
 	for(i=0; i<6; i++)
 		addr[i] = pdev->resource[i].flags;
 
-	(void) pcibios_read_config_word(bus, device_fn,
-					PCI_COMMAND,&command);
-	(void) pcibios_read_config_byte(bus, device_fn,
-					PCI_CLASS_REVISION,&revision);
-	(void) pcibios_read_config_byte(bus, device_fn,
-					PCI_CACHE_LINE_SIZE, &cache_line_size);
-	(void) pcibios_read_config_byte(bus, device_fn,
-					PCI_LATENCY_TIMER, &latency_timer);
+	if (pci_enable_device(pdev))
+		return -1;
 
-	(void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id);
+	pci_read_config_word(pdev, PCI_COMMAND, &command);
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
+
+	pci_read_config_dword(pdev, 0x2c, &board_id);
 
 DBGINFO(
 	printk("vendor_id = %x\n", vendor_id);
@@ -659,7 +657,7 @@
 	 */
 	for(i=0; i<6; i++)
 		if (!(addr[i] & 0x1)) {
-			c->paddr = pdev->resource[i].start;
+			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
 	c->vaddr = remap_pci_mem(c->paddr, 128);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.99-pre6/linux/drivers/block/floppy.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/block/floppy.c	Tue May  2 16:48:16 2000
@@ -583,8 +583,7 @@
 }
 
 typedef void (*timeout_fn)(unsigned long);
-static struct timer_list fd_timeout ={ NULL, NULL, 0, 0,
-				       (timeout_fn) floppy_shutdown };
+static struct timer_list fd_timeout ={ function: (timeout_fn) floppy_shutdown };
 
 static const char *timeout_message;
 
@@ -592,7 +591,7 @@
 static void is_alive(const char *message)
 {
 	/* this routine checks whether the floppy driver is "alive" */
-	if (fdc_busy && command_status < 2 && !fd_timeout.prev){
+	if (fdc_busy && command_status < 2 && !timer_pending(&fd_timeout)){
 		DPRINT("timeout handler died: %s\n",message);
 	}
 }
@@ -903,14 +902,14 @@
 }
 
 static struct timer_list motor_off_timer[N_DRIVE] = {
-	{ NULL, NULL, 0, 0, motor_off_callback },
-	{ NULL, NULL, 0, 1, motor_off_callback },
-	{ NULL, NULL, 0, 2, motor_off_callback },
-	{ NULL, NULL, 0, 3, motor_off_callback },
-	{ NULL, NULL, 0, 4, motor_off_callback },
-	{ NULL, NULL, 0, 5, motor_off_callback },
-	{ NULL, NULL, 0, 6, motor_off_callback },
-	{ NULL, NULL, 0, 7, motor_off_callback }
+	{ data: 0, function: motor_off_callback },
+	{ data: 1, function: motor_off_callback },
+	{ data: 2, function: motor_off_callback },
+	{ data: 3, function: motor_off_callback },
+	{ data: 4, function: motor_off_callback },
+	{ data: 5, function: motor_off_callback },
+	{ data: 6, function: motor_off_callback },
+	{ data: 7, function: motor_off_callback }
 };
 
 /* schedules motor off */
@@ -976,7 +975,7 @@
 	mark_bh(IMMEDIATE_BH);
 }
 
-static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
+static struct timer_list fd_timer;
 
 static void cancel_activity(void)
 {
@@ -1852,9 +1851,9 @@
 		printk("DEVICE_INTR=%p\n", DEVICE_INTR);
 	if (floppy_tq.sync)
 		printk("floppy_tq.routine=%p\n", floppy_tq.routine);
-	if (fd_timer.prev)
+	if (timer_pending(&fd_timer))
 		printk("fd_timer.function=%p\n", fd_timer.function);
-	if (fd_timeout.prev){
+	if (timer_pending(&fd_timeout)){
 		printk("timer_table=%p\n",fd_timeout.function);
 		printk("expires=%lu\n",fd_timeout.expires-jiffies);
 		printk("now=%lu\n",jiffies);
@@ -4334,13 +4333,13 @@
 #ifdef FLOPPY_SANITY_CHECK
 #ifndef __sparc__
 	for (drive=0; drive < N_FDC * 4; drive++)
-		if (motor_off_timer[drive].next)
+		if (timer_pending(motor_off_timer + drive))
 			printk("motor off timer %d still active\n", drive);
 #endif
 
-	if (fd_timeout.next)
+	if (timer_pending(&fd_timeout))
 		printk("floppy timer still active:%s\n", timeout_message);
-	if (fd_timer.next)
+	if (timer_pending(&fd_timer))
 		printk("auxiliary floppy timer still active\n");
 	if (floppy_tq.sync)
 		printk("task queue still active\n");
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.99-pre6/linux/drivers/block/loop.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/block/loop.c	Wed May 10 18:22:41 2000
@@ -443,6 +443,7 @@
 			lo->lo_backing_file->f_flags = file->f_flags;
 			lo->lo_backing_file->f_owner = file->f_owner;
 			lo->lo_backing_file->f_dentry = file->f_dentry;
+			lo->lo_backing_file->f_vfsmnt = file->f_vfsmnt;
 			lo->lo_backing_file->f_op = file->f_op;
 			lo->lo_backing_file->private_data = file->private_data;
 			file_moveto(lo->lo_backing_file, file);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/paride/jumbo linux/drivers/block/paride/jumbo
--- v2.3.99-pre6/linux/drivers/block/paride/jumbo	Tue Dec 22 08:29:00 1998
+++ linux/drivers/block/paride/jumbo	Mon May  8 22:00:01 2000
@@ -26,7 +26,7 @@
 echo
 #
 case $USMP in
-	y* | Y* ) FSMP="-D__SMP__"
+	y* | Y* ) FSMP="-DCONFIG_SMP"
 		  ;;
 	*)	  FSMP=""
 		  ;;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/paride/on26.c linux/drivers/block/paride/on26.c
--- v2.3.99-pre6/linux/drivers/block/paride/on26.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/block/paride/on26.c	Wed May  3 01:45:18 2000
@@ -125,7 +125,7 @@
 
 static int on26_test_port( PIA *pi)  /* hard reset */
 
-{       int     i, m, d, x, y;
+{       int     i, m, d, x=0, y=0;
 
         pi->saved_r0 = r0();
         pi->saved_r2 = r2();
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.3.99-pre6/linux/drivers/block/paride/pd.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/paride/pd.c	Wed May  3 01:45:18 2000
@@ -637,7 +637,7 @@
 
 int     init_module(void)
 
-{       int     err, unit;
+{
 
 #ifdef PARIDE_JUMBO
        { extern paride_init();
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.3.99-pre6/linux/drivers/block/paride/pseudo.h	Sun Dec 27 11:25:58 1998
+++ linux/drivers/block/paride/pseudo.h	Wed May  3 01:45:17 2000
@@ -49,7 +49,7 @@
 
 static spinlock_t ps_spinlock __attribute__((unused)) = SPIN_LOCK_UNLOCKED;
 
-static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
+static struct timer_list ps_timer = { function: ps_timer_int };
 static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
 
 static void ps_set_intr( void (*continuation)(void), 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.3.99-pre6/linux/drivers/block/ps2esdi.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/ps2esdi.c	Fri May  5 12:37:52 2000
@@ -379,9 +379,9 @@
 	reset_status = 0;
 	reset_start = jiffies;
 	while (!reset_status) {
-		esdi_timer.expires = HZ;
+		init_timer(&esdi_timer);
+		esdi_timer.expires = jiffies + HZ;
 		esdi_timer.data = 0;
-		esdi_timer.next = esdi_timer.prev = NULL;
 		add_timer(&esdi_timer);
 		sleep_on(&ps2esdi_int);
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.99-pre6/linux/drivers/block/rd.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/rd.c	Fri May  5 12:37:52 2000
@@ -436,8 +436,8 @@
 
 #ifdef MODULE
 module_init(rd_init);
-module_exit(rd_cleanup);
 #endif
+module_exit(rd_cleanup);
 
 /* loadable module support */
 MODULE_PARM     (rd_size, "1i");
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.99-pre6/linux/drivers/block/xd.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/block/xd.c	Wed May  3 01:45:18 2000
@@ -149,9 +149,7 @@
 static volatile int xdc_busy = 0;
 static DECLARE_WAIT_QUEUE_HEAD(xdc_wait);
 
-typedef void (*timeout_fn)(unsigned long);
-static struct timer_list xd_timer = { NULL, NULL, 0, 0, (timeout_fn) xd_wakeup },
-			 xd_watchdog_int = { NULL, NULL, 0, 0, (timeout_fn) xd_watchdog };
+static struct timer_list xd_timer, xd_watchdog_int;
 
 static volatile u_char xd_error;
 static int nodma = XD_DONT_USE_DMA;
@@ -161,6 +159,9 @@
 /* xd_init: register the block device number and set up pointer tables */
 int __init xd_init (void)
 {
+	init_timer (&xd_timer); xd_timer.function = xd_wakeup;
+	init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
+
 	if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 		printk("xd: Unable to get major number %d\n",MAJOR_NR);
 		return -1;
@@ -551,13 +552,13 @@
 }
 
 /* xd_wakeup is called from timer interrupt */
-static void xd_wakeup (void)
+static void xd_wakeup (unsigned long unused)
 {
 	wake_up(&xdc_wait);
 }
 
 /* xd_wakeup is called from timer interrupt */
-static void xd_watchdog (void)
+static void xd_watchdog (unsigned long unused)
 {
 	xd_error = 1;
 	wake_up(&xd_wait_int);
@@ -1136,8 +1137,8 @@
 	if((xd[0] = count))
 		do_xd_setup(xd);
 
-	if (error = xd_init())
-		return error;
+	error = xd_init();
+	if (error) return error;
 
 	printk(KERN_INFO "XD: Loaded as a module.\n");
 	if (!xd_drives) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/block/xd.h linux/drivers/block/xd.h
--- v2.3.99-pre6/linux/drivers/block/xd.h	Wed Apr 26 16:34:07 2000
+++ linux/drivers/block/xd.h	Wed May  3 01:45:18 2000
@@ -122,8 +122,8 @@
 static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
 static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
-static void xd_wakeup (void);
-static void xd_watchdog (void);
+static void xd_wakeup (unsigned long unused);
+static void xd_watchdog (unsigned long unused);
 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.99-pre6/linux/drivers/cdrom/cdrom.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/cdrom/cdrom.c	Wed May 10 17:33:57 2000
@@ -199,11 +199,22 @@
   home now.
   -- Clear header length in mode_select unconditionally.
   -- Removed the register_disk() that was added, not needed here.
+
+  3.08 May 1, 2000 - Jens Axboe <axboe@suse.de>
+  -- Fix direction flag in setup_send_key and setup_report_key. This
+  gave some SCSI adapters problems.
+  -- Always return -EROFS for write opens
+  -- Convert to module_init/module_exit style init and remove some
+  of the #ifdef MODULE stuff
+  -- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid,
+  DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and
+  dvd_do_auth passed uninitialized data to drive because init_cdrom_command
+  did not clear a 0 sized buffer.
   
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.07"
-#define VERSION "Id: cdrom.c 3.07 2000/02/02"
+#define REVISION "Revision: 3.08"
+#define VERSION "Id: cdrom.c 3.08 2000/05/01"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -432,17 +443,6 @@
 	while (cdi != NULL && cdi->dev != dev)
 		cdi = cdi->next;
 
-	/* we need to find the device this way when IDE devices such
-	 * as /dev/hdc2 are opened. SCSI drives will be found above and
-	 * so will /dev/hdc, for instance.
-	 */
-	if (cdi == NULL) {
-		kdev_t cd_dev = MKDEV(MAJOR(dev), MINOR(dev) | CD_PART_MASK);
-		cdi = topCdromPtr;
-		while (cdi != NULL && cdi->dev != cd_dev)
-			cdi = cdi->next;
-	}
-
 	return cdi;
 }
 
@@ -834,7 +834,7 @@
 	/* This talks to the VFS, which doesn't like errors - just 1 or 0.  
 	 * Returning "0" is always safe (media hasn't been changed). Do that 
 	 * if the low-level cdrom driver dosn't support media changed. */ 
-	if (cdi->ops->media_changed == NULL)
+	if (cdi == NULL || cdi->ops->media_changed == NULL)
 		return 0;
 	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
 	    return 0;
@@ -994,6 +994,7 @@
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
 
+	memset(buf, 0, sizeof(buf));
 	init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ);
 
 	switch (ai->type) {
@@ -1052,7 +1053,7 @@
 
 	case DVD_LU_SEND_ASF:
 		cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); 
-		setup_report_key(&cgc, ai->lsasf.asf, 5);
+		setup_report_key(&cgc, ai->lsasf.agid, 5);
 		
 		if ((ret = cdo->generic_packet(cdi, &cgc)))
 			return ret;
@@ -1113,6 +1114,7 @@
 	case DVD_HOST_SEND_RPC_STATE:
 		cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
 		setup_send_key(&cgc, 0, 6);
+		buf[1] = 6;
 		buf[4] = ai->hrpcs.pdrc;
 
 		if ((ret = cdo->generic_packet(cdi, &cgc)))
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v2.3.99-pre6/linux/drivers/cdrom/cm206.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/cdrom/cm206.c	Wed May  3 01:45:19 2000
@@ -1420,7 +1420,7 @@
 #ifdef MODULE
 
 
-void __init parse_options(void)
+static void __init parse_options(void)
 {
   int i;
   for (i=0; i<2; i++) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v2.3.99-pre6/linux/drivers/cdrom/optcd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/cdrom/optcd.c	Fri May  5 12:37:52 2000
@@ -265,23 +265,18 @@
 /* Timed waiting for status or data */
 static int sleep_timeout;	/* max # of ticks to sleep */
 static DECLARE_WAIT_QUEUE_HEAD(waitq);
-static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
-
-#define SET_TIMER(func, jifs) \
-	delay_timer.expires = jiffies+(jifs); \
-	delay_timer.function = (void *) (func); \
-	add_timer(&delay_timer);
-#define CLEAR_TIMER	del_timer(&delay_timer)
+static void sleep_timer(unsigned long data);
+static struct timer_list delay_timer = {function: sleep_timer};
 
 
 /* Timer routine: wake up when desired flag goes low,
    or when timeout expires. */
-static void sleep_timer(void)
+static void sleep_timer(unsigned long data)
 {
 	int flags = inb(STATUS_PORT) & FL_STDT;
 
 	if (flags == FL_STDT && --sleep_timeout > 0) {
-		SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */
+		mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */
 	} else
 		wake_up(&waitq);
 }
@@ -297,7 +292,7 @@
 	sleep_timeout = timeout;
 	flag_high = inb(STATUS_PORT) & flag;
 	if (flag_high && sleep_timeout > 0) {
-		SET_TIMER(sleep_timer, HZ/100);
+		mod_timer(&delay_timer, jiffies + HZ/100);
 		sleep_on(&waitq);
 		flag_high = inb(STATUS_PORT) & flag;
 	}
@@ -1079,15 +1074,11 @@
 static int tries;		/* ibid?? */
 static int timeout = 0;
 
-static struct timer_list req_timer = {NULL, NULL, 0, 0, NULL};
+static void poll(unsigned long data);
+static struct timer_list req_timer = {function: poll};
 
-#define SET_REQ_TIMER(func, jifs) \
-	req_timer.expires = jiffies+(jifs); \
-	req_timer.function = (void *) (func); \
-	add_timer(&req_timer);
-#define CLEAR_REQ_TIMER	del_timer(&req_timer)
 
-static void poll(void)
+static void poll(unsigned long data)
 {
 	static volatile int read_count = 1;
 	int flags;
@@ -1363,7 +1354,7 @@
 		}
 	}
 
-	SET_REQ_TIMER(poll, HZ/100);
+	mod_timer(&req_timer, jiffies + HZ/100);
 }
 
 
@@ -1401,7 +1392,7 @@
 				timeout = READ_TIMEOUT;
 				tries = 5;
 				/* %% why not start right away?? */
-				SET_REQ_TIMER(poll, HZ/100);
+				mod_timer(&req_timer, jiffies + HZ/100);
 			}
 			break;
 		}
@@ -1945,8 +1936,8 @@
 			status = exec_cmd(COMOPEN);
 			DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
 		}
-		CLEAR_TIMER;
-		CLEAR_REQ_TIMER;
+		del_timer(&delay_timer);
+		del_timer(&req_timer);
 	}
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.3.99-pre6/linux/drivers/cdrom/sbpcd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/cdrom/sbpcd.c	Wed May  3 01:45:18 2000
@@ -764,10 +764,10 @@
 unsigned long cli_sti; /* for saving the processor flags */
 #endif
 /*==========================================================================*/
-static struct timer_list delay_timer = { NULL, NULL, 0, 0, mark_timeout_delay};
-static struct timer_list data_timer = { NULL, NULL, 0, 0, mark_timeout_data};
+static struct timer_list delay_timer = { function: mark_timeout_delay};
+static struct timer_list data_timer = { function: mark_timeout_data};
 #if 0
-static struct timer_list audio_timer = { NULL, NULL, 0, 0, mark_timeout_audio};
+static struct timer_list audio_timer = { function: mark_timeout_audio};
 #endif
 /*==========================================================================*/
 /*
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.3.99-pre6/linux/drivers/cdrom/sjcd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/cdrom/sjcd.c	Fri May  5 12:37:52 2000
@@ -153,7 +153,7 @@
 /*
  * Timer.
  */
-static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL };
+static struct timer_list sjcd_delay_timer = { function: NULL };
 
 #define SJCD_SET_TIMER( func, tmout )           \
     ( sjcd_delay_timer.expires = jiffies+tmout,         \
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.99-pre6/linux/drivers/char/Config.in	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/Config.in	Wed May 10 16:56:41 2000
@@ -204,6 +204,9 @@
       dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT
    fi
    dep_tristate '  Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_ALL_PPC" = "y" ]; then
+      dep_tristate '  PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
+   fi
    if [ "$CONFIG_PARPORT" != "n" ]; then
       dep_tristate '  Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.99-pre6/linux/drivers/char/Makefile	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/Makefile	Wed May 10 16:56:42 2000
@@ -23,7 +23,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick pcmcia
+ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick pcmcia rio
 
 #
 # This file contains the font map for the default (hardware) font
@@ -45,6 +45,13 @@
 CONSOLE  =console.o
 SERIAL   =serial.o
 
+ifeq ($(ARCH),s390)
+  KEYMAP   =
+  KEYBD    =
+  CONSOLE  =
+  SERIAL   =
+endif
+
 ifeq ($(ARCH),m68k)
    ifdef CONFIG_AMIGA
       KEYBD = amikeyb.o
@@ -127,11 +134,41 @@
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
 obj-$(CONFIG_SPECIALIX) += specialix.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
+obj-$(CONFIG_SX) += sx.o
+
 
+# If either is in the kernel, generic_serial goes in the kernel, and
+# the module is no longer required. The "in kernel" case is last to be
+# able to override the module case....  This is an example of the new
+# "makefile automatically figures out the dependencies"....  -- REW
+
+GS = n
+ifeq ($(CONFIG_SX),m)
+  GS = m
+endif
+ifeq ($(CONFIG_RIO),m)
+  GS = m 
+endif
 ifeq ($(CONFIG_SX),y)
-obj-y += sx.o generic_serial.o
+  GS = y 
+endif
+ifeq ($(CONFIG_RIO),y)
+  GS = y 
+endif
+obj-$(GS) += generic_serial.o
+
+
+
+
+ifeq ($(CONFIG_RIO),y)
+obj-y += rio/rio.o  generic_serial.o
+SUB_DIRS += rio
+MOD_SUB_DIRS += rio
 else
-  obj-$(CONFIG_SX) += sx.o
+  ifeq ($(CONFIG_RIO),m)
+  obj-m += generic_serial.o
+  MOD_SUB_DIRS += rio
+  endif
 endif
 
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- v2.3.99-pre6/linux/drivers/char/amiserial.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/amiserial.c	Mon May  8 22:00:01 2000
@@ -2259,6 +2259,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 amiserial.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 amiserial.c"
   End:
 */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/applicom.c linux/drivers/char/applicom.c
--- v2.3.99-pre6/linux/drivers/char/applicom.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/applicom.c	Fri Apr 28 23:00:05 2000
@@ -205,6 +205,9 @@
 		if (dev->device  > MAX_PCI_DEVICE_NUM || dev->device == 0)
 			continue;
 		
+		if (pci_enable_device(dev))
+			return -EIO;
+
 		RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
 
 		if (!RamIO) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.99-pre6/linux/drivers/char/bttv.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/bttv.c	Fri Apr 28 23:00:06 2000
@@ -3661,7 +3661,10 @@
 
         btv->id=dev->device;
         btv->irq=dev->irq;
-        btv->bt848_adr=dev->resource[0].start;
+        btv->bt848_adr=pci_resource_start(dev, 0);
+
+	if (pci_enable_device(dev))
+		return -EIO;
 	if (!request_mem_region(pci_resource_start(dev,0),
 				pci_resource_len(dev,0),
 				"bttv")) {
@@ -3672,7 +3675,6 @@
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
-        btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
                bttv_num,btv->id, btv->revision);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/buz.c linux/drivers/char/buz.c
--- v2.3.99-pre6/linux/drivers/char/buz.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/buz.c	Fri Apr 28 23:00:06 2000
@@ -3324,7 +3324,10 @@
 
 		spin_lock_init(&zr->lock);
 
-		zr->zr36057_adr = zr->pci_dev->resource[0].start;
+		if (pci_enable_device(dev))
+			continue;
+
+		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
 		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
 		if (zr->revision < 2) {
 			printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
@@ -3332,8 +3335,8 @@
 		} else {
 			unsigned short ss_vendor_id, ss_id;
 
-			pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id);
-			pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id);
+			ss_vendor_id = zr->pci_dev->subsystem_vendor;
+			ss_id = zr->pci_dev->subsystem_device;
 			printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
 			       zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
 			printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n",
@@ -3346,6 +3349,10 @@
 		}
 
 		zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
+		if (!zr->zr36057_mem) {
+			printk(KERN_ERR "%s: ioremap failed\n", zr->name);
+			/* XXX handle error */
+		}
 
 		/* set PCI latency timer */
 		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.99-pre6/linux/drivers/char/cyclades.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/cyclades.c	Wed May  3 01:45:17 2000
@@ -877,9 +877,8 @@
 static long cyz_polling_cycle = CZ_DEF_POLL;
 
 static int cyz_timeron = 0;
-static struct timer_list
-cyz_timerlist = {
-    NULL, NULL, 0, 0, cyz_poll
+static struct timer_list cyz_timerlist = {
+    function: cyz_poll
 };
 #else /* CONFIG_CYZ_INTR */
 static void cyz_rx_restart(unsigned long);
@@ -4859,9 +4858,6 @@
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   unsigned char         Ze_irq[NR_CARDS];
 
-        if(pci_present() == 0) {    /* PCI bus not present */
-                return(0);
-        }
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
                 while((device_id = cy_pci_dev_id[dev_index]) != 0) {
@@ -4876,11 +4872,14 @@
 		if (device_id == 0)
 		    break;
 
+		if (pci_enable_device(pdev))
+		    continue;
+
                 /* read PCI configuration area */
 		cy_pci_irq = pdev->irq;
-		cy_pci_addr0 = pdev->resource[0].start;
-		cy_pci_addr1 = pdev->resource[1].start;
-		cy_pci_addr2 = pdev->resource[2].start;
+		cy_pci_addr0 = pci_resource_start(pdev, 0);
+		cy_pci_addr1 = pci_resource_start(pdev, 1);
+		cy_pci_addr2 = pci_resource_start(pdev, 2);
                 pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
 		device_id &= ~PCI_DEVICE_ID_MASK;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c
--- v2.3.99-pre6/linux/drivers/char/dtlk.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/char/dtlk.c	Fri Apr 28 22:50:13 2000
@@ -241,6 +241,8 @@
 static unsigned int dtlk_poll(struct file *file, poll_table * wait)
 {
 	int mask = 0;
+	unsigned long expires;
+
 	TRACE_TEXT(" dtlk_poll");
 	/*
 	   static long int j;
@@ -261,9 +263,8 @@
 	/* there are no exception conditions */
 
 	/* There won't be any interrupts, so we set a timer instead. */
-	del_timer(&dtlk_timer);
-	dtlk_timer.expires = jiffies + 3*HZ / 100;
-	add_timer(&dtlk_timer);
+	expires = jiffies + 3*HZ / 100;
+	mod_timer(&dtlk_timer, expires);
 
 	return mask;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.3.99-pre6/linux/drivers/char/isicom.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/char/isicom.c	Wed May 10 16:56:41 2000
@@ -98,7 +98,7 @@
 
 /*   baud index mappings from linux defns to isi */
 
-static char linuxb_to_isib[] = {
+static signed char linuxb_to_isib[] = {
 	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17,     
 	18, 19
 };
@@ -1995,12 +1995,14 @@
 				if (card >= BOARD_COUNT)
 					break;
 					
+				if (pci_enable_device(dev))
+					break;
+
 				/* found a PCI ISI card! */
-				ioaddr = dev->resource[3].start; /* i.e at offset 0x1c in the
-								* PCI configuration register
-								* space.
-								*/
-				ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+				ioaddr = pci_resource_start (dev, 3); /* i.e at offset 0x1c in the
+								       * PCI configuration register
+								       * space.
+								       */
 				pciirq = dev->irq;
 				printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]);
 				/*
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.3.99-pre6/linux/drivers/char/istallion.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/istallion.c	Wed May  3 01:45:17 2000
@@ -796,7 +796,7 @@
  *	not increase character latency by much either...
  */
 static struct timer_list	stli_timerlist = {
-	NULL, NULL, 0, 0, stli_poll
+	function: stli_poll
 };
 
 static int	stli_timeron = 0;
@@ -837,7 +837,7 @@
 	stlibrd_t	*brdp;
 	stliport_t	*portp;
 	unsigned long	flags;
-	int		i, j, k;
+	int		i, j;
 
 #if DEBUG
 	printk("cleanup_module()\n");
@@ -4657,6 +4657,8 @@
 		dev->bus->number, dev->devfn);
 #endif
 
+	if (pci_enable_device(devp))
+		return(-EIO);
 	if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
 		return(-ENOMEM);
 	if ((brdp->brdnr = stli_getbrdnr()) < 0) {
@@ -4667,17 +4669,19 @@
 	brdp->brdtype = brdtype;
 
 #if DEBUG
-	printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
-		devp->resource[0].start, devp->resource[1].start,
-		devp->resource[2].start, devp->resource[3].start);
+	printk("%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__,
+		pci_resource_start(devp, 0),
+		pci_resource_start(devp, 1),
+		pci_resource_start(devp, 2),
+		pci_resource_start(devp, 3));
 #endif
 
 /*
  *	We have all resources from the board, so lets setup the actual
  *	board structure now.
  */
-	brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
-	brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
+	brdp->iobase = pci_resource_start(devp, 3);
+	brdp->memaddr = pci_resource_start(devp, 2);
 	stli_brdinit(brdp);
 
 	return(0);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.99-pre6/linux/drivers/char/misc.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/misc.c	Fri May  5 12:23:20 2000
@@ -85,12 +85,24 @@
 			  int len, int *eof, void *private)
 {
 	struct miscdevice *p;
+	int written;
 
-	len=0;
-	for (p = misc_list.next; p != &misc_list && len < 4000; p = p->next)
-		len += sprintf(buf+len, "%3i %s\n",p->minor, p->name ?: "");
+	written=0;
+	for (p = misc_list.next; p != &misc_list && written < len; p = p->next) {
+		written += sprintf(buf+written, "%3i %s\n",p->minor, p->name ?: "");
+		if (written < offset) {
+			offset -= written;
+			written = 0;
+		}
+	}
 	*start = buf + offset;
-	return len > offset ? len - offset : 0;
+	written -= offset;
+	if(written > len) {
+		*eof = 0;
+		return len;
+	}
+	*eof = 1;
+	return (written<0) ? 0 : written;
 }
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/moxa.c linux/drivers/char/moxa.c
--- v2.3.99-pre6/linux/drivers/char/moxa.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/char/moxa.c	Wed May  3 01:45:18 2000
@@ -482,13 +482,15 @@
 #endif
 	/* Find PCI boards here */
 #ifdef CONFIG_PCI
-	if (pci_present()) {
+	{
 		struct pci_dev *p = NULL;
 		n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo);
 		i = 0;
 		while (i < n) {
 			while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL)
 			{
+				if (pci_enable_device(p))
+					continue;
 				if (numBoards >= MAX_BOARDS) {
 					if (verbose)
 						printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
@@ -511,9 +513,7 @@
 
 static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
 {
-	unsigned int val;
-
-	board->baseAddr = p->resource[2].start;
+	board->baseAddr = pci_resource_start (p, 2);
 	board->boardType = board_type;
 	switch (board_type) {
 	case MOXA_BOARD_C218_ISA:
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.3.99-pre6/linux/drivers/char/msp3400.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/msp3400.c	Fri May  5 12:37:52 2000
@@ -663,11 +663,8 @@
 	}
 	if (once)
 		msp->watch_stereo = 0;
-	if (msp->watch_stereo) {
-		del_timer(&msp->wake_stereo);
-		msp->wake_stereo.expires = jiffies + 5*HZ;
-		add_timer(&msp->wake_stereo);
-	}
+	if (msp->watch_stereo)
+		mod_timer(&msp->wake_stereo, jiffies+5*HZ);
 }
 
 static int msp3400c_thread(void *data)
@@ -874,11 +871,8 @@
 		/* unmute */
 		msp3400c_setvolume(client, msp->left, msp->right);
 
-		if (msp->watch_stereo) {
-			del_timer(&msp->wake_stereo);
-			msp->wake_stereo.expires = jiffies + 5*HZ;
-			add_timer(&msp->wake_stereo);
-		}
+		if (msp->watch_stereo) 
+			mod_timer(&msp->wake_stereo, jiffies+5*HZ);
 
 		if (debug)
 			msp3400c_print_mode(msp);
@@ -1092,11 +1086,8 @@
 		msp3400c_settreble(client, msp->treble);
 		msp3400c_setvolume(client, msp->left, msp->right);
 
-		if (msp->watch_stereo) {
-			del_timer(&msp->wake_stereo);
-			msp->wake_stereo.expires = jiffies + HZ;
-			add_timer(&msp->wake_stereo);
-		}
+		if (msp->watch_stereo) 
+			mod_timer(&msp->wake_stereo, jiffies+HZ);
 
 		msp->active = 0;
 	}
@@ -1245,7 +1236,7 @@
 msp3400c_mixer_open(struct inode *inode, struct file *file)
 {
         int minor = MINOR(inode->i_rdev);
-	struct i2c_client *client;
+	struct i2c_client *client = NULL;
 	struct msp3400c *msp;
 	int i;
 
@@ -1255,12 +1246,12 @@
 		if (msp->mixer_num == minor) {
 			client = msps[i];
 			file->private_data = client;
-			break;
+			goto match;
 		}
 	}
-	if (MSP3400_MAX == i)
-		return -ENODEV;
+	return -ENODEV;
 
+match:
 	/* lock bttv in memory while the mixer is in use  */
 	if (client->adapter->inc_use)
 		client->adapter->inc_use(client->adapter);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- v2.3.99-pre6/linux/drivers/char/mxser.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/mxser.c	Fri May  5 12:37:52 2000
@@ -170,11 +170,6 @@
 	{PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, MXSER_BOARD_C104_PCI},
 };
 
-typedef struct _moxa_pci_info {
-	unsigned short busNum;
-	unsigned short devNum;
-} moxa_pci_info;
-
 static int ioaddr[MXSER_BOARDS] = {0, 0, 0, 0};
 static int ttymajor = MXSERMAJOR;
 static int calloutmajor = MXSERCUMAJOR;
@@ -198,7 +193,7 @@
 	int uart_type;
 	int ioaddr[MXSER_PORTS_PER_BOARD];
 	int baud_base[MXSER_PORTS_PER_BOARD];
-	moxa_pci_info pciInfo;
+	struct pci_dev *pdev;
 };
 
 struct mxser_struct {
@@ -304,7 +299,7 @@
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
 int mxser_init(void);
 static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
-static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
+static int mxser_get_PCI_conf(struct pci_dev *, int, struct mxser_hwconf *);
 static void mxser_do_softint(void *);
 static int mxser_open(struct tty_struct *, struct file *);
 static void mxser_close(struct tty_struct *, struct file *);
@@ -454,33 +449,21 @@
 	mxsercfg[board] = *hwconf;
 }
 
-static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
+static int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser_hwconf *hwconf)
 {
 	int i;
-	unsigned int val, ioaddress;
+	unsigned int ioaddress;
 
 	hwconf->board_type = board_type;
 	hwconf->ports = mxser_numports[board_type - 1];
-	pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_2, &val);
-	if (val == 0xffffffff)
-		return (MXSER_ERR_IOADDR);
-	else
-		ioaddress = val & 0xffffffc;
+	ioaddress = pci_resource_start (pdev, 2);
 	for (i = 0; i < hwconf->ports; i++)
 		hwconf->ioaddr[i] = ioaddress + 8 * i;
 
-	pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_3, &val);
-	if (val == 0xffffffff)
-		return (MXSER_ERR_VECTOR);
-	else
-		ioaddress = val & 0xffffffc;
+	ioaddress = pci_resource_start (pdev, 3);
 	hwconf->vector = ioaddress;
 
-	pcibios_read_config_dword(busnum, devnum, PCI_INTERRUPT_LINE, &val);
-	if (val == 0xffffffff)
-		return (MXSER_ERR_IRQ);
-	else
-		hwconf->irq = val & 0xff;
+	hwconf->irq = pdev->irq;
 
 	hwconf->uart_type = PORT_16550A;
 	hwconf->vector_mask = 0;
@@ -496,7 +479,6 @@
 	int i, m, retval, b;
 	int n, index;
 	int ret1, ret2;
-	unsigned char busnum, devnum;
 	struct mxser_hwconf hwconf;
 
 	printk("MOXA Smartio family driver version %s\n", MXSER_VERSION);
@@ -577,8 +559,7 @@
 
 			continue;
 		}
-		hwconf.pciInfo.busNum = 0;
-		hwconf.pciInfo.devNum = 0;
+		hwconf.pdev = NULL;
 
 		if (mxser_initbrd(m, &hwconf) < 0)
 			continue;
@@ -613,8 +594,7 @@
 
 			continue;
 		}
-		hwconf.pciInfo.busNum = 0;
-		hwconf.pciInfo.devNum = 0;
+		hwconf.pdev = NULL;
 
 		if (mxser_initbrd(m, &hwconf) < 0)
 			continue;
@@ -627,29 +607,26 @@
 	/* start finding PCI board here */
 
 #ifdef CONFIG_PCI
-	if (pci_present()) 
 	{
+		struct pci_dev *pdev = NULL;
+
 		n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo);
 		index = 0;
 		b = 0;
 		while (b < n) {
-			if (pcibios_find_device(mxser_pcibrds[b].vendor_id,
-					      mxser_pcibrds[b].device_id,
-						index,
-						&busnum,
-						&devnum) != 0) {
-				b++;
-				index = 0;
-				continue;
-			}
-			hwconf.pciInfo.busNum = busnum;
-			hwconf.pciInfo.devNum = devnum;
-			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], busnum, devnum >> 3);
-			index++;
+			pdev = pci_find_device(mxser_pcibrds[b].vendor_id,
+					       mxser_pcibrds[b].device_id, pdev);
+			if (!pdev)
+				break;
+			b++;
+			hwconf.pdev = pdev;
+			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+				mxser_brdname[mxser_pcibrds[b].board_type - 1],
+				pdev->bus->number, PCI_SLOT(pdev->devfn >> 3));
 			if (m >= MXSER_BOARDS) {
 				printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
 			} else {
-				retval = mxser_get_PCI_conf(busnum, devnum,
+				retval = mxser_get_PCI_conf(pdev,
 				   mxser_pcibrds[b].board_type, &hwconf);
 				if (retval < 0) {
 					if (retval == MXSER_ERR_IRQ)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- v2.3.99-pre6/linux/drivers/char/n_r3964.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/n_r3964.c	Wed May  3 01:45:19 2000
@@ -110,8 +110,6 @@
 #define TRACE_Q(fmt, arg...) /**/
 #endif
 
-void cleanup_module(void);
-
 static void on_timer_1(void*);
 static void on_timer_2(void*);
 static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
@@ -196,11 +194,7 @@
  * Module support routines
  *************************************************************/
 
-#ifdef MODULE
-
-#define r3964_init init_module
-
-void cleanup_module(void)
+static void __exit r3964_exit(void)
 {
    int status;
    
@@ -219,9 +213,6 @@
    
 }
 
-
-#endif /* MODULE */
-
 static int __init r3964_init(void)
 {
    int status;
@@ -248,9 +239,9 @@
    return status;
 }
 
-#ifndef MODULE
-__initcall (r3964_init);
-#endif
+module_init(r3964_init);
+module_exit(r3964_exit);
+
 
 /*************************************************************
  * Protocol implementation routines
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.3.99-pre6/linux/drivers/char/pc110pad.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/pc110pad.c	Wed May  3 01:45:18 2000
@@ -70,20 +70,6 @@
 static int active=0;	/* number of concurrent open()s */
 static struct semaphore reader_lock;
 
-/*
- *	set_timer_callback:
- *
- *	Utility to reset a timer to go off some time in the future.
- */
-
-static void set_timer_callback(struct timer_list *timer, int ticks)
-{
-	del_timer(timer);
-	timer->expires = jiffies+ticks;
-	add_timer(timer);
-}
-
-
 /**
  *	wake_readers:
  *
@@ -130,7 +116,7 @@
 static int transition_count=0;
 static int synthesize_tap=0;
 static void tap_timeout(unsigned long data);
-static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout };
+static struct timer_list tap_timer = { function: tap_timeout };
 
 
 /**
@@ -178,7 +164,7 @@
 		transition_count=1;
 		recent_transition=1;
 	}
-	set_timer_callback(&tap_timer, current_params.tap_interval);
+	mod_timer(&tap_timer, jiffies + current_params.tap_interval);
 
 	/* changes to transition_count can cause reported button to change */
 	button_pending = 1;
@@ -246,7 +232,7 @@
  */
  
 static void bounce_timeout(unsigned long data);
-static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout };
+static struct timer_list bounce_timer = { function: bounce_timeout };
 
 
 
@@ -369,8 +355,8 @@
 				else
 				{
 					bounce=JUST_GONE_DOWN;
-					set_timer_callback(&bounce_timer,
-						current_params.bounce_interval);
+					mod_timer(&bounce_timer,
+						jiffies+current_params.bounce_interval);
 					/* start new stroke/tap */
 					debounced_down=new_down;
 					notify_pad_up_down();
@@ -391,8 +377,8 @@
 				{
 					/* don't trust it yet */
 					bounce=JUST_GONE_UP;
-					set_timer_callback(&bounce_timer,
-						current_params.bounce_interval);
+					mod_timer(&bounce_timer,
+						jiffies+current_params.bounce_interval);
 				}
 			}
 		}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c
--- v2.3.99-pre6/linux/drivers/char/pcmcia/serial_cb.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/pcmcia/serial_cb.c	Fri May  5 12:37:52 2000
@@ -50,12 +50,12 @@
 
 ======================================================================*/
 
-static void device_setup(u_char bus, u_char devfn, u_int ioaddr)
+static void device_setup(struct pci_dev *pdev, u_int ioaddr)
 {
     u_short a, b;
 
-    pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &a);
-    pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_ID, &b);
+    a = pdev->subsystem_vendor;
+    b = pdev->subsystem_device;
     if (((a == 0x13a2) && (b == 0x8007)) ||
 	((a == 0x1420) && (b == 0x8003))) {
 	/* Ositech, Psion 83c175-based cards */
@@ -81,22 +81,26 @@
 static dev_node_t *serial_attach(dev_locator_t *loc)
 {
     u_int io;
-    u_char bus, devfn, irq;
+    u_char irq;
     int line;
     struct serial_struct serial;
+    struct pci_dev *pdev;
+    dev_node_t *node;
     
-    if (loc->bus != LOC_PCI) return NULL;
-    bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-    printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", bus, devfn);
-    pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-    pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-    if (io & PCI_BASE_ADDRESS_SPACE_IO) {
-	io &= PCI_BASE_ADDRESS_IO_MASK;
-    } else {
+    MOD_INC_USE_COUNT;
+
+    if (loc->bus != LOC_PCI) goto err_out;
+    pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
+    if (!pdev) goto err_out;
+
+    printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn);
+    io = pci_resource_start (pdev, 0);
+    irq = pdev->irq;
+    if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
 	printk(KERN_NOTICE "serial_cb: PCI base address 0 is not IO\n");
-	return NULL;
+	goto err_out;
     }
-    device_setup(bus, devfn, io);
+    device_setup(pdev, io);
     memset(&serial, 0, sizeof(serial));
     serial.port = io; serial.irq = irq;
     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
@@ -109,15 +113,22 @@
     if (line < 0) {
 	printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, "
 	       "irq %d failed\n", serial.port, serial.irq);
-	return NULL;
-    } else {
-	dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-	sprintf(node->dev_name, "ttyS%d", line);
-	node->major = TTY_MAJOR; node->minor = 0x40 + line;
-	node->next = NULL;
-	MOD_INC_USE_COUNT;
-	return node;
+    	goto err_out;
     }
+
+    node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+    if (!node)
+	    goto err_out_unregister;
+    sprintf(node->dev_name, "ttyS%d", line);
+    node->major = TTY_MAJOR; node->minor = 0x40 + line;
+    node->next = NULL;
+    return node;
+
+err_out_unregister:
+    unregister_serial(line);
+err_out:
+    MOD_DEC_USE_COUNT;
+    return NULL;
 }
 
 static void serial_detach(dev_node_t *node)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c
--- v2.3.99-pre6/linux/drivers/char/pcmcia/serial_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/pcmcia/serial_cs.c	Mon May  8 21:26:05 2000
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.117 1999/12/11 03:59:18
+    serial_cs.c 1.118 2000/05/04 01:29:47
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -58,7 +58,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"serial_cs.c 1.117 1999/12/11 03:59:18 (David Hinds)";
+"serial_cs.c 1.118 2000/05/04 01:29:47 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -206,7 +206,6 @@
 {
     serial_info_t *info = link->priv;
     dev_link_t **linkp;
-    long flags;
     int ret;
 
     DEBUG(0, "serial_detach(0x%p)\n", link);
@@ -217,14 +216,7 @@
     if (*linkp == NULL)
 	return;
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-    
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	serial_release((u_long)link);
     
@@ -610,11 +602,8 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    link->release.expires = jiffies + HZ/20;
-	    link->state |= DEV_RELEASE_PENDING;
-	    add_timer(&link->release);
-	}
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.3.99-pre6/linux/drivers/char/planb.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/planb.c	Wed May  3 01:45:19 2000
@@ -2200,6 +2200,7 @@
 	unsigned char		dev_fn, confreg, bus;
 	unsigned int		old_base, new_base;
 	unsigned int		irq;
+	struct pci_dev 		*pdev;
 
 	if (_machine != _MACH_Pmac)
 		return 0;
@@ -2251,17 +2252,23 @@
 		"membase 0x%x (base reg. 0x%x)\n",
 		bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
 
+	pdev = pci_find_slot (bus, dev_fn);
+	if (!pdev) {
+		printk(KERN_ERR "cannot find slot\n");
+		/* XXX handle error */
+	}
+
 	/* Enable response in memory space, bus mastering,
 	   use memory write and invalidate */
-	pcibios_write_config_word (bus, dev_fn, PCI_COMMAND,
+	pci_write_config_word (pdev, PCI_COMMAND,
 		PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
 		PCI_COMMAND_INVALIDATE);
 	/* Set PCI Cache line size & latency timer */
-	pcibios_write_config_byte (bus, dev_fn, PCI_CACHE_LINE_SIZE, 0x8);
-	pcibios_write_config_byte (bus, dev_fn, PCI_LATENCY_TIMER, 0x40);
+	pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, 0x8);
+	pci_write_config_byte (pdev, PCI_LATENCY_TIMER, 0x40);
 
 	/* Set the new base address */
-	pcibios_write_config_dword (bus, dev_fn, confreg, new_base);
+	pci_write_config_dword (pdev, confreg, new_base);
 
 	planb_regs = (volatile struct planb_registers *)
 						ioremap (new_base, 0x400);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.3.99-pre6/linux/drivers/char/radio-cadet.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/radio-cadet.c	Wed May  3 01:45:19 2000
@@ -39,7 +39,6 @@
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
 static int cadet_lock=0;
-static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
@@ -562,7 +561,7 @@
 }
 #endif
 
-int __init cadet_init(void)
+static int __init cadet_init(void)
 {
 #ifndef MODULE        
 	io = cadet_probe ();
@@ -572,12 +571,14 @@
 #ifdef MODULE        
 		printk(KERN_ERR "You must set an I/O address with io=0x???\n");
 #endif
-	        return EINVAL;
+	        return -EINVAL;
 	}
-	if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1)
+	if (!request_region(io,2,"cadet"))
+		return -EBUSY;
+	if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) {
+		release_region(io,2);
 		return -EINVAL;
-		
-	request_region(io,2,"cadet");
+	}
 	printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/Makefile linux/drivers/char/rio/Makefile
--- v2.3.99-pre6/linux/drivers/char/rio/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/Makefile	Wed May 10 16:56:43 2000
@@ -0,0 +1,22 @@
+#
+# Makefile for the linux rio-subsystem.
+#
+# (C) R.E.Wolff@BitWizard.nl 
+# 
+# This file is GPL. See other files for the full Blurb. I'm lazy today. 
+#
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := rio.o
+O_OBJS   := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+            rioparam.o riopcicopy.o rioroute.o riotable.o riotty.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+rio.o: $(O_OBJS)
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/board.h linux/drivers/char/rio/board.h
--- v2.3.99-pre6/linux/drivers/char/rio/board.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/board.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources. 
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: board.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:07
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)board.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_board_h__
+#define	__rio_board_h__
+
+#ifdef SCCS_LABELS
+static char *_board_h_sccs_ = "@(#)board.h	1.2";
+#endif
+
+/*
+** board.h contains the definitions for the *hardware* of the host cards.
+** It describes the memory overlay for the dual port RAM area.
+*/
+
+#define	DP_SRAM1_SIZE	0x7C00
+#define	DP_SRAM2_SIZE	0x0200
+#define	DP_SRAM3_SIZE	0x7000
+#define	DP_SCRATCH_SIZE	0x1000
+#define	DP_PARMMAP_ADDR	0x01FE	/* offset into SRAM2 */
+#define	DP_STARTUP_ADDR	0x01F8	/* offset into SRAM2 */
+
+/*
+**	The shape of the Host Control area, at offset 0x7C00, Write Only
+*/
+struct s_Ctrl
+{
+	BYTE	DpCtl;				/* 7C00 */
+	BYTE	Dp_Unused2_[127];
+	BYTE	DpIntSet;			/* 7C80 */
+	BYTE	Dp_Unused3_[127];
+	BYTE	DpTpuReset;			/* 7D00 */
+	BYTE	Dp_Unused4_[127];
+	BYTE	DpIntReset;			/* 7D80 */
+	BYTE	Dp_Unused5_[127];
+};
+
+/*
+** The PROM data area on the host (0x7C00), Read Only
+*/
+struct s_Prom
+{
+	WORD	DpSlxCode[2];
+	WORD	DpRev;
+	WORD	Dp_Unused6_;
+	WORD	DpUniq[4];
+	WORD	DpJahre;
+	WORD	DpWoche;
+	WORD	DpHwFeature[5];
+	WORD	DpOemId;
+	WORD	DpSiggy[16];
+};
+
+/*
+** Union of the Ctrl and Prom areas
+*/
+union u_CtrlProm	/* This is the control/PROM area (0x7C00) */
+{
+	struct s_Ctrl	DpCtrl;
+	struct s_Prom	DpProm;
+};
+
+/*
+** The top end of memory!
+*/
+struct s_ParmMapS		/* Area containing Parm Map Pointer */
+{
+	BYTE	Dp_Unused8_[DP_PARMMAP_ADDR];
+	WORD	DpParmMapAd;
+};
+
+struct s_StartUpS
+{
+	BYTE    Dp_Unused9_[DP_STARTUP_ADDR];
+	BYTE	Dp_LongJump[0x4];
+	BYTE	Dp_Unused10_[2];
+	BYTE	Dp_ShortJump[0x2];
+};
+
+union u_Sram2ParmMap	/* This is the top of memory (0x7E00-0x7FFF) */
+{
+	BYTE	DpSramMem[DP_SRAM2_SIZE];
+	struct s_ParmMapS DpParmMapS;
+	struct s_StartUpS DpStartUpS;
+};
+
+/*
+**	This is the DP RAM overlay.
+*/
+struct DpRam
+{
+    BYTE 		 DpSram1[DP_SRAM1_SIZE];     /* 0000 - 7BFF */
+    union u_CtrlProm     DpCtrlProm;                 /* 7C00 - 7DFF */
+    union u_Sram2ParmMap DpSram2ParmMap;             /* 7E00 - 7FFF */
+    BYTE		 DpScratch[DP_SCRATCH_SIZE]; /* 8000 - 8FFF */
+    BYTE		 DpSram3[DP_SRAM3_SIZE];     /* 9000 - FFFF */
+};
+
+#define	DpControl	DpCtrlProm.DpCtrl.DpCtl
+#define	DpSetInt	DpCtrlProm.DpCtrl.DpIntSet
+#define	DpResetTpu	DpCtrlProm.DpCtrl.DpTpuReset
+#define	DpResetInt	DpCtrlProm.DpCtrl.DpIntReset
+
+#define	DpSlx		DpCtrlProm.DpProm.DpSlxCode
+#define	DpRevision	DpCtrlProm.DpProm.DpRev
+#define	DpUnique	DpCtrlProm.DpProm.DpUniq
+#define	DpYear		DpCtrlProm.DpProm.DpJahre
+#define	DpWeek		DpCtrlProm.DpProm.DpWoche
+#define	DpSignature	DpCtrlProm.DpProm.DpSiggy
+
+#define	DpParmMapR	DpSram2ParmMap.DpParmMapS.DpParmMapAd
+#define	DpSram2		DpSram2ParmMap.DpSramMem
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/bootpkt.h linux/drivers/char/rio/bootpkt.h
--- v2.3.99-pre6/linux/drivers/char/rio/bootpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/bootpkt.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,62 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******        B O O T    P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_bootpkt_h_sccs = "@(#)bootpkt.h	1.1" ;
+#endif
+#endif
+
+    /*************************************************
+     * Overlayed onto the Data fields of a regular
+     * Packet
+     ************************************************/
+typedef struct BOOT_PKT BOOT_PKT ;
+struct BOOT_PKT {
+                    short     seq_num ;
+                    char      data[10] ;
+                } ;
+
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/brates.h linux/drivers/char/rio/brates.h
--- v2.3.99-pre6/linux/drivers/char/rio/brates.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/brates.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *******                                                              *******
+ *******		BRATES.H				      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    : 1 Nov 1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _brates_h
+#ifndef lint
+/* static char * _brates_h_sccs = "@(#)brates.h	1.4"; */
+#endif
+#define _brates_h 1
+/* List of baud rate defines. Most are borrowed from /usr/include/sys/termio.h
+*/
+#ifndef INKERNEL
+
+#define	B0	0x00
+#define	B50	0x01
+#define	B75	0x02
+#define	B110	0x03
+#define	B134	0x04
+#define	B150	0x05
+#define	B200	0x06
+#define	B300	0x07
+#define	B600	0x08
+#define	B1200	0x09
+#define	B1800	0x0a
+#define	B2400	0x0b
+#define	B4800	0x0c
+#define	B9600	0x0d
+#define	B19200	0x0e
+#define	B38400	0x0f
+
+#endif
+
+/*
+** The following baudrates may or may not be defined
+** on various UNIX systems.
+** If they are not then we define them.
+** If they are then we do not define them ;-)
+**
+** This is appalling that we use same definitions as UNIX
+** for our own download code as there is no garuntee that
+** B57600 will be defined as 0x11 by a UNIX system....
+** Arghhhhh!!!!!!!!!!!!!!
+*/
+#if !defined(B56000)
+#define	B56000	0x10
+#endif
+
+#if !defined(B57600)
+#define	B57600	0x11
+#endif
+
+#if !defined(B64000)
+#define	B64000	0x12
+#endif
+
+#if !defined(B115200)
+#define	B115200	0x13
+#endif
+
+
+#if !defined(B2000)
+#define B2000	0x14
+#endif
+
+
+#define MAX_RATE B2000
+
+struct    baud_rate            /* Tag for baud rates */
+{
+     /* short    host_rate,*/        /* As passed by the driver */
+     short    divisor,          /* The divisor */
+              prescaler;        /* The pre-scaler */
+};
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/cdproto.h linux/drivers/char/rio/cdproto.h
--- v2.3.99-pre6/linux/drivers/char/rio/cdproto.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cdproto.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,55 @@
+/* 
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef _cirrusprots_h
+#define _cirrusprots_h
+
+#ifdef RTA
+extern void cd1400_reset ( int uart) ;
+extern void cd1400_init ( int uart ) ;
+extern void ccr_wait ( int priority, int port) ;
+extern void cd1400_txstart( int port) ;
+extern void cd1400_rxstart ( int port) ;
+extern void command_acknowledge ( PHB *port_header ) ;
+extern int close_port ( ushort port, PHB *port_header, ushort preemptive, int pseudo) ;
+extern void command_preemptive ( PKT *packet) ;
+extern void rup_service ( void ) ;
+extern ushort GetModemLines(struct PHB *, register short *);
+extern void cd1400_intr (Process *cirrus_p, ushort *RtaType) ;
+extern void cd1400_mdint ( short port) ;
+extern void cd1400_rxint ( short port) ;
+extern void cd1400_rxexcept ( short port) ;
+extern void cd1400_txdata ( short port, PHB *port_header, PKT *packet) ;
+extern void cd1400_fast_clock(void);
+extern void cd1400_map_baud ( ushort host_rate, ushort *prescaler, ushort *divisor) ;
+extern void cd1400_modem ( ushort port, ushort way) ;
+extern void cd1400_txcommand ( short port, PHB *port_header, PKT *packet) ;
+extern void cd1400_txint ( int port) ;
+void Rprintf( char *RIOPrBuf, char *Str, ... );
+#if defined(DCIRRUS)
+void debug_packet(PKT *pkt, int option, char *string, int channel);
+#endif	/* defined(DCIRRUS) */
+#endif
+
+#ifdef HOST
+extern void wflush (PHB *);
+extern void command_preemptive (PKT *);
+#endif
+
+#endif /* _cirrusprots_h */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/chan.h linux/drivers/char/rio/chan.h
--- v2.3.99-pre6/linux/drivers/char/rio/chan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/chan.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,33 @@
+/*
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef _chan_h
+#define _chan_h
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_chan_h_sccs = "@(#)chan.h	1.1" ;
+#endif
+#endif
+
+#define Link0   0
+#define Link1   1
+#define Link2   2
+#define Link3   3
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/cirrus.h linux/drivers/char/rio/cirrus.h
--- v2.3.99-pre6/linux/drivers/char/rio/cirrus.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cirrus.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,463 @@
+/****************************************************************************
+ *******                                                              *******
+ *******		CIRRUS.H				      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    : 3 Aug 1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _cirrus_h
+#ifndef lint
+/* static char* _cirrus_h_sccs = "@(#)cirrus.h	1.16"; */
+#endif
+#define _cirrus_h 1
+
+#ifdef RTA
+#define	TO_UART	RX
+#define TO_DRIVER TX
+#endif
+
+#ifdef HOST
+#define	TO_UART	TX
+#define TO_DRIVER RX
+#endif
+#ifdef RTA
+/* Miscellaneous defines for CIRRUS addresses and related logic for
+   interrupts etc.
+*/
+#define	MAP(a)		((short *)(cirrus_base + (a)))
+#define outp(a,b)	(*MAP (a) =(b))
+#define inp(a)		((*MAP (a)) & 0xff)
+#define	CIRRUS_FIRST	(short*)0x7300
+#define	CIRRUS_SECOND	(short*)0x7200
+#define	CIRRUS_THIRD	(short*)0x7100
+#define	CIRRUS_FOURTH	(short*)0x7000
+#define	PORTS_ON_CIRRUS	4
+#define	CIRRUS_FIFO_SIZE	12
+#define	SPACE		0x20
+#define	TAB		0x09
+#define	LINE_FEED	0x0a
+#define	CARRIAGE_RETURN	0x0d
+#define	BACKSPACE	0x08
+#define	SPACES_IN_TABS	8
+#define	SEND_ESCAPE	0x00
+#define START_BREAK	0x81
+#define	TIMER_TICK	0x82
+#define STOP_BREAK	0x83
+#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH)))
+#define txack1	((short *)0x7104) 
+#define rxack1	((short *)0x7102) 
+#define mdack1  ((short *)0x7106)
+#define txack2  ((short *)0x7006) 
+#define rxack2	((short *)0x7004) 
+#define mdack2  ((short *)0x7100) 
+#define int_latch       ((short *) 0x7800)
+#define int_status      ((short *) 0x7c00) 
+#define tx1_pending     0x20 
+#define rx1_pending     0x10 
+#define md1_pending     0x40 
+#define tx2_pending     0x02 
+#define rx2_pending     0x01 
+#define md2_pending     0x40 
+#define module1_bits	0x07
+#define module1_modern	0x08
+#define module2_bits	0x70
+#define module2_modern	0x80
+#define module_blank	0xf
+#define rs232_d25	0x0
+#define	rs232_rj45	0x1
+#define rs422_d25	0x3
+#define parallel	0x5
+
+#define	CLK0	0x00
+#define CLK1	0x01
+#define CLK2	0x02
+#define CLK3	0x03
+#define CLK4	0x04
+
+#define CIRRUS_REVC    0x42
+#define CIRRUS_REVE    0x44
+
+#define	TURNON	1
+#define TURNOFF 0
+
+/* The list of CIRRUS registers. 
+   NB. These registers are relative values on 8 bit boundaries whereas
+   on the RTA's the CIRRUS registers are on word boundaries. Use pointer
+   arithmetic (short *) to obtain the real addresses required */
+#define ccr	0x05	/* Channel Command Register     */
+#define ier	0x06	/* Interrupt Enable Register    */
+#define cor1	0x08	/* Channel Option Register 1    */
+#define cor2	0x09	/* Channel Option Register 2    */
+#define cor3	0x0a	/* Channel Option Register 3    */
+#define cor4	0x1e	/* Channel Option Register 4    */
+#define	cor5	0x1f	/* Channel Option Register 5	*/
+
+#define ccsr	0x0b	/* Channel Control Status Register */
+#define rdcr	0x0e	/* Receive Data Count Register  */
+#define tdcr	0x12	/* Transmit Data Count Register */
+#define mcor1	0x15	/* Modem Change Option Register 1 */
+#define mcor2	0x16	/* Modem Change Option Regsiter 2 */
+
+#define livr	0x18	/* Local Interrupt Vector Register */
+#define schr1	0x1a	/* Special Character Register 1 */
+#define schr2	0x1b	/* Special Character Register 2 */
+#define schr3	0x1c	/* Special Character Register 3 */
+#define schr4	0x1d	/* Special Character Register 4 */
+
+#define rtr	0x20    /* Receive Timer Register */
+#define rtpr	0x21	/* Receive Timeout Period Register */
+#define lnc	0x24	/* Lnext character */
+
+#define rivr	0x43	/* Receive Interrupt Vector Register    */
+#define tivr	0x42	/* Transmit Interrupt Vector Register   */
+#define mivr	0x41	/* Modem Interrupt Vector Register      */
+#define gfrcr	0x40	/* Global Firmware Revision code Reg    */
+#define ricr	0x44	/* Receive Interrupting Channel Reg     */
+#define ticr	0x45	/* Transmit Interrupting Channel Reg    */
+#define micr	0x46	/* Modem Interrupting Channel Register  */
+
+#define gcr	0x4b	/* Global configuration register*/
+#define misr    0x4c    /* Modem interrupt status register */
+
+#define rbusr	0x59
+#define tbusr	0x5a
+#define mbusr	0x5b
+
+#define eoir	0x60	/* End Of Interrupt Register */
+#define rdsr	0x62	/* Receive Data / Status Register */
+#define tdr	0x63	/* Transmit Data Register */
+#define svrr	0x67	/* Service Request Register */
+
+#define car	0x68	/* Channel Access Register */
+#define mir	0x69	/* Modem Interrupt Register */
+#define tir	0x6a	/* Transmit Interrupt Register */
+#define rir	0x6b	/* Receive Interrupt Register */
+#define msvr1	0x6c	/* Modem Signal Value Register 1 */
+#define msvr2	0x6d	/* Modem Signal Value Register 2*/
+#define psvr	0x6f	/* Printer Signal Value Register*/
+
+#define tbpr	0x72	/* Transmit Baud Rate Period Register */
+#define tcor	0x76	/* Transmit Clock Option Register */
+
+#define rbpr	0x78	/* Receive Baud Rate Period Register */
+#define rber	0x7a	/* Receive Baud Rate Extension Register */
+#define rcor	0x7c	/* Receive Clock Option Register*/
+#define ppr	0x7e	/* Prescalar Period Register    */
+
+/* Misc registers used for forcing the 1400 out of its reset woes */
+#define airl	0x6d
+#define airm	0x6e
+#define airh	0x6f
+#define btcr	0x66
+#define mtcr	0x6c
+#define tber	0x74
+
+#endif				/* #ifdef RTA */
+
+
+/* Bit fields for particular registers */
+
+/* GCR */
+#define GCR_SERIAL	0x00	/* Configure as serial channel */
+#define GCR_PARALLEL	0x80	/* Configure as parallel channel */
+
+/* RDSR - when status read from FIFO */
+#define	RDSR_BREAK		0x08	/* Break received */
+#define RDSR_TIMEOUT    	0x80    /* No new data timeout */
+#define RDSR_SC1  	  	0x10    /* Special char 1 (tx XON) matched */
+#define RDSR_SC2  	  	0x20    /* Special char 2 (tx XOFF) matched */
+#define RDSR_SC12_MASK	  	0x30    /* Mask for special chars 1 and 2 */
+
+/* PPR */
+#define PPR_DEFAULT	0x31	/* Default value - for a 25Mhz clock gives
+				   a timeout period of 1ms */
+
+/* LIVR */
+#define	LIVR_EXCEPTION	0x07	/* Receive exception interrupt */
+
+/* CCR */
+#define	CCR_RESET	0x80	/* Reset channel */
+#define	CCR_CHANGE	0x4e	/* COR's have changed - NB always change all
+				   COR's */
+#define	CCR_WFLUSH	0x82	/* Flush transmit FIFO and TSR / THR */
+
+#define	CCR_SENDSC1	0x21	/* Send special character one */
+#define CCR_SENDSC2	0x22	/* Send special character two */
+#define CCR_SENDSC3	0x23	/* Send special character three */
+#define CCR_SENDSC4	0x24	/* Send special character four */
+
+#define CCR_TENABLE	0x18	/* Enable transmitter */
+#define	CCR_TDISABLE	0x14	/* Disable transmitter */
+#define CCR_RENABLE	0x12	/* Enable receiver */
+#define CCR_RDISABLE	0x11	/* Disable receiver */
+
+#define	CCR_READY	0x00	/* CCR is ready for another command */
+
+/* CCSR */
+#define CCSR_TXENABLE	0x08	/* Transmitter enable */
+#define CCSR_RXENABLE	0x80	/* Receiver enable */
+#define CCSR_TXFLOWOFF	0x04	/* Transmit flow off */
+#define CCSR_TXFLOWON	0x02	/* Transmit flow on */
+
+/* SVRR */
+#define	SVRR_RECEIVE	0x01	/* Receive interrupt pending */
+#define	SVRR_TRANSMIT	0x02	/* Transmit interrupt pending */
+#define	SVRR_MODEM	0x04	/* Modem interrupt pending */
+
+/* CAR */
+#define CAR_PORTS	0x03	/* Bit fields for ports */
+
+/* IER */
+#define	IER_MODEM	0x80	/* Change in modem status */
+#define	IER_RECEIVE	0x10	/* Good data / data exception */
+#define IER_TRANSMITR	0x04	/* Transmit ready (FIFO empty) */
+#define	IER_TRANSMITE	0x02	/* Transmit empty */
+#define IER_TIMEOUT	0x01	/* Timeout on no data */
+
+#define	IER_DEFAULT	0x94	/* Default values */
+#define IER_PARALLEL    0x84    /* Default for Parallel */
+#define	IER_EMPTY	0x92	/* Transmitter empty rather than ready */
+
+/* COR1 - Driver only */
+#define	COR1_INPCK	0x10	/* Check parity of received characters */
+
+/* COR1 - driver and RTA */
+#define	COR1_ODD	0x80	/* Odd parity */
+#define COR1_EVEN	0x00	/* Even parity */
+#define	COR1_NOP	0x00	/* No parity */
+#define	COR1_FORCE	0x20	/* Force parity */
+#define	COR1_NORMAL	0x40	/* With parity */
+#define	COR1_1STOP	0x00	/* 1 stop bit */
+#define	COR1_15STOP	0x04	/* 1.5 stop bits */
+#define	COR1_2STOP	0x08	/* 2 stop bits */
+#define	COR1_5BITS	0x00	/* 5 data bits */
+#define	COR1_6BITS	0x01	/* 6 data bits */
+#define	COR1_7BITS	0x02	/* 7 data bits */
+#define	COR1_8BITS	0x03	/* 8 data bits */
+
+#define COR1_HOST       0xef    /* Safe host bits */
+
+/* RTA only */
+#define COR1_CINPCK     0x00    /* Check parity of received characters */
+#define COR1_CNINPCK    0x10    /* Don't check parity */
+
+/* COR2 bits for both RTA and driver use */
+#define	COR2_IXANY	0x80	/* IXANY - any character is XON */
+#define	COR2_IXON	0x40	/* IXON - enable tx soft flowcontrol */
+#define	COR2_RTSFLOW	0x02	/* Enable tx hardware flow control */
+
+/* Additional driver bits */
+#define	COR2_HUPCL	0x20	/* Hang up on close */
+#define	COR2_CTSFLOW	0x04	/* Enable rx hardware flow control */
+#define	COR2_IXOFF	0x01	/* Enable rx software flow control */
+#define COR2_DTRFLOW	0x08	/* Enable tx hardware flow control */
+
+/* RTA use only */
+#define COR2_ETC	0x20	/* Embedded transmit options */
+#define	COR2_LOCAL	0x10	/* Local loopback mode */
+#define	COR2_REMOTE	0x08	/* Remote loopback mode */
+#define	COR2_HOST	0xc2	/* Safe host bits */
+
+/* COR3 - RTA use only */
+#define	COR3_SCDRNG	0x80	/* Enable special char detect for range */
+#define	COR3_SCD34	0x40	/* Special character detect for SCHR's 3 + 4 */
+#define	COR3_FCT	0x20	/* Flow control transparency */
+#define	COR3_SCD12	0x10	/* Special character detect for SCHR's 1 + 2 */
+#define	COR3_FIFO12	0x0c	/* 12 chars for receive FIFO threshold */
+#define COR3_FIFO10     0x0a    /* 10 chars for receive FIFO threshold */
+#define COR3_FIFO8      0x08    /* 8 chars for receive FIFO threshold */
+#define COR3_FIFO6      0x06    /* 6 chars for receive FIFO threshold */
+
+#define COR3_THRESHOLD  COR3_FIFO8	/* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define	COR3_DEFAULT	(COR3_FCT | COR3_THRESHOLD)
+				/* Default bits for COR3 */
+
+/* COR4 driver and RTA use */
+#define	COR4_IGNCR	0x80	/* Throw away CR's on input */
+#define	COR4_ICRNL	0x40	/* Map CR -> NL on input */
+#define	COR4_INLCR	0x20	/* Map NL -> CR on input */
+#define	COR4_IGNBRK	0x10	/* Ignore Break */
+#define	COR4_NBRKINT	0x08	/* No interrupt on break (-BRKINT) */
+#define COR4_RAISEMOD	0x01	/* Raise modem output lines on non-zero baud */
+
+
+/* COR4 driver only */
+#define COR4_IGNPAR	0x04	/* IGNPAR (ignore characters with errors) */
+#define COR4_PARMRK	0x02	/* PARMRK */
+
+#define COR4_HOST	0xf8	/* Safe host bits */
+
+/* COR4 RTA only */
+#define COR4_CIGNPAR	0x02	/* Thrown away bad characters */
+#define COR4_CPARMRK	0x04	/* PARMRK characters */
+#define COR4_CNPARMRK	0x03	/* Don't PARMRK */
+
+/* COR5 driver and RTA use */
+#define	COR5_ISTRIP	0x80	/* Strip input chars to 7 bits */
+#define	COR5_LNE	0x40	/* Enable LNEXT processing */
+#define	COR5_CMOE	0x20	/* Match good and errored characters */
+#define	COR5_ONLCR	0x02	/* NL -> CR NL on output */
+#define	COR5_OCRNL	0x01	/* CR -> NL on output */
+
+/*
+** Spare bits - these are not used in the CIRRUS registers, so we use
+** them to set various other features.
+*/
+/*
+** tstop and tbusy indication
+*/
+#define	COR5_TSTATE_ON	0x08	/* Turn on monitoring of tbusy and tstop */
+#define	COR5_TSTATE_OFF	0x04	/* Turn off monitoring of tbusy and tstop */
+/*
+** TAB3
+*/
+#define	COR5_TAB3	0x10	/* TAB3 mode */
+
+#define	COR5_HOST	0xc3	/* Safe host bits */
+
+/* CCSR */
+#define	CCSR_TXFLOFF	0x04	/* Tx is xoffed */
+
+/* MSVR1 */
+/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
+   RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
+   serial option.
+*/
+#define	MSVR1_CD	0x80	/* CD (DSR on Cirrus) */
+#define	MSVR1_RTS	0x40	/* RTS (CTS on Cirrus) */
+#define	MSVR1_RI	0x20	/* RI */
+#define	MSVR1_DTR	0x10	/* DTR (CD on Cirrus) */
+#define	MSVR1_CTS	0x01	/* CTS output pin (RTS on Cirrus) */
+/* Next two used to indicate state of tbusy and tstop to driver */
+#define	MSVR1_TSTOP	0x08	/* Set if port flow controlled */
+#define	MSVR1_TEMPTY	0x04	/* Set if port tx buffer empty */
+
+#define	MSVR1_HOST	0xf3	/* The bits the host wants */
+
+/* MSVR2 */
+#define	MSVR2_DSR	0x02	/* DSR output pin (DTR on Cirrus) */
+
+/* MCOR */
+#define	MCOR_CD	        0x80	/* CD (DSR on Cirrus) */
+#define	MCOR_RTS	0x40	/* RTS (CTS on Cirrus) */
+#define	MCOR_RI	        0x20	/* RI */
+#define	MCOR_DTR	0x10	/* DTR (CD on Cirrus) */
+
+#define MCOR_DEFAULT    (MCOR_CD | MCOR_RTS | MCOR_RI | MCOR_DTR)
+#define MCOR_FULLMODEM  MCOR_DEFAULT
+#define MCOR_RJ45       (MCOR_CD | MCOR_RTS | MCOR_DTR)
+#define MCOR_RESTRICTED (MCOR_CD | MCOR_RTS)
+
+/* More MCOR - H/W Handshake (flowcontrol) stuff */
+#define	MCOR_THRESH8	0x08	/* eight characters then we stop */
+#define	MCOR_THRESH9	0x09	/* nine characters then we stop */
+#define	MCOR_THRESH10	0x0A	/* ten characters then we stop */
+#define	MCOR_THRESH11	0x0B	/* eleven characters then we stop */
+
+#define	MCOR_THRESHBITS 0x0F	/* mask for ANDing out the above */
+
+#define	MCOR_THRESHOLD	MCOR_THRESH9 /* MUST BE GREATER THAN COR3_THRESHOLD */
+
+
+/* RTPR */
+#define RTPR_DEFAULT	0x02	/* Default */
+
+
+/* Defines for the subscripts of a CONFIG packet */
+#define	CONFIG_COR1	1	/* Option register 1 */
+#define	CONFIG_COR2	2	/* Option register 2 */
+#define	CONFIG_COR4	3	/* Option register 4 */
+#define	CONFIG_COR5	4	/* Option register 5 */
+#define	CONFIG_TXXON	5	/* Tx XON character */
+#define	CONFIG_TXXOFF	6	/* Tx XOFF character */
+#define	CONFIG_RXXON	7	/* Rx XON character */
+#define	CONFIG_RXXOFF	8	/* Rx XOFF character */
+#define CONFIG_LNEXT	9	/* LNEXT character */
+#define	CONFIG_TXBAUD	10	/* Tx baud rate */
+#define	CONFIG_RXBAUD	11	/* Rx baud rate */
+
+/* Port status stuff */
+#define	IDLE_CLOSED	0	/* Closed */
+#define IDLE_OPEN	1	/* Idle open */
+#define IDLE_BREAK	2	/* Idle on break */
+
+/* Subscript of MODEM STATUS packet */
+#define	MODEM_VALUE	3	/* Current values of handshake pins */
+/* Subscript of SBREAK packet */
+#define BREAK_LENGTH	1	/* Length of a break in slices of 0.01 seconds
+				   0 = stay on break until an EBREAK command
+				   is sent */
+
+
+#define	PRE_EMPTIVE	0x80	/* Pre-emptive bit in command field */
+
+/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
+   CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
+   be used 
+*/
+#define	OPEN		0x00	/* Open a port */
+#define CONFIG		0x01	/* Configure a port */
+#define	MOPEN		0x02	/* Modem open (block for DCD) */
+#define	CLOSE		0x03	/* Close a port */
+#define	WFLUSH		(0x04 | PRE_EMPTIVE) /* Write flush */
+#define	RFLUSH		(0x05 | PRE_EMPTIVE) /* Read flush */
+#define	RESUME		(0x06 | PRE_EMPTIVE) /* Resume if xoffed */
+#define	SBREAK		0x07 	/* Start break */
+#define	EBREAK		0x08	/* End break */
+#define	SUSPEND		(0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define FCLOSE          (0x0a | PRE_EMPTIVE) /* Force close */
+#define XPRINT          0x0b    /* Xprint packet */
+#define MBIS		(0x0c | PRE_EMPTIVE) /* Set modem lines */
+#define MBIC		(0x0d | PRE_EMPTIVE) /* Clear modem lines */
+#define MSET		(0x0e | PRE_EMPTIVE) /* Set modem lines */
+#define PCLOSE		0x0f	/* Pseudo close - Leaves rx/tx enabled */
+#define MGET		(0x10 | PRE_EMPTIVE) /* Force update of modem status */
+#define MEMDUMP		(0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define	READ_REGISTER	(0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */
+
+/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
+   use data[4] / data[3] to indicate current state and modem status respectively
+*/ 
+
+#define	COMPLETE	(0x20 | PRE_EMPTIVE)
+				/* Command complete */
+#define BREAK_RECEIVED	(0x21 | PRE_EMPTIVE)
+				/* Break received */
+#define MODEM_STATUS	(0x22 | PRE_EMPTIVE)
+				/* Change in modem status */
+
+/* "Command" packet that could go either way - handshake wake-up */
+#define HANDSHAKE	(0x23 | PRE_EMPTIVE)
+				/* Wake-up to HOST / RTA */
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/cmd.h linux/drivers/char/rio/cmd.h
--- v2.3.99-pre6/linux/drivers/char/rio/cmd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmd.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,84 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******           C O M M A N D   P A C K E T   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef _cmd_h
+#define _cmd_h
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_cmd_h_sccs = "@(#)cmd.h	1.1" ;
+#endif
+#endif
+
+
+#define PRE_EMPTIVE_CMD         0x80
+#define INLINE_CMD              ~PRE_EMPTIVE_CMD
+
+#define CMD_IGNORE_PKT          ( (ushort) 0)
+#define CMD_STATUS_REQ          ( (ushort) 1)
+#define CMD_UNIT_STATUS_REQ     ( (ushort) 2)     /* Is this needed ??? */
+#define CMD_CONF_PORT           ( (ushort) 3)
+#define CMD_CONF_UNIT           ( (ushort) 4)
+#define CMD_ROUTE_MAP_REQ       ( (ushort) 5)
+#define CMD_FLUSH_TX            ( (ushort) 6)
+#define CMD_FLUSH_RX            ( (ushort) 7)
+#define CMD_PARTION_PORT        ( (ushort) 8)
+#define CMD_RESET_PORT          ( (ushort) 0x0a)
+#define CMD_BOOT_UNIT           ( (ushort) 0x0b)
+#define CMD_FOUND_UNIT          ( (ushort) 0x0c)
+#define CMD_ATTACHED_RTA_2      ( (ushort) 0x0d)
+#define CMD_PROVIDE_BOOT        ( (ushort) 0x0e)
+#define CMD_CIRRUS              ( (ushort) 0x0f)
+
+#define FORM_STATUS_PKT         ( (ushort) 1 )
+#define FORM_POLL_PKT           ( (ushort) 2 )
+#define FORM_LINK_STATUS_PKT    ( (ushort) 3 )
+
+
+#define CMD_DATA_PORT           ( (ushort) 1 )
+#define CMD_DATA                ( (ushort) 2 )
+
+#define CMD_TX_PART             ( (ushort) 2 )
+#define CMD_RX_PART             ( (ushort) 3 )
+#define CMD_RX_LIMIT            ( (ushort) 4 )
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/cmdblk.h linux/drivers/char/rio/cmdblk.h
--- v2.3.99-pre6/linux/drivers/char/rio/cmdblk.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmdblk.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,60 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: cmdblk.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdblk.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_cmdblk_h__
+#define __rio_cmdblk_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_cmdblk_h_sccs_ = "@(#)cmdblk.h	1.2";
+#endif
+#endif
+
+/*
+** the structure of a command block, used to queue commands destined for
+** a rup.
+*/
+
+struct CmdBlk
+{
+ struct CmdBlk *NextP;          /* Pointer to next command block */
+ struct	PKT     Packet;         /* A packet, to copy to the rup */
+    	                        /* The func to call to check if OK */
+    	int     (*PreFuncP)(int, struct CmdBlk *);
+    	int     PreArg;         /* The arg for the func */
+    	                        /* The func to call when completed */
+    	int     (*PostFuncP)(int, struct CmdBlk *);
+    	int     PostArg;        /* The arg for the func */
+};
+
+#define NUM_RIO_CMD_BLKS (3 * (MAX_RUP * 4 + LINKS_PER_UNIT * 4))
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/cmdpkt.h linux/drivers/char/rio/cmdpkt.h
--- v2.3.99-pre6/linux/drivers/char/rio/cmdpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/cmdpkt.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,206 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: cmdpkt.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdpkt.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifndef __rio_cmdpkt_h__
+#define __rio_cmdpkt_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_cmdpkt_h_sccs_ = "@(#)cmdpkt.h	1.2";
+#endif
+#endif
+
+/*
+** overlays for the data area of a packet. Used in both directions
+** (to build a packet to send, and to interpret a packet that arrives)
+** and is very inconvenient for MIPS, so they appear as two seperate
+** structures - those used for modifying/reading packets on the card
+** and those for modifying/reading packets in real memory, which have an _M
+** suffix.
+*/
+
+#define	RTA_BOOT_DATA_SIZE (PKT_MAX_DATA_LEN-2)
+
+/*
+** The boot information packet looks like this:
+** This structure overlays a PktCmd->CmdData structure, and so starts
+** at Data[2] in the actual pkt!
+*/
+struct BootSequence
+{
+    WORD	NumPackets;
+    WORD	LoadBase;
+    WORD	CodeSize;
+};
+
+#define	BOOT_SEQUENCE_LEN	8
+
+struct SamTop
+{
+    BYTE Unit;
+    BYTE Link;
+};
+
+struct CmdHdr
+{
+    BYTE PcCommand;
+    union
+    {
+    BYTE PcPhbNum;
+    BYTE PcLinkNum;
+    BYTE PcIDNum;
+    } U0;
+};
+
+
+struct PktCmd
+{
+    union
+    {
+	struct 
+	{
+	    struct CmdHdr CmdHdr;
+	    struct BootSequence PcBootSequence;
+	} S1;
+	struct
+	{
+	    WORD PcSequence;
+	    BYTE PcBootData[RTA_BOOT_DATA_SIZE];
+	} S2;
+	struct
+	{
+	    WORD  __crud__;
+	    BYTE  PcUniqNum[4];	        /* this is really a uint. */
+	    BYTE  PcModuleTypes;  	/* what modules are fitted */
+	} S3;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    BYTE   __undefined__;
+	    BYTE   PcModemStatus;
+	    BYTE   PcPortStatus;
+	    BYTE   PcSubCommand;	/* commands like mem or register dump */
+	    WORD   PcSubAddr;		/* Address for command */
+	    BYTE   PcSubData[64];	/* Date area for command */
+	} S4;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    BYTE   PcCommandText[1];
+	    BYTE   __crud__[20];
+	    BYTE   PcIDNum2;		/* It had to go somewhere! */
+	} S5;
+	struct
+	{
+	    struct CmdHdr CmdHdr;
+	    struct SamTop    Topology[LINKS_PER_UNIT];
+	} S6;
+    } U1;
+};
+
+struct PktCmd_M
+{
+    union
+    {
+	struct 
+	{
+	    struct
+	    {
+    		uchar PcCommand;
+    		union
+    		{
+    		    uchar PcPhbNum;
+    		    uchar PcLinkNum;
+    		    uchar PcIDNum;
+    		} U0;
+	    } CmdHdr;
+	    struct
+	    {
+                ushort	NumPackets;
+                ushort	LoadBase;
+                ushort	CodeSize;
+            } PcBootSequence;
+	} S1;
+	struct
+	{
+	    ushort PcSequence;
+	    uchar PcBootData[RTA_BOOT_DATA_SIZE];
+	} S2;
+	struct
+	{
+	    ushort  __crud__;
+	    uchar  PcUniqNum[4];	        /* this is really a uint. */
+	    uchar  PcModuleTypes;  	/* what modules are fitted */
+	} S3;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    uchar   __undefined__;
+	    uchar   PcModemStatus;
+	    uchar   PcPortStatus;
+	    uchar   PcSubCommand;
+	    ushort  PcSubAddr;
+	    uchar   PcSubData[64];
+	} S4;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    uchar   PcCommandText[1];
+	    uchar   __crud__[20];
+	    uchar   PcIDNum2;		/* Tacked on end */
+	} S5;
+	struct
+	{
+	    ushort  __cmd_hdr__;
+	    struct Top Topology[LINKS_PER_UNIT];
+	} S6;
+    } U1;
+};
+
+#define Command		U1.S1.CmdHdr.PcCommand
+#define PhbNum		U1.S1.CmdHdr.U0.PcPhbNum
+#define IDNum		U1.S1.CmdHdr.U0.PcIDNum
+#define IDNum2		U1.S5.PcIDNum2
+#define LinkNum		U1.S1.CmdHdr.U0.PcLinkNum
+#define Sequence	U1.S2.PcSequence
+#define BootData	U1.S2.PcBootData
+#define BootSequence	U1.S1.PcBootSequence
+#define UniqNum		U1.S3.PcUniqNum
+#define ModemStatus	U1.S4.PcModemStatus
+#define PortStatus	U1.S4.PcPortStatus
+#define SubCommand	U1.S4.PcSubCommand
+#define SubAddr		U1.S4.PcSubAddr
+#define SubData		U1.S4.PcSubData
+#define CommandText	U1.S5.PcCommandText
+#define RouteTopology	U1.S6.Topology
+#define ModuleTypes	U1.S3.PcModuleTypes
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/control.h linux/drivers/char/rio/control.h
--- v2.3.99-pre6/linux/drivers/char/rio/control.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/control.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,62 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******           C O N T R O L   P A C K E T   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jon Brawn
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef _control_h
+#define _control_h
+
+#ifndef lint
+/* static char *_rio_control_h_sccs = "@(#)control.h	1.4"; */
+#endif
+
+#define	CONTROL		'^'
+#define IFOAD		( CONTROL + 1 )
+#define	IDENTIFY	( CONTROL + 2 )
+#define	ZOMBIE		( CONTROL + 3 )
+#define	UFOAD		( CONTROL + 4 )
+#define IWAIT		( CONTROL + 5 )
+
+#define	IFOAD_MAGIC	0xF0AD		/* of course */
+#define	ZOMBIE_MAGIC	(~0xDEAD)	/* not dead -> zombie */
+#define	UFOAD_MAGIC	0xD1E		/* kill-your-neighbour */
+#define	IWAIT_MAGIC	0xB1DE		/* Bide your time */
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/daemon.h linux/drivers/char/rio/daemon.h
--- v2.3.99-pre6/linux/drivers/char/rio/daemon.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/daemon.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,334 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: daemon.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)daemon.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_daemon_h__
+#define	__rio_daemon_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_daemon_h_sccs_ = "@(#)daemon.h	1.3";
+#endif
+#endif
+
+
+/*
+** structures used on /dev/rio
+*/
+
+struct Error
+{
+	uint	Error;
+	uint	Entry;
+	uint	Other;
+};
+
+struct DownLoad
+{
+	char	*DataP;
+	uint	Count;
+	uint	ProductCode;
+};
+
+/*
+** A few constants....
+*/
+#ifndef MAX_VERSION_LEN
+#define	MAX_VERSION_LEN	256
+#endif
+
+#ifndef MAX_XP_CTRL_LEN
+#define	MAX_XP_CTRL_LEN 16		/* ALSO IN PORT.H */
+#endif
+
+struct	PortSetup
+{
+	uint	From;	/* Set/Clear XP & IXANY Control from this port.... */
+	uint	To;	/* .... to this port */
+	uint	XpCps;			/* at this speed */
+	char	XpOn[MAX_XP_CTRL_LEN];	/* this is the start string */
+	char	XpOff[MAX_XP_CTRL_LEN];	/* this is the stop string */
+	uchar	IxAny;			/* enable/disable IXANY */
+	uchar	IxOn;			/* enable/disable IXON */
+	uchar	Lock;			/* lock port params */
+	uchar	Store;			/* store params across closes */
+	uchar	Drain;			/* close only when drained */
+};
+
+struct	LpbReq
+{
+	uint	Host;
+	uint	Link;
+	struct  LPB     *LpbP;
+};
+
+struct	RupReq
+{
+	uint	HostNum;
+	uint	RupNum;
+	struct  RUP 	*RupP;
+};
+
+struct	PortReq
+{
+	uint	SysPort;
+	struct  Port 	*PortP;
+};
+
+struct  StreamInfo
+{
+	uint	SysPort;
+#if 0
+	queue_t RQueue;
+	queue_t WQueue;
+#else
+	int RQueue;
+	int WQueue;
+#endif
+};
+
+struct	HostReq
+{
+	uint	HostNum;
+	struct  Host 	*HostP;
+};
+
+struct	HostDpRam
+{
+	uint	HostNum;
+	struct	DpRam	*DpRamP;
+};
+
+struct	DebugCtrl
+{
+	uint	SysPort;
+	uint	Debug;
+	uint	Wait;
+};
+
+struct	MapInfo
+{
+	uint	FirstPort;	/* 8 ports, starting from this (tty) number */
+	uint	RtaUnique;	/* reside on this RTA (unique number) */
+};
+
+struct	MapIn
+{
+	uint	NumEntries;		/* How many port sets are we mapping? */
+	struct  MapInfo	*MapInfoP;	/* Pointer to (user space) info */
+};
+
+struct  SendPack
+{
+        unsigned int	PortNum;
+	unsigned char	Len;
+	unsigned char	Data[PKT_MAX_DATA_LEN];
+};
+
+struct SpecialRupCmd
+{
+	struct	PKT		Packet;
+	unsigned short	Host;
+	unsigned short	RupNum;
+};
+
+struct	IdentifyRta
+{
+	ulong	RtaUnique;
+	uchar	ID;
+};
+
+struct	KillNeighbour
+{
+	ulong	UniqueNum;
+	uchar	Link;
+};
+
+struct rioVersion {
+    char        version[MAX_VERSION_LEN];
+    char        relid[MAX_VERSION_LEN];
+    int         buildLevel;
+    char        buildDate[MAX_VERSION_LEN];
+};
+
+
+/*
+**	RIOC commands are for the daemon type operations
+**
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in rioioctl.h, so we'd better do a
+** #ifndef here first.
+** rioioctl.h also now has #define 'RIO_QUICK_CHECK' as this ioctl is now
+** allowed to be used by customers.
+*/
+#ifndef RIOC
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+#endif
+
+/*
+** Boot stuff
+*/
+#define	RIO_GET_TABLE     (RIOC | 100)
+#define RIO_PUT_TABLE     (RIOC | 101)
+#define RIO_ASSIGN_RTA    (RIOC | 102)
+#define RIO_DELETE_RTA    (RIOC | 103)
+#define	RIO_HOST_FOAD	  (RIOC | 104)
+#define	RIO_QUICK_CHECK	  (RIOC | 105)
+#define RIO_SIGNALS_ON    (RIOC | 106)
+#define RIO_SIGNALS_OFF   (RIOC | 107)
+#define	RIO_CHANGE_NAME   (RIOC | 108)
+#define RIO_DOWNLOAD      (RIOC | 109)
+#define	RIO_GET_LOG	  (RIOC | 110)
+#define	RIO_SETUP_PORTS   (RIOC | 111)
+#define RIO_ALL_MODEM     (RIOC | 112)
+
+/*
+** card state, debug stuff
+*/
+#define	RIO_NUM_HOSTS	  (RIOC | 120)
+#define	RIO_HOST_LPB	  (RIOC | 121)
+#define	RIO_HOST_RUP	  (RIOC | 122)
+#define	RIO_HOST_PORT	  (RIOC | 123)
+#define	RIO_PARMS 	  (RIOC | 124)
+#define RIO_HOST_REQ	  (RIOC | 125)
+#define	RIO_READ_CONFIG	  (RIOC | 126)
+#define	RIO_SET_CONFIG	  (RIOC | 127)
+#define	RIO_VERSID	  (RIOC | 128)
+#define	RIO_FLAGS	  (RIOC | 129)
+#define	RIO_SETDEBUG	  (RIOC | 130)
+#define	RIO_GETDEBUG	  (RIOC | 131)
+#define	RIO_READ_LEVELS   (RIOC | 132)
+#define	RIO_SET_FAST_BUS  (RIOC | 133)
+#define	RIO_SET_SLOW_BUS  (RIOC | 134)
+#define	RIO_SET_BYTE_MODE (RIOC | 135)
+#define	RIO_SET_WORD_MODE (RIOC | 136)
+#define RIO_STREAM_INFO   (RIOC | 137)
+#define	RIO_START_POLLER  (RIOC | 138)
+#define	RIO_STOP_POLLER   (RIOC | 139)
+#define	RIO_LAST_ERROR    (RIOC | 140)
+#define	RIO_TICK	  (RIOC | 141)
+#define	RIO_TOCK	  (RIOC | 241)	/* I did this on purpose, you know. */
+#define	RIO_SEND_PACKET   (RIOC | 142)
+#define	RIO_SET_BUSY	  (RIOC | 143)
+#define	SPECIAL_RUP_CMD   (RIOC | 144)
+#define	RIO_FOAD_RTA      (RIOC | 145)
+#define	RIO_ZOMBIE_RTA    (RIOC | 146)
+#define RIO_IDENTIFY_RTA  (RIOC | 147)
+#define RIO_KILL_NEIGHBOUR (RIOC | 148)
+#define RIO_DEBUG_MEM     (RIOC | 149)
+/*
+** 150 - 167 used.....   See below
+*/
+#define RIO_GET_PORT_SETUP (RIOC | 168)
+#define RIO_RESUME        (RIOC | 169)
+#define	RIO_MESG	(RIOC | 170)
+#define	RIO_NO_MESG	(RIOC | 171)
+#define	RIO_WHAT_MESG	(RIOC | 172)
+#define RIO_HOST_DPRAM	(RIOC | 173)
+#define RIO_MAP_B50_TO_50	(RIOC | 174)
+#define RIO_MAP_B50_TO_57600	(RIOC | 175)
+#define RIO_MAP_B110_TO_110	(RIOC | 176)
+#define RIO_MAP_B110_TO_115200	(RIOC | 177)
+#define RIO_GET_PORT_PARAMS	(RIOC | 178)
+#define RIO_SET_PORT_PARAMS	(RIOC | 179)
+#define RIO_GET_PORT_TTY	(RIOC | 180)
+#define RIO_SET_PORT_TTY	(RIOC | 181)
+#define RIO_SYSLOG_ONLY	(RIOC | 182)
+#define RIO_SYSLOG_CONS	(RIOC | 183)
+#define RIO_CONS_ONLY	(RIOC | 184)
+#define RIO_BLOCK_OPENS	(RIOC | 185)
+
+/*
+** 02.03.1999 ARG - ESIL 0820 fix :
+** RIOBootMode is no longer use by the driver, so these ioctls
+** are now obsolete :
+**
+#define RIO_GET_BOOT_MODE	(RIOC | 186)
+#define RIO_SET_BOOT_MODE	(RIOC | 187)
+**
+*/
+
+#define RIO_MEM_DUMP	(RIOC | 189)
+#define RIO_READ_REGISTER	(RIOC | 190)
+#define RIO_GET_MODTYPE	(RIOC | 191)
+#define RIO_SET_TIMER	(RIOC | 192)
+#define RIO_READ_CHECK	(RIOC | 196)
+#define RIO_WAITING_FOR_RESTART	(RIOC | 197)
+#define RIO_BIND_RTA	(RIOC | 198)
+#define RIO_GET_BINDINGS	(RIOC | 199)
+#define RIO_PUT_BINDINGS	(RIOC | 200)
+
+#define	RIO_MAKE_DEV		(RIOC | 201)
+#define	RIO_MINOR		(RIOC | 202)
+
+#define	RIO_IDENTIFY_DRIVER	(RIOC | 203)
+#define	RIO_DISPLAY_HOST_CFG	(RIOC | 204)
+
+
+/*
+** MAKE_DEV / MINOR stuff
+*/
+#define	RIO_DEV_DIRECT		0x0000
+#define	RIO_DEV_MODEM		0x0200
+#define	RIO_DEV_XPRINT		0x0400
+#define	RIO_DEV_MASK		0x0600
+
+/*
+** port management, xprint stuff
+*/
+#define	rIOCN(N)	(RIOC|(N))
+#define	rIOCR(N,T)	(RIOC|(N))
+#define	rIOCW(N,T)	(RIOC|(N))
+
+#define	RIO_GET_XP_ON     rIOCR(150,char[16])	/* start xprint string */
+#define	RIO_SET_XP_ON     rIOCW(151,char[16])
+#define	RIO_GET_XP_OFF    rIOCR(152,char[16])	/* finish xprint string */
+#define	RIO_SET_XP_OFF    rIOCW(153,char[16])
+#define	RIO_GET_XP_CPS    rIOCR(154,int)	/* xprint CPS */
+#define	RIO_SET_XP_CPS    rIOCW(155,int)
+#define RIO_GET_IXANY     rIOCR(156,int)	/* ixany allowed? */
+#define RIO_SET_IXANY     rIOCW(157,int)
+#define RIO_SET_IXANY_ON  rIOCN(158)		/* allow ixany */
+#define RIO_SET_IXANY_OFF rIOCN(159)		/* disallow ixany */
+#define RIO_GET_MODEM     rIOCR(160,int)	/* port is modem/direct line? */
+#define RIO_SET_MODEM     rIOCW(161,int)
+#define RIO_SET_MODEM_ON  rIOCN(162)		/* port is a modem */
+#define RIO_SET_MODEM_OFF rIOCN(163)		/* port is direct */
+#define RIO_GET_IXON      rIOCR(164,int)	/* ixon allowed? */
+#define RIO_SET_IXON      rIOCW(165,int)
+#define RIO_SET_IXON_ON   rIOCN(166)		/* allow ixon */
+#define RIO_SET_IXON_OFF  rIOCN(167)		/* disallow ixon */
+
+#define RIO_GET_SIVIEW	  ((('s')<<8) | 106)	/* backwards compatible with SI */
+
+#define	RIO_IOCTL_UNKNOWN	-2
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/data.h linux/drivers/char/rio/data.h
--- v2.3.99-pre6/linux/drivers/char/rio/data.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/data.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,40 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: data.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)data.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_datadex__
+#define __rio_datadex__
+
+#ifndef lint
+static char *_data_h_sccs_ = "@(#)data.h	1.2";
+#endif
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/debug.h linux/drivers/char/rio/debug.h
--- v2.3.99-pre6/linux/drivers/char/rio/debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/debug.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,39 @@
+/*
+** File:		debug.h
+**
+** Author:		David Dix
+**
+** Created:		12th March 1993
+**
+** Last modified:	93/04/27
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _debug_h_
+#define _debug_h_
+
+
+#if defined(DCIRRUS)
+#define	DBPACKET(pkt, opt, str, chn) 	debug_packet((pkt), (opt), (str), (chn))
+#else
+#define	DBPACKET(pkt, opt, str, c)
+#endif	/* DCIRRUS */
+
+
+#endif	/* _debug_h_ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/defaults.h linux/drivers/char/rio/defaults.h
--- v2.3.99-pre6/linux/drivers/char/rio/defaults.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/defaults.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,59 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                     D E F A U L T S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_defaults_h_sccs = "@(#)defaults.h	1.1" ;
+#endif
+#endif
+
+
+#define MILLISECOND           (int) (1000/64)   /* 15.625 low ticks */
+#define SECOND                (int) 15625       /* Low priority ticks */
+
+#ifdef RTA
+#define RX_LIMIT       (ushort) 3
+#endif
+#ifdef HOST
+#define RX_LIMIT       (ushort) 1
+#endif
+
+#define LINK_TIMEOUT          (int) (POLL_PERIOD / 2)
+
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/eisa.h linux/drivers/char/rio/eisa.h
--- v2.3.99-pre6/linux/drivers/char/rio/eisa.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/eisa.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,104 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: eisa.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)eisa.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_eisa_h__
+#define __rio_eisa_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_eisa_h_sccs_ = "@(#)eisa.h	1.2";
+#endif
+#endif
+
+/*
+** things to do with the EISA bus
+*/
+
+#define RIO_EISA_STRING_ADDRESS 	0xfffd9	/* where EISA is stored */
+
+#define	RIO_MAX_EISA_SLOTS		16	/* how many EISA slots? */
+
+#define	RIO_EISA_IDENT			0x984D	/* Specialix */
+#define	RIO_EISA_PRODUCT_CODE		0x14	/* Code 14 */
+#define	RIO_EISA_ENABLE_BIT		0x01	/* To enable card */
+
+#define	EISA_MEMORY_BASE_LO		0xC00	/* A16-A23 */
+#define	EISA_MEMORY_BASE_HI		0xC01	/* A24-A31 */
+#define	EISA_INTERRUPT_VEC		0xC02	/* see below */
+#define	EISA_CONTROL_PORT		0xC02	/* see below */
+#define	EISA_INTERRUPT_RESET		0xC03	/* read to clear IRQ */
+
+#define	EISA_PRODUCT_IDENT_LO		0xC80	/* where RIO_EISA_IDENT is */
+#define	EISA_PRODUCT_IDENT_HI		0xC81
+#define	EISA_PRODUCT_NUMBER		0xC82   /* where PROD_CODE is */
+#define	EISA_REVISION_NUMBER		0xC83	/* revision (1dp) */
+#define	EISA_ENABLE			0xC84	/* set LSB to enable card */
+#define	EISA_UNIQUE_NUM_0		0xC88	/* vomit */
+#define	EISA_UNIQUE_NUM_1		0xC8A
+#define	EISA_UNIQUE_NUM_2		0xC90	/* bit strangely arranged */
+#define	EISA_UNIQUE_NUM_3		0xC92
+#define	EISA_MANUF_YEAR			0xC98	/* when */
+#define	EISA_MANUF_WEEK			0xC9A	/* more when */
+
+#define	EISA_TP_BOOT_FROM_RAM	0x01
+#define	EISA_TP_BOOT_FROM_LINK	0x00
+#define	EISA_TP_FAST_LINKS	0x02
+#define	EISA_TP_SLOW_LINKS	0x00
+#define	EISA_TP_BUS_ENABLE	0x04
+#define	EISA_TP_BUS_DISABLE	0x00
+#define	EISA_TP_RUN		0x08
+#define	EISA_TP_RESET		0x00
+#define	EISA_POLLED		0x00
+#define	EISA_IRQ_3		0x30
+#define	EISA_IRQ_4		0x40
+#define	EISA_IRQ_5		0x50
+#define	EISA_IRQ_6		0x60
+#define	EISA_IRQ_7		0x70
+#define	EISA_IRQ_9		0x90
+#define	EISA_IRQ_10		0xA0
+#define	EISA_IRQ_11		0xB0
+#define	EISA_IRQ_12		0xC0
+#define	EISA_IRQ_14		0xE0
+#define	EISA_IRQ_15		0xF0
+
+#define	EISA_INTERRUPT_MASK	0xF0
+#define	EISA_CONTROL_MASK	0x0F
+
+#define	RIO_EISA_DEFAULT_MODE	EISA_TP_SLOW_LINKS
+
+#define	RIOEisaToIvec(X)	(uchar )((uchar)((X) & EISA_INTERRUPT_MASK)>>4)
+
+#define	INBZ(z,x)	inb(((z)<<12) | (x))
+#define	OUTBZ(z,x,y)	outb((((z)<<12) | (x)), y)
+
+#endif /* __rio_eisa_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/enable.h linux/drivers/char/rio/enable.h
--- v2.3.99-pre6/linux/drivers/char/rio/enable.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/enable.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               E N A B L E   H E A D E R S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_enable_h_sccs = "@(#)enable.h	1.1" ;
+#endif
+#endif
+
+
+#define ENABLE_LTT  TRUE
+#define ENABLE_LRT  TRUE
+
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/error.h linux/drivers/char/rio/error.h
--- v2.3.99-pre6/linux/drivers/char/rio/error.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/error.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,85 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******     E R R O R  H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+/* static char *_rio_error_h_sccs = "@(#)error.h	1.3"; */
+#endif
+
+#define E_NO_ERROR                       ((ushort) 0)
+#define E_PROCESS_NOT_INIT               ((ushort) 1)
+#define E_LINK_TIMEOUT                   ((ushort) 2)
+#define E_NO_ROUTE                       ((ushort) 3)
+#define E_CONFUSED                       ((ushort) 4)
+#define E_HOME                           ((ushort) 5)
+#define E_CSUM_FAIL                      ((ushort) 6)
+#define E_DISCONNECTED                   ((ushort) 7)
+#define E_BAD_RUP                        ((ushort) 8)
+#define E_NO_VIRGIN                      ((ushort) 9)
+#define E_BOOT_RUP_BUSY                  ((ushort) 10)
+
+
+
+    /*************************************************
+     * Parsed to mem_halt()
+     ************************************************/
+#define E_CHANALLOC                      ((ushort) 0x80)
+#define E_POLL_ALLOC                     ((ushort) 0x81)
+#define E_LTTWAKE                        ((ushort) 0x82)
+#define E_LTT_ALLOC                      ((ushort) 0x83)
+#define E_LRT_ALLOC                      ((ushort) 0x84)
+#define E_CIRRUS                         ((ushort) 0x85)
+#define E_MONITOR                        ((ushort) 0x86)
+#define E_PHB_ALLOC                      ((ushort) 0x87)
+#define E_ARRAY_ALLOC                    ((ushort) 0x88)
+#define E_QBUF_ALLOC                     ((ushort) 0x89)
+#define E_PKT_ALLOC                      ((ushort) 0x8a)
+#define E_GET_TX_Q_BUF                   ((ushort) 0x8b)
+#define E_GET_RX_Q_BUF                   ((ushort) 0x8c)
+#define E_MEM_OUT                        ((ushort) 0x8d)
+#define E_MMU_INIT                       ((ushort) 0x8e)
+#define E_LTT_INIT                       ((ushort) 0x8f)
+#define E_LRT_INIT                       ((ushort) 0x90)
+#define E_LINK_RUN                       ((ushort) 0x91)
+#define E_MONITOR_ALLOC                  ((ushort) 0x92)
+#define E_MONITOR_INIT                   ((ushort) 0x93)
+#define E_POLL_INIT                      ((ushort) 0x94)
+
+
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/errors.h linux/drivers/char/rio/errors.h
--- v2.3.99-pre6/linux/drivers/char/rio/errors.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/errors.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,104 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: errors.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)errors.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_errors_h__
+#define	__rio_errors_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_errors_h_sccs_ = "@(#)errors.h	1.2";
+#endif
+#endif
+
+/*
+** error codes
+*/
+
+#define	NOTHING_WRONG_AT_ALL		0
+#define	BAD_CHARACTER_IN_NAME		1
+#define	TABLE_ENTRY_ISNT_PROPERLY_NULL	2
+#define	UNKNOWN_HOST_NUMBER		3
+#define	ZERO_RTA_ID			4
+#define	BAD_RTA_ID			5
+#define	DUPLICATED_RTA_ID		6
+#define	DUPLICATE_UNIQUE_NUMBER		7
+#define	BAD_TTY_NUMBER			8
+#define	TTY_NUMBER_IN_USE		9
+#define	NAME_USED_TWICE			10
+#define	HOST_ID_NOT_ZERO		11
+#define	BOOT_IN_PROGRESS		12
+#define	COPYIN_FAILED			13
+#define	HOST_FILE_TOO_LARGE		14
+#define	COPYOUT_FAILED			15
+#define	NOT_SUPER_USER			16
+#define	RIO_ALREADY_POLLING		17
+
+#define	ID_NUMBER_OUT_OF_RANGE		18
+#define PORT_NUMBER_OUT_OF_RANGE	19
+#define	HOST_NUMBER_OUT_OF_RANGE	20
+#define	RUP_NUMBER_OUT_OF_RANGE		21
+#define	TTY_NUMBER_OUT_OF_RANGE		22
+#define	LINK_NUMBER_OUT_OF_RANGE	23
+
+#define	HOST_NOT_RUNNING		24
+#define	IOCTL_COMMAND_UNKNOWN		25
+#define	RIO_SYSTEM_HALTED		26
+#define	WAIT_FOR_DRAIN_BROKEN		27
+#define	PORT_NOT_MAPPED_INTO_SYSTEM	28
+#define	EXCLUSIVE_USE_SET		29
+#define	WAIT_FOR_NOT_CLOSING_BROKEN	30
+#define	WAIT_FOR_PORT_TO_OPEN_BROKEN	31
+#define	WAIT_FOR_CARRIER_BROKEN		32
+#define	WAIT_FOR_NOT_IN_USE_BROKEN	33
+#define	WAIT_FOR_CAN_ADD_COMMAND_BROKEN	34
+#define	WAIT_FOR_ADD_COMMAND_BROKEN	35
+#define	WAIT_FOR_NOT_PARAM_BROKEN	36
+#define	WAIT_FOR_RETRY_BROKEN		37
+#define	HOST_HAS_ALREADY_BEEN_BOOTED	38
+#define	UNIT_IS_IN_USE			39
+#define	COULDNT_FIND_ENTRY		40
+#define	RTA_UNIQUE_NUMBER_ZERO		41
+#define	CLOSE_COMMAND_FAILED		42
+#define	WAIT_FOR_CLOSE_BROKEN		43
+#define	CPS_VALUE_OUT_OF_RANGE		44
+#define	ID_ALREADY_IN_USE		45
+#define	SIGNALS_ALREADY_SET		46
+#define	NOT_RECEIVING_PROCESS		47
+#define	RTA_NUMBER_WRONG		48
+#define NO_SUCH_PRODUCT			49
+#define	HOST_SYSPORT_BAD		50
+#define	ID_NOT_TENTATIVE		51
+#define XPRINT_CPS_OUT_OF_RANGE		52
+#define	NOT_ENOUGH_CORE_FOR_PCI_COPY	53
+
+
+#endif /* __rio_errors_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/formpkt.h linux/drivers/char/rio/formpkt.h
--- v2.3.99-pre6/linux/drivers/char/rio/formpkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/formpkt.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,154 @@
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******         F O R M   P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _formpkt_h
+#define _formpkt_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_formpkt_h_sccs = "@(#)formpkt.h	1.1" ;
+#endif
+#endif
+
+typedef struct FORM_BOOT_PKT_1 FORM_BOOT_PKT_1 ;
+struct FORM_BOOT_PKT_1 {
+                           ushort pkt_number ;
+                           ushort pkt_total ;
+                           ushort boot_top ;
+                       } ;
+
+typedef struct FORM_BOOT_PKT_2 FORM_BOOT_PKT_2 ;
+struct FORM_BOOT_PKT_2 {
+                           ushort pkt_number ;
+                           char   boot_data[10] ;
+                       } ;
+
+
+typedef struct FORM_ATTACH_RTA   FORM_ATTACH_RTA ;
+struct FORM_ATTACH_RTA  {
+                       char    cmd_code ;
+                       char    booter_serial[4] ;
+                       char    booter_link ;
+                       char    bootee_serial[4] ;
+                       char    bootee_link ;
+                   } ;
+
+
+typedef struct FORM_BOOT_ID   FORM_BOOT_ID ;
+struct FORM_BOOT_ID  {
+                       char    cmd_code ;
+                       char    bootee_serial[4] ;
+                       char    bootee_prod_id ;
+                       char    bootee_link ;
+                   } ;
+
+
+
+typedef struct FORM_ROUTE_1   FORM_ROUTE_1 ;
+struct FORM_ROUTE_1 {
+                        char     cmd_code ;
+                        char     pkt_number ;
+                        char     total_in_sequence ;
+                        char     unit_id ;
+                        char     host_unit_id ;
+                    } ;
+
+typedef struct FORM_ROUTE_2   FORM_ROUTE_2 ;
+struct FORM_ROUTE_2 {
+                        char   cmd_code ;
+                        char   pkt_number ;
+                        char   total_in_sequence ;
+                        char   route_data[9] ;
+                    } ;
+
+typedef struct FORM_ROUTE_REQ   FORM_ROUTE_REQ ;
+struct FORM_ROUTE_REQ {
+                          char   cmd_code ;
+                          char   pkt_number ;
+                          char   total_in_sequence ;
+                          char   route_data[10] ;
+                      } ;
+
+
+typedef struct FORM_ERROR   FORM_ERROR ;
+struct FORM_ERROR {
+                        char   cmd_code ;
+                        char   error_code ;
+
+                    } ;
+
+typedef struct FORM_STATUS   FORM_STATUS ;
+struct FORM_STATUS {
+                        char   cmd_code ;
+                        char   status_code ;
+                        char   last_packet_valid ;
+                        char   tx_buffer ;
+                        char   rx_buffer ;
+                        char   port_status ;
+                        char   phb_status ;
+                    } ;
+
+
+typedef struct FORM_LINK_STATUS   FORM_LINK_STATUS ;
+struct FORM_LINK_STATUS {
+                        char    cmd_code ;
+                        char    status_code ;
+                        char    link_number ;
+                        ushort  rx_errors ;
+                        ushort  tx_errors ;
+                        ushort  csum_errors ;
+                        ushort  disconnects ;
+                    } ;
+
+
+
+typedef struct FORM_PARTITION FORM_PARTITION ;
+struct FORM_PARTITION {
+                        char    cmd_code ;
+                        char    status_code ;
+                        char    port_number ;
+                        char    tx_max ;
+                        char    rx_max ;
+                        char    rx_limit ;
+                      } ;
+
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/func.h linux/drivers/char/rio/func.h
--- v2.3.99-pre6/linux/drivers/char/rio/func.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/func.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,171 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: func.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)func.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __func_h_def
+#define __func_h_def
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_func_h_sccs_ = "@(#)func.h	1.3";
+#endif
+#endif
+
+/* rioboot.c */
+int RIOBootCodeRTA(struct rio_info *, struct DownLoad *);
+int RIOBootCodeHOST(struct rio_info *, register struct DownLoad *);
+int RIOBootCodeUNKNOWN(struct rio_info *, struct DownLoad *);
+void msec_timeout(struct Host *);
+int RIOBootRup(struct rio_info *, uint, struct Host *, struct PKT *);
+int RIOBootComplete(struct rio_info *, struct Host *, uint, struct PktCmd *);
+int RIOBootOk(struct rio_info *,struct Host *, ulong);
+int RIORtaBound(struct rio_info *, uint); 
+void FillSlot(int, int, uint, struct Host *);
+
+/* riocmd.c */
+int RIOFoadRta(struct Host *, struct Map *);
+int RIOZombieRta(struct Host *, struct Map *);
+int RIOCommandRta(struct rio_info *, uint, int (* func)( struct Host *, 
+								struct Map *));
+int RIOIdentifyRta(struct rio_info *, caddr_t); 
+int RIOKillNeighbour(struct rio_info *, caddr_t);
+int RIOSuspendBootRta(struct Host *, int, int);
+int RIOFoadWakeup(struct rio_info *);
+int RIOCommandRup(struct rio_info *, uint, struct Host *, struct PKT *);
+struct CmdBlk * RIOGetCmdBlk(void);
+void RIOFreeCmdBlk(struct CmdBlk *);
+int RIOQueueCmdBlk(struct Host *, uint, struct CmdBlk *);
+void RIOPollHostCommands(struct rio_info *, struct Host *);
+int RIOStrlen(register char *);
+int RIOStrCmp(register char *, register char *);
+int RIOStrnCmp(register char *, register char *, int);
+void  RIOStrNCpy(char *, char *, int);
+int RIOWFlushMark(int, struct CmdBlk *);
+int RIORFlushEnable(int, struct CmdBlk *);
+int RIOUnUse(int, struct CmdBlk *);
+void ShowPacket(uint, struct PKT *);
+
+/* rioctrl.c */
+int copyin(int, caddr_t, int);
+int copyout(caddr_t, int, int);
+int riocontrol(struct rio_info *, dev_t,int,caddr_t,int); 
+int RIOPreemptiveCmd(struct rio_info *,struct Port *,uchar);
+
+/* rioinit.c */
+void rioinit(struct rio_info *, struct RioHostInfo *);
+void RIOInitHosts(struct rio_info *, struct RioHostInfo *);
+void RIOISAinit(struct rio_info *,int);
+int RIODoAT(struct rio_info *, int, int);
+caddr_t RIOCheckForATCard(int);
+int RIOAssignAT(struct rio_info *, int, caddr_t, int);
+int RIOBoardTest(paddr_t, caddr_t, uchar, int);
+int RIOScrub(int, BYTE *, int);
+void RIOAllocateInterrupts(struct rio_info *);
+void RIOStopInterrupts(struct rio_info *, int, int);
+void RIOAllocDataStructs(struct rio_info *);
+void RIOSetupDataStructs(struct rio_info *);
+int RIODefaultName(struct rio_info *, struct Host *, uint);
+int RIOReport(struct rio_info *);
+struct rioVersion * RIOVersid(void);
+int RIOMapin(paddr_t, int, caddr_t *);
+void RIOMapout(paddr_t, long, caddr_t);
+void RIOHostReset(uint, volatile struct DpRam *, uint);
+
+/* riointr.c */
+void riopoll(struct rio_info *);
+void riointr(struct rio_info *);
+void RIOTxEnable(char *);
+void RIOServiceHost(struct rio_info *, struct Host *, int);
+void RIOReceive(struct rio_info *, struct Port *);
+int riotproc(struct rio_info *, register struct ttystatics *, int, int);
+
+/* rioparam.c */
+int RIOParam(struct Port *, int, int, int);
+int RIODelay(struct Port *PortP, int);
+int RIODelay_ni(struct Port *PortP, int);
+void ms_timeout(struct Port *);
+int can_add_transmit(struct PKT **, struct Port *);
+void add_transmit(struct Port *);
+void put_free_end(struct Host *, struct PKT *);
+int can_remove_receive(struct PKT **, struct Port *);
+void remove_receive(struct Port *);
+
+/* rioroute.c */
+int RIORouteRup(struct rio_info *, uint, struct Host *, struct PKT *);
+void RIOFixPhbs(struct rio_info *, struct Host *, uint); 
+int RIOCheckIsolated(struct rio_info *, struct Host *, uint);
+int RIOIsolate(struct rio_info *, struct Host *, uint);
+int RIOCheck(struct Host *, uint);
+uint GetUnitType(uint);
+int RIOSetChange(struct rio_info *);
+void RIOConCon(struct rio_info *, struct Host *, uint, uint, uint, uint, int);
+int RIOFindFreeID(struct rio_info *, struct Host *, uint *, uint *);
+int RIOFreeDisconnected(struct rio_info *, struct Host *, int );
+int RIORemoveFromSavedTable(struct rio_info *, struct Map *);
+
+
+/* riotty.c */
+
+int riotopen(struct tty_struct * tty, struct file * filp);
+int riotclose(void  *ptr);
+int RIOCookMode(struct ttystatics *);
+int riotioctl(struct rio_info *, dev_t, register int, register caddr_t); 
+void ttyseth(struct Port *, struct ttystatics *, struct old_sgttyb *sg);
+
+/* riotable.c */
+int RIONewTable(struct rio_info *);
+int RIOApel(struct rio_info *);
+int RIODeleteRta(struct rio_info *, struct Map *);
+int RIOAssignRta(struct rio_info *, struct Map *);
+int RIOReMapPorts(struct rio_info *, struct Host *, struct Map *);
+int RIOChangeName(struct rio_info *, struct Map*);
+
+#if 0
+/* riodrvr.c */
+struct rio_info * rio_install(struct RioHostInfo *);
+int rio_uninstall(register struct rio_info *);
+int rio_open(struct rio_info *, int, struct file *);
+int rio_close(struct rio_info *, struct file *);
+int rio_read(struct rio_info *, struct file *, char *, int);
+int rio_write(struct rio_info *, struct file *	f, char *, int);
+int rio_ioctl(struct rio_info *, struct file *, int, char *);
+int rio_select(struct rio_info *, struct file *	f, int, struct sel *);
+int	rio_intr(char *);
+int rio_isr_thread(char  *);
+struct rio_info * rio_info_store( int cmd, struct rio_info * p);
+#endif
+
+extern int    rio_pcicopy(char *src, char *dst, int n);
+extern int rio_minor (kdev_t device);
+extern int rio_ismodem (kdev_t device);
+extern void rio_udelay (int usecs);
+
+#endif	/* __func_h_def */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/host.h linux/drivers/char/rio/host.h
--- v2.3.99-pre6/linux/drivers/char/rio/host.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/host.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,134 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: host.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)host.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_host_h__
+#define __rio_host_h__
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_host_h_sccs_ = "@(#)host.h	1.2";
+#endif
+#endif
+
+/*
+** the host structure - one per host card in the system.
+*/
+
+#define	MAX_EXTRA_UNITS	64
+
+/*
+**    Host data structure. This is used for the software equiv. of
+**    the host.
+*/
+struct    Host
+{
+    uchar             	    Type;      /* RIO_EISA, RIO_MCA, ... */
+    uchar             	    Ivec;      /* POLLED or ivec number */
+    uchar             	    Mode;      /* Control stuff */
+    uchar                   Slot;      /* Slot */
+    volatile caddr_t        Caddr;     /* KV address of DPRAM */
+    volatile struct DpRam   *CardP;    /* KV address of DPRAM, with overlay */
+    paddr_t          	    PaddrP;    /* Phys. address of DPRAM */
+    char                    Name[MAX_NAME_LEN];  /* The name of the host */
+    uint            	    UniqueNum; /* host unique number */
+    spinlock_t		    HostLock;  /* Lock structure for MPX */
+    /*struct pci_devinfo	    PciDevInfo; *//* PCI Bus/Device/Function stuff */
+    /*struct lockb	    HostLock;  *//* Lock structure for MPX */
+    uint                    WorkToBeDone; /* set to true each interrupt */
+    uint                    InIntr;    /* Being serviced? */
+    uint                    IntSrvDone;	/* host's interrupt has been serviced */
+    int			    (*Copy)( caddr_t, caddr_t, int ); /* copy func */
+    struct timer_list timer;
+    /*
+    **               I M P O R T A N T !
+    **
+    ** The rest of this data structure is cleared to zero after
+    ** a RIO_HOST_FOAD command.
+    */
+    
+    ulong                   Flags;     /* Whats going down */
+#define RC_WAITING            0
+#define RC_STARTUP            1
+#define RC_RUNNING            2
+#define RC_STUFFED            3
+#define RC_SOMETHING          4
+#define RC_SOMETHING_NEW      5
+#define RC_SOMETHING_ELSE     6
+#define RC_READY              7
+#define RUN_STATE             7
+/*
+** Boot mode applies to the way in which hosts in this system will
+** boot RTAs
+*/
+#define RC_BOOT_ALL           0x8	/* Boot all RTAs attached */
+#define RC_BOOT_OWN           0x10	/* Only boot RTAs bound to this system */
+#define RC_BOOT_NONE          0x20	/* Don't boot any RTAs (slave mode) */
+
+    struct Top		    Topology[LINKS_PER_UNIT]; /* one per link */
+    struct Map              Mapping[MAX_RUP];     /* Mappings for host */
+    struct PHB		    *PhbP;                /* Pointer to the PHB array */
+    ushort           	    *PhbNumP;             /* Ptr to Number of PHB's */
+    struct LPB 	            *LinkStrP ;           /* Link Structure Array */
+    struct RUP       	    *RupP;                /* Sixteen real rups here */
+    struct PARM_MAP  	    *ParmMapP;            /* points to the parmmap */
+    uint                    ExtraUnits[MAX_EXTRA_UNITS]; /* unknown things */
+    uint                    NumExtraBooted;       /* how many of the above */
+    /*
+    ** Twenty logical rups.
+    ** The first sixteen are the real Rup entries (above), the last four
+    ** are the link RUPs.
+    */
+    struct UnixRup	    UnixRups[MAX_RUP+LINKS_PER_UNIT];
+	int				timeout_id;	/* For calling 100 ms delays */
+	int				timeout_sem;/* For calling 100 ms delays */
+    int locks;
+    char             	    ____end_marker____;
+};
+#define Control      CardP->DpControl
+#define SetInt       CardP->DpSetInt
+#define ResetTpu     CardP->DpResetTpu
+#define ResetInt     CardP->DpResetInt
+#define Signature    CardP->DpSignature
+#define Sram1        CardP->DpSram1
+#define Sram2        CardP->DpSram2
+#define Sram3        CardP->DpSram3
+#define Scratch      CardP->DpScratch
+#define __ParmMapR   CardP->DpParmMapR
+#define SLX          CardP->DpSlx
+#define Revision     CardP->DpRevision
+#define Unique       CardP->DpUnique
+#define Year         CardP->DpYear
+#define Week         CardP->DpWeek
+
+#define RIO_DUMBPARM 0x0860    /* what not to expect */
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/hosthw.h linux/drivers/char/rio/hosthw.h
--- v2.3.99-pre6/linux/drivers/char/rio/hosthw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/hosthw.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,57 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                H O S T      H A R D W A R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_hosthw_h_sccs = "@(#)hosthw.h	1.2" ;
+#endif
+#endif
+
+#define SET_OTHER_INTERRUPT  ( (volatile u_short *) 0x7c80 )
+#define SET_EISA_INTERRUPT  ( (volatile u_short *) 0x7ef0 )
+
+#define EISA_HOST    0x30
+#define AT_HOST      0xa0
+#define MCA_HOST     0xb0
+#define PCI_HOST     0xd0
+
+#define PRODUCT_MASK 0xf0
+
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/link.h linux/drivers/char/rio/link.h
--- v2.3.99-pre6/linux/drivers/char/rio/link.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/link.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,188 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L I N K
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _link_h
+#define _link_h 1
+
+#ifndef lint
+#ifdef SCCS_LABELS
+/* static char *_rio_link_h_sccs = "@(#)link.h	1.15"; */
+#endif
+#endif
+
+
+
+/*************************************************
+ * Define the Link Status stuff
+ ************************************************/
+#define LRT_ACTIVE         ((ushort) 0x01)
+#define LRT_SPARE1         ((ushort) 0x02)
+#define INTRO_RCVD         ((ushort) 0x04)
+#define FORCED_DISCONNECT  ((ushort) 0x08)
+#define LRT_SPARE2	   ((ushort) 0x80)
+
+#define TOP_OF_RTA_RAM     ((ushort) 0x7000)
+#define HOST_SERIAL_POINTER (unsigned char **) (TOP_OF_RTA_RAM - 2 * sizeof (ushort))
+
+/* Flags for ltt_status */
+#define  WAITING_ACK		(ushort) 0x0001
+#define  DATA_SENT		(ushort) 0x0002
+#define  WAITING_RUP		(ushort) 0x0004
+#define  WAITING_RETRY		(ushort) 0x0008
+#define  WAITING_TOPOLOGY	(ushort) 0x0010
+#define  SEND_SYNC		(ushort) 0x0020
+#define  FOAD_THIS_LINK		(ushort) 0x0040
+#define  REQUEST_SYNC		(ushort) 0x0080
+#define  REMOTE_DYING		(ushort) 0x0100
+#define  DIE_NOW		(ushort) 0x0200
+
+/* Boot request stuff */
+#define BOOT_REQUEST       ((ushort) 0)    /* Request for a boot */
+#define BOOT_ABORT         ((ushort) 1)    /* Abort a boot */
+#define BOOT_SEQUENCE      ((ushort) 2)    /* Packet with the number of packets
+                                              and load address */
+#define BOOT_COMPLETED     ((ushort) 3)    /* Boot completed */
+
+/* States that a link can be in */
+#define	LINK_DISCONNECTED  ((ushort) 0)    /* Disconnected */
+#define LINK_BOOT1         ((ushort) 1)    /* Trying to send 1st stage boot */
+#define LINK_BOOT2         ((ushort) 2)    /* Trying to send 2nd stage boot */
+#define LINK_BOOT2WAIT     ((ushort) 3)    /* Waiting for selftest results */
+#define LINK_BOOT3         ((ushort) 4)    /* Trying to send 3rd stage boots */
+#define LINK_SYNC          ((ushort) 5)    /* Syncing */
+
+#define LINK_INTRO         ((ushort) 10)    /* Introductory packet */
+#define LINK_SUPPLYID      ((ushort) 11)    /* Trying to supply an ID */
+#define LINK_TOPOLOGY      ((ushort) 12)    /* Send a topology update */
+#define LINK_REQUESTID     ((ushort) 13)    /* Waiting for an ID */
+#define LINK_CONNECTED     ((ushort) 14)    /* Connected */
+
+#define LINK_INTERCONNECT  ((ushort) 20)   /* Subnets interconnected */
+
+#define LINK_SPARE	   ((ushort) 40)
+
+/*
+** Set the default timeout for link communications.
+*/
+#define	LINKTIMEOUT		(400 * MILLISECOND)
+
+/*
+** LED stuff
+*/
+#if defined(RTA)
+#define LED_OFF            ((ushort) 0)    /* LED off */
+#define LED_RED            ((ushort) 1)    /* LED Red */
+#define LED_GREEN          ((ushort) 2)    /* LED Green */
+#define LED_ORANGE         ((ushort) 4)    /* LED Orange */
+#define LED_1TO8_OPEN      ((ushort) 1)    /* Port 1->8 LED on */
+#define LED_9TO16_OPEN     ((ushort) 2)    /* Port 9->16 LED on */
+#define LED_SET_COLOUR(colour)	(link->led = (colour))
+#define LED_OR_COLOUR(colour)	(link->led |= (colour))
+#define LED_TIMEOUT(time)    (link->led_timeout = RioTimePlus(RioTime(),(time)))
+#else
+#define LED_SET_COLOUR(colour)
+#define LED_OR_COLOUR(colour)
+#define LED_TIMEOUT(time)
+#endif /* RTA */
+
+struct LPB {
+               WORD          link_number ;       /* Link Number */
+               Channel_ptr   in_ch ;             /* Link In Channel */
+               Channel_ptr   out_ch ;            /* Link Out Channel */
+#ifdef RTA
+               uchar        stat_led ;          /* Port open leds */
+               uchar        led ;               /* True, light led! */
+#endif
+               BYTE attached_serial[4]; /* Attached serial number */
+               BYTE attached_host_serial[4];
+                                                 /* Serial number of Host who
+                                                    booted the other end */
+               WORD          descheduled ;       /* Currently Descheduled */
+               WORD          state;              /* Current state */
+               WORD          send_poll ;         /* Send a Poll Packet */
+               Process_ptr   ltt_p ;             /* Process Descriptor */
+               Process_ptr   lrt_p ;             /* Process Descriptor */
+               WORD          lrt_status ;        /* Current lrt status */
+               WORD          ltt_status ;        /* Current ltt status */
+               WORD          timeout ;           /* Timeout value */
+               WORD          topology;           /* Topology bits */
+               WORD          mon_ltt ;
+               WORD          mon_lrt ;
+               WORD          WaitNoBoot ;	 /* Secs to hold off booting */
+               PKT_ptr       add_packet_list;    /* Add packets to here */
+               PKT_ptr       remove_packet_list; /* Send packets from here */
+#ifdef RTA
+#ifdef DCIRRUS
+#define    QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1) 
+#else
+#define    QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1) 
+#endif
+               PKT_ptr_ptr   rd_add ;            /* Add a new Packet here */
+               Q_BUF_ptr     rd_add_qb;          /* Pointer to the add Q buf */
+               PKT_ptr_ptr   rd_add_st_qbb ;     /* Pointer to start of the Q's buf */
+               PKT_ptr_ptr   rd_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+               PKT_ptr_ptr   rd_remove ;         /* Remove a Packet here */
+               Q_BUF_ptr     rd_remove_qb ;      /* Pointer to the remove Q buf */
+               PKT_ptr_ptr   rd_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+               PKT_ptr_ptr   rd_remove_end_qbb ; /* Pointer to the end of the Q buf */
+               ushort        pkts_in_q ;         /* Packets in queue */
+#endif
+
+               Channel_ptr   lrt_fail_chan ;     /* Lrt's failure channel */
+               Channel_ptr   ltt_fail_chan ;     /* Ltt's failure channel */
+
+#if defined (HOST) || defined (INKERNEL)
+ /* RUP structure for HOST to driver communications */
+               struct RUP           rup ;              
+#endif
+               struct RUP           link_rup;           /* RUP for the link (POLL,
+                                                    topology etc.) */
+               WORD          attached_link ;     /* Number of attached link */
+               WORD          csum_errors ;       /* csum errors */
+               WORD          num_disconnects ;   /* number of disconnects */
+               WORD          num_sync_rcvd ;     /* # sync's received */
+               WORD          num_sync_rqst ;     /* # sync requests */
+               WORD          num_tx ;            /* Num pkts sent */
+               WORD          num_rx ;            /* Num pkts received */
+               WORD          module_attached;    /* Module tpyes of attached */
+               WORD          led_timeout;        /* LED timeout */
+               WORD          first_port;         /* First port to service */
+               WORD          last_port;          /* Last port to service */
+           } ;
+
+#endif
+
+/*********** end of file ***********/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h
--- v2.3.99-pre6/linux/drivers/char/rio/linux_compat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/linux_compat.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,126 @@
+/*
+ * (C) 2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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 disable(oldspl) save_flags (oldspl)
+#define restore(oldspl) restore_flags (oldspl)
+
+#define sysbrk(x) kmalloc ((x), GFP_KERNEL)
+#define sysfree(p,size) kfree ((p))
+
+#define WBYTE(p,v) writeb(v, &p)
+#define RBYTE(p)   readb (&p)
+#define WWORD(p,v) writew(v, &p)
+#define RWORD(p)   readw(&p)
+#define WINDW(p,v) writew(v, p)
+#define RINDW(p)   readw(p)
+
+#define DEBUG_ALL
+
+#define cprintf printk
+
+#ifdef __KERNEL__
+#define INKERNEL
+#endif
+
+struct ttystatics {
+  struct termios tm;
+};
+
+#define bzero(d, n)         memset((d), 0, (n))
+#define bcopy(src, dest, n) memcpy ((dest), (src), (n))
+
+#define SEM_SIGIGNORE 0x1234
+
+
+#ifdef DEBUG_SEM
+#define swait(a,b)      printk ("waiting:    " __FILE__ " line %d\n", __LINE__)
+#define ssignal(sem)    printk ("signalling: " __FILE__ " line %d\n", __LINE__)
+
+#define sreset(sem)     printk ("sreset:     " __FILE__ "\n")
+#define sem_init(sem,v) printk ("sreset:     " __FILE__ "\n")
+#endif
+
+
+#define getpid()    (current->pid)
+
+#define major(dev) MAJOR(dev)
+#define minor(dev) MINOR(dev)
+
+#define QSIZE SERIAL_XMIT_SIZE
+
+#define pseterr(errno) return (- errno)
+
+#define V_CBAUD CBAUD
+
+/* For one reason or another rioboot.c uses delay instead of RIODelay. */
+#define delay(x,y) RIODelay(NULL, y)
+
+extern int rio_debug;
+
+#define rio_dprint(f, p) do {if (rio_debug & f) printk p;} while (0)
+
+#define RIO_DEBUG_INIT         0x000001
+#define RIO_DEBUG_BOOT         0x000002
+#define RIO_DEBUG_CMD          0x000004
+#define RIO_DEBUG_CTRL         0x000008
+#define RIO_DEBUG_INTR         0x000010
+#define RIO_DEBUG_PARAM        0x000020
+#define RIO_DEBUG_ROUTE        0x000040
+#define RIO_DEBUG_TABLE        0x000080
+#define RIO_DEBUG_TTY          0x000100
+#define RIO_DEBUG_FLOW         0x000200
+#define RIO_DEBUG_MODEMSIGNALS 0x000400
+#define RIO_DEBUG_PROBE        0x000800
+#define RIO_DEBUG_CLEANUP      0x001000
+#define RIO_DEBUG_IFLOW        0x002000
+#define RIO_DEBUG_PFE          0x004000
+#define RIO_DEBUG_REC          0x008000
+#define RIO_DEBUG_SPINLOCK     0x010000
+#define RIO_DEBUG_DELAY        0x020000
+
+
+/* Copied over from riowinif.h . This is ugly. The winif file declares
+also much other stuff which is incompatible with the headers from
+the older driver. The older driver includes "brates.h" which shadows
+the definitions from Linux, and is incompatible... */
+
+/* RxBaud and TxBaud definitions... */
+#define	RIO_B0			0x00			/* RTS / DTR signals dropped */
+#define	RIO_B50			0x01			/* 50 baud */
+#define	RIO_B75			0x02			/* 75 baud */
+#define	RIO_B110		0x03			/* 110 baud */
+#define	RIO_B134		0x04			/* 134.5 baud */
+#define	RIO_B150		0x05			/* 150 baud */
+#define	RIO_B200		0x06			/* 200 baud */
+#define	RIO_B300		0x07			/* 300 baud */
+#define	RIO_B600		0x08			/* 600 baud */
+#define	RIO_B1200		0x09			/* 1200 baud */
+#define	RIO_B1800		0x0A			/* 1800 baud */
+#define	RIO_B2400		0x0B			/* 2400 baud */
+#define	RIO_B4800		0x0C			/* 4800 baud */
+#define	RIO_B9600		0x0D			/* 9600 baud */
+#define	RIO_B19200		0x0E			/* 19200 baud */
+#define	RIO_B38400		0x0F			/* 38400 baud */
+#define	RIO_B56000		0x10			/* 56000 baud */
+#define	RIO_B57600		0x11			/* 57600 baud */
+#define	RIO_B64000		0x12			/* 64000 baud */
+#define	RIO_B115200		0x13			/* 115200 baud */
+#define	RIO_B2000		0x14			/* 2000 baud */
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/list.h linux/drivers/char/rio/list.h
--- v2.3.99-pre6/linux/drivers/char/rio/list.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/list.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,196 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L I S T                                 *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls.
+ Date    : 04-Nov-1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+ ***************************************************************************/
+
+#ifndef _list_h
+#define _list_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+static char *_rio_list_h_sccs = "@(#)list.h	1.9" ;
+#endif
+#endif
+
+#define PKT_IN_USE    0x1
+
+#ifdef INKERNEL
+
+#define ZERO_PTR (ushort) 0x8000
+#define	CaD	PortP->Caddr
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+
+#ifndef linux
+#if defined( MIPS ) && !defined( MIPSEISA )
+/* May the shoes of the Devil dance on your grave for creating this */
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
+          & (PKT_IN_USE<<2)))
+
+#elif  defined(MIPSEISA) || defined(nx6000) || \
+       defined(drs6000)  || defined(UWsparc)
+
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
+	  & PKT_IN_USE))
+
+#else
+#define   can_add_transmit(PacketP,PortP) \
+          (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \
+	  & PKT_IN_USE))
+#endif
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define add_transmit(PortP)  \
+	WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\
+	if (PortP->TxAdd == PortP->TxEnd)\
+	    PortP->TxAdd = PortP->TxStart;\
+	else\
+	    PortP->TxAdd++;\
+	WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd));
+#elif defined(AIX)
+#   define add_transmit(PortP)  \
+	{\
+	    register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\
+	    WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\
+	    if (PortP->TxAddO == PortP->TxEndO )\
+		PortP->TxAddO = PortP->TxStartO;\
+	    else\
+		PortP->TxAddO += sizeof(ushort);\
+	    WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\
+	}
+#else
+#   define add_transmit(PortP)  \
+	*PortP->TxAdd |= PKT_IN_USE;\
+	if (PortP->TxAdd == PortP->TxEnd)\
+	    PortP->TxAdd = PortP->TxStart;\
+	else\
+	    PortP->TxAdd++;\
+	PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd);
+#endif
+
+/*
+** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PacketP to point to the
+** relevent packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define can_remove_receive(PacketP,PortP) \
+	((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0)
+#elif defined(AIX)
+#   define can_remove_receive(PacketP,PortP) \
+	((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0)
+#else
+#   define can_remove_receive(PacketP,PortP) \
+	((*PortP->RxRemove & PKT_IN_USE) ? \
+	(PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0)
+#endif
+
+
+/*
+** Will God see it within his heart to forgive us for this thing that
+** we have created? To remove a packet from the receive queue you clear
+** its PKT_IN_USE bit, and then bump the pointers. Once the pointers
+** get to the end, they must be wrapped back to the start.
+*/
+#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
+#   define remove_receive(PortP) \
+	WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\
+	if (PortP->RxRemove == PortP->RxEnd)\
+	    PortP->RxRemove = PortP->RxStart;\
+	else\
+	    PortP->RxRemove++;\
+	WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove));
+#elif defined(AIX)
+#   define remove_receive(PortP) \
+    {\
+        register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\
+        WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\
+        if (PortP->RxRemoveO == PortP->RxEndO)\
+            PortP->RxRemoveO = PortP->RxStartO;\
+        else\
+            PortP->RxRemoveO += sizeof(ushort);\
+        WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\
+    }
+#else
+#   define remove_receive(PortP) \
+	*PortP->RxRemove &= ~PKT_IN_USE;\
+	if (PortP->RxRemove == PortP->RxEnd)\
+	    PortP->RxRemove = PortP->RxStart;\
+	else\
+	    PortP->RxRemove++;\
+	PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove);
+#endif
+#endif
+
+
+#else /* !IN_KERNEL */
+
+#define ZERO_PTR NULL
+
+
+#ifdef HOST
+/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE))   */
+#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\
+                             if (phb->tx_remove == phb->tx_end)\
+                                phb->tx_remove = phb->tx_start;\
+                             else\
+                                phb->tx_remove++;
+#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE)
+#define add_receive(pkt,phb) *phb->rx_add = pkt;\
+                             *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\
+                             if (phb->rx_add == phb->rx_end)\
+                                phb->rx_add = phb->rx_start;\
+                             else\
+                                phb->rx_add++;
+#endif
+#endif
+
+#ifdef RTA
+#define splx(oldspl)    if ((oldspl) == 0) spl0()
+#endif
+
+#endif /* ifndef _list.h */
+/*********** end of file ***********/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/lrt.h linux/drivers/char/rio/lrt.h
--- v2.3.99-pre6/linux/drivers/char/rio/lrt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/lrt.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L R T
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_lrt_h_sccs = "@(#)lrt.h	1.1" ;
+#endif
+#endif
+
+
+#ifdef DCIRRUS
+#define LRT_STACK       (unsigned short) 600
+#else
+#define LRT_STACK        (ushort) 200
+#endif
+
+
+
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/ltt.h linux/drivers/char/rio/ltt.h
--- v2.3.99-pre6/linux/drivers/char/rio/ltt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/ltt.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L T T
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_ltt_h_sccs = "@(#)ltt.h	1.1" ;
+#endif
+#endif
+
+#ifdef DCIRRUS
+#define LTT_STACK       (unsigned short)  600
+#else
+#define LTT_STACK       (ushort) 200
+#endif
+ 
+
+
+
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/lttwake.h linux/drivers/char/rio/lttwake.h
--- v2.3.99-pre6/linux/drivers/char/rio/lttwake.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/lttwake.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,53 @@
+
+
+
+/****************************************************************************
+ *******                                                              *******
+ *******            L T T    W A K E U P    H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_lttwake_h_sccs = "@(#)lttwake.h	1.1" ;
+#endif
+#endif
+
+#define LTT_WAKEUP_STACK          500
+#define LTT_WAKEUP_INTERVAL       (int) (500 * MILLISECOND)
+
+
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/map.h linux/drivers/char/rio/map.h
--- v2.3.99-pre6/linux/drivers/char/rio/map.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/map.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,103 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: map.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:11
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)map.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_map_h__
+#define __rio_map_h__
+
+#ifdef SCCS_LABELS
+static char *_map_h_sccs_ = "@(#)map.h	1.2";
+#endif
+
+/*
+** mapping structure passed to and from the config.rio program to
+** determine the current topology of the world
+*/
+
+#define MAX_MAP_ENTRY 17
+#define	TOTAL_MAP_ENTRIES (MAX_MAP_ENTRY*RIO_SLOTS)
+#define	MAX_NAME_LEN 32
+
+struct Map
+{
+	uint	HostUniqueNum;	        /* Supporting hosts unique number */
+	uint	RtaUniqueNum;	        /* Unique number */
+	/*
+	** The next two IDs must be swapped on big-endian architectures
+	** when using a v2.04 /etc/rio/config with a v3.00 driver (when
+	** upgrading for example).
+	*/
+	ushort	ID;			/* ID used in the subnet */
+	ushort	ID2;			/* ID of 2nd block of 8 for 16 port */
+	ulong	Flags;			/* Booted, ID Given, Disconnected */
+	ulong	SysPort;		/* First tty mapped to this port */
+	struct Top   Topology[LINKS_PER_UNIT];	/* ID connected to each link */
+	char	Name[MAX_NAME_LEN];        /* Cute name by which RTA is known */
+};
+
+/*
+** Flag values:
+*/
+#define	RTA_BOOTED		0x00000001
+#define RTA_NEWBOOT		0x00000010
+#define	MSG_DONE		0x00000020
+#define	RTA_INTERCONNECT	0x00000040
+#define	RTA16_SECOND_SLOT	0x00000080
+#define	BEEN_HERE		0x00000100
+#define SLOT_TENTATIVE		0x40000000
+#define SLOT_IN_USE		0x80000000
+
+/*
+** HostUniqueNum is the unique number from the host card that this RTA
+** is to be connected to.
+** RtaUniqueNum is the unique number of the RTA concerned. It will be ZERO
+** if the slot in the table is unused. If it is the same as the HostUniqueNum
+** then this slot represents a host card.
+** Flags contains current boot/route state info
+** SysPort is a value in the range 0-504, being the number of the first tty
+** on this RTA. Each RTA supports 8 ports. The SysPort value must be modulo 8.
+** SysPort 0-127 correspond to /dev/ttyr001 to /dev/ttyr128, with minor
+** numbers 0-127. SysPort 128-255 correspond to /dev/ttyr129 to /dev/ttyr256,
+** again with minor numbers 0-127, and so on for SysPorts 256-383 and 384-511
+** ID will be in the range 0-16 for a `known' RTA. ID will be 0xFFFF for an
+** unused slot/unknown ID etc.
+** The Topology array contains the ID of the unit connected to each of the
+** four links on this unit. The entry will be 0xFFFF if NOTHING is connected
+** to the link, or will be 0xFF00 if an UNKNOWN unit is connected to the link.
+** The Name field is a null-terminated string, upto 31 characters, containing
+** the 'cute' name that the sysadmin/users know the RTA by. It is permissible
+** for this string to contain any character in the range \040 to \176 inclusive.
+** In particular, ctrl sequences and DEL (0x7F, \177) are not allowed. The
+** special character '%' IS allowable, and needs no special action.
+**
+*/
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/mca.h linux/drivers/char/rio/mca.h
--- v2.3.99-pre6/linux/drivers/char/rio/mca.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/mca.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,73 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: mca.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:11
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)mca.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_mca_h__
+#define	__rio_mca_h__
+
+#ifdef SCCS_LABELS
+static char *_mca_h_sccs_ = "@(#)mca.h	1.2";
+#endif
+
+/*
+** Micro Channel stuff
+*/
+
+#define	McaMaxSlots	8
+#define McaSlotSelect	0x96
+#define	McaSlotEnable	0x08
+#define	McaIdLow	0x100
+#define	McaIdHigh	0x101
+#define	McaIrqEnable	0x102
+#define	McaMemory	0x103
+#define McaRIOId	0x6a5c
+#define	McaIrq9		0x00
+#define	McaIrq3		0x02
+#define	McaIrq4		0x04
+#define	McaIrq7		0x06
+#define	McaIrq10	0x08
+#define	McaIrq11	0x0A
+#define	McaIrq12	0x0C
+#define	McaIrq15	0x0E
+#define McaIrqMask	0x0E
+#define	McaCardEnable	0x01
+#define	McaAddress(X)	(((X)&0xFF)<<16)
+
+#define	McaTpFastLinks	        0x40
+#define	McaTpSlowLinks	        0x00
+#define	McaTpBootFromRam	0x01
+#define	McaTpBootFromLink	0x00
+#define	McaTpBusEnable		0x02
+#define	McaTpBusDisable		0x00
+
+#define	RIO_MCA_DEFAULT_MODE	SLOW_LINKS
+
+#endif	/* __rio_mca_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/mesg.h linux/drivers/char/rio/mesg.h
--- v2.3.99-pre6/linux/drivers/char/rio/mesg.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/mesg.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,41 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: mesg.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)mesg.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_mesg_h__
+#define	__rio_mesg_h__
+
+#ifdef SCCS_LABELS
+static char *_mesg_h_sccs_ = "@(#)mesg.h	1.2";
+#endif
+
+
+#endif /* __rio_mesg_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/param.h linux/drivers/char/rio/param.h
--- v2.3.99-pre6/linux/drivers/char/rio/param.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/param.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,61 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: param.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)param.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_param_h__
+#define __rio_param_h__
+
+#ifdef SCCS_LABELS
+static char *_param_h_sccs_ = "@(#)param.h	1.2";
+#endif
+
+
+/*
+** the param command block, as used in OPEN and PARAM calls.
+*/
+
+struct phb_param
+{
+    BYTE    Cmd;        /* It is very important that these line up */
+    BYTE    Cor1;       /* with what is expected at the other end. */
+    BYTE    Cor2;       /* to confirm that you've got it right,    */
+    BYTE    Cor4;       /* check with cirrus/cirrus.h              */
+    BYTE    Cor5;
+    BYTE    TxXon;	/* Transmit X-On character */
+    BYTE    TxXoff;	/* Transmit X-Off character */
+    BYTE    RxXon;	/* Receive X-On character */
+    BYTE    RxXoff;	/* Receive X-Off character */
+    BYTE    LNext;	/* Literal-next character */
+    BYTE    TxBaud;	/* Transmit baudrate */
+    BYTE    RxBaud;	/* Receive baudrate */
+};
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/parmmap.h linux/drivers/char/rio/parmmap.h
--- v2.3.99-pre6/linux/drivers/char/rio/parmmap.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/parmmap.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,96 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               H O S T   M E M O R Y  M A P
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+6/4/1991   jonb		     Made changes to accomodate Mips R3230 bus
+ ***************************************************************************/
+
+#ifndef _parmap_h
+#define _parmap_h
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_parmmap_h_sccs = "@(#)parmmap.h	1.4"; */
+#endif
+#endif
+
+typedef struct PARM_MAP PARM_MAP ;
+
+struct PARM_MAP
+{
+PHB_ptr           phb_ptr ;              /* Pointer to the PHB array */
+WORD_ptr          phb_num_ptr ;          /* Ptr to Number of PHB's */
+FREE_LIST_ptr     free_list;             /* Free List pointer */
+FREE_LIST_ptr     free_list_end;         /* Free List End pointer */
+Q_BUF_ptr_ptr     q_free_list_ptr ;      /* Ptr to Q_BUF variable */
+BYTE_ptr          unit_id_ptr ;          /* Unit Id */
+LPB_ptr           link_str_ptr ;         /* Link Structure Array */
+BYTE_ptr          bootloader_1 ;         /* 1st Stage Boot Loader */
+BYTE_ptr          bootloader_2 ;         /* 2nd Stage Boot Loader */
+WORD_ptr          port_route_map_ptr ;   /* Port Route Map */
+ROUTE_STR_ptr     route_ptr ;            /* Unit Route Map */
+NUMBER_ptr        map_present ;          /* Route Map present */
+NUMBER            pkt_num ;               /* Total number of packets */
+NUMBER            q_num ;                 /* Total number of Q packets */
+WORD              buffers_per_port ;      /* Number of buffers per port */
+WORD              heap_size ;             /* Initial size of heap */
+WORD              heap_left ;             /* Current Heap left */
+WORD              error ;                 /* Error code */
+WORD              tx_max;                 /* Max number of tx pkts per phb */
+WORD              rx_max;                 /* Max number of rx pkts per phb */
+WORD              rx_limit;               /* For high / low watermarks */
+NUMBER            links ;                 /* Links to use */
+NUMBER            timer ;                 /* Interrupts per second */
+RUP_ptr           rups ;                 /* Pointer to the RUPs */
+WORD              max_phb ;              /* Mostly for debugging */
+WORD              living ;               /* Just increments!! */
+WORD              init_done ;            /* Initialisation over */
+WORD              booting_link ;
+WORD              idle_count ;           /* Idle time counter */
+WORD              busy_count ;           /* Busy counter */
+WORD              idle_control ;         /* Control Idle Process */
+#if defined(HOST) || defined(INKERNEL)
+WORD              tx_intr;               /* TX interrupt pending */
+WORD              rx_intr;               /* RX interrupt pending */
+WORD              rup_intr;              /* RUP interrupt pending */
+#endif
+#if defined(RTA)
+WORD		  dying_count;		/* Count of processes dead */
+#endif
+} ;
+
+#endif
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/pci.h linux/drivers/char/rio/pci.h
--- v2.3.99-pre6/linux/drivers/char/rio/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/pci.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,76 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: pci.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)pci.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_pci_h__
+#define	__rio_pci_h__
+
+#ifdef SCCS_LABELS
+static char *_pci_h_sccs_ = "@(#)pci.h	1.2";
+#endif
+
+/*
+** PCI stuff
+*/
+
+#define	PCITpFastClock		0x80
+#define	PCITpSlowClock		0x00
+#define	PCITpFastLinks	        0x40
+#define	PCITpSlowLinks	        0x00
+#define	PCITpIntEnable		0x04
+#define	PCITpIntDisable		0x00
+#define	PCITpBusEnable		0x02
+#define	PCITpBusDisable		0x00
+#define	PCITpBootFromRam	0x01
+#define	PCITpBootFromLink	0x00
+
+#define	RIO_PCI_VENDOR		0x11CB
+#define	RIO_PCI_DEVICE		0x8000
+#define	RIO_PCI_BASE_CLASS	0x02
+#define	RIO_PCI_SUB_CLASS	0x80
+#define	RIO_PCI_PROG_IFACE	0x00
+
+#define RIO_PCI_RID		0x0008
+#define RIO_PCI_BADR0		0x0010
+#define RIO_PCI_INTLN		0x003C
+#define RIO_PCI_INTPIN		0x003D
+
+#define	RIO_PCI_MEM_SIZE	65536
+
+#define	RIO_PCI_TURBO_TP	0x80
+#define	RIO_PCI_FAST_LINKS	0x40
+#define	RIO_PCI_INT_ENABLE	0x04
+#define	RIO_PCI_TP_BUS_ENABLE	0x02
+#define	RIO_PCI_BOOT_FROM_RAM	0x01
+
+#define	RIO_PCI_DEFAULT_MODE	0x05
+
+#endif	/* __rio_pci_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/phb.h linux/drivers/char/rio/phb.h
--- v2.3.99-pre6/linux/drivers/char/rio/phb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/phb.h	Wed May 10 16:56:43 2000
@@ -0,0 +1,293 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 P H B     H E A D E R                        *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra, Jeremy Rolls
+ Date    : 
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _phb_h
+#define _phb_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_phb_h_sccs = "@(#)phb.h	1.12"; */
+#endif
+#endif
+
+
+ /*************************************************
+  * Set the LIMIT values.
+  ************************************************/
+#ifdef RTA
+#define RX_LIMIT       (ushort) 3
+#endif
+#ifdef HOST
+#define RX_LIMIT       (ushort) 1
+#endif
+
+
+/*************************************************
+ * Handshake asserted. Deasserted by the LTT(s)
+ ************************************************/
+#define PHB_HANDSHAKE_SET      ((ushort) 0x001) /* Set by LRT */
+
+#define PHB_HANDSHAKE_RESET     ((ushort) 0x002) /* Set by ISR / driver */
+
+#define PHB_HANDSHAKE_FLAGS     (PHB_HANDSHAKE_RESET | PHB_HANDSHAKE_SET)
+                                                /* Reset by ltt */
+
+
+/*************************************************
+ * Maximum number of PHB's
+ ************************************************/
+#if defined (HOST) || defined (INKERNEL)
+#define MAX_PHB               ((ushort) 128)  /* range 0-127 */
+#else
+#define MAX_PHB               ((ushort) 8)    /* range 0-7 */
+#endif
+
+/*************************************************
+ * Defines for the mode fields
+ ************************************************/
+#define TXPKT_INCOMPLETE        0x0001  /* Previous tx packet not completed */
+#define TXINTR_ENABLED          0x0002  /* Tx interrupt is enabled */
+#define TX_TAB3                 0x0004  /* TAB3 mode */
+#define TX_OCRNL                0x0008  /* OCRNL mode */
+#define TX_ONLCR                0x0010  /* ONLCR mode */
+#define TX_SENDSPACES           0x0020  /* Send n spaces command needs 
+                                           completing */
+#define TX_SENDNULL             0x0040  /* Escaping NULL needs completing */
+#define TX_SENDLF               0x0080  /* LF -> CR LF needs completing */
+#define TX_PARALLELBUG          0x0100  /* CD1400 LF -> CR LF bug on parallel
+                                           port */
+#define TX_HANGOVER             (TX_SENDSPACES | TX_SENDLF | TX_SENDNULL)
+#define TX_DTRFLOW		0x0200	/* DTR tx flow control */
+#define	TX_DTRFLOWED		0x0400	/* DTR is low - don't allow more data
+					   into the FIFO */
+#define	TX_DATAINFIFO		0x0800	/* There is data in the FIFO */
+#define	TX_BUSY			0x1000	/* Data in FIFO, shift or holding regs */
+
+#define RX_SPARE	        0x0001   /* SPARE */
+#define RXINTR_ENABLED          0x0002   /* Rx interrupt enabled */
+#define RX_ICRNL                0x0008   /* ICRNL mode */
+#define RX_INLCR                0x0010   /* INLCR mode */
+#define RX_IGNCR                0x0020   /* IGNCR mode */
+#define RX_CTSFLOW              0x0040   /* CTSFLOW enabled */
+#define RX_IXOFF                0x0080   /* IXOFF enabled */
+#define RX_CTSFLOWED            0x0100   /* CTSFLOW and CTS dropped */
+#define RX_IXOFFED              0x0200   /* IXOFF and xoff sent */
+#define RX_BUFFERED		0x0400	 /* Try and pass on complete packets */
+
+#define PORT_ISOPEN             0x0001  /* Port open? */
+#define PORT_HUPCL              0x0002  /* Hangup on close? */
+#define PORT_MOPENPEND          0x0004  /* Modem open pending */
+#define PORT_ISPARALLEL         0x0008  /* Parallel port */
+#define PORT_BREAK              0x0010  /* Port on break */
+#define PORT_STATUSPEND		0x0020  /* Status packet pending */
+#define PORT_BREAKPEND          0x0040  /* Break packet pending */
+#define PORT_MODEMPEND          0x0080  /* Modem status packet pending */
+#define PORT_PARALLELBUG        0x0100  /* CD1400 LF -> CR LF bug on parallel
+                                           port */
+#define PORT_FULLMODEM          0x0200  /* Full modem signals */
+#define PORT_RJ45               0x0400  /* RJ45 connector - no RI signal */
+#define PORT_RESTRICTED         0x0600  /* Restricted connector - no RI / DTR */
+
+#define PORT_MODEMBITS          0x0600  /* Mask for modem fields */
+
+#define PORT_WCLOSE             0x0800  /* Waiting for close */
+#define	PORT_HANDSHAKEFIX	0x1000	/* Port has H/W flow control fix */
+#define	PORT_WASPCLOSED		0x2000	/* Port closed with PCLOSE */
+#define	DUMPMODE		0x4000	/* Dump RTA mem */
+#define	READ_REG		0x8000	/* Read CD1400 register */
+
+
+
+/**************************************************************************
+ * PHB Structure
+ * A  few words.
+ *
+ * Normally Packets are added to the end of the list and removed from
+ * the start. The pointer tx_add points to a SPACE to put a Packet.
+ * The pointer tx_remove points to the next Packet to remove
+ *************************************************************************/
+#ifndef INKERNEL
+#define src_unit     u2.s2.unit
+#define src_port     u2.s2.port
+#define dest_unit    u1.s1.unit
+#define dest_port    u1.s1.port
+#endif
+#ifdef HOST
+#define tx_start     u3.s1.tx_start_ptr_ptr
+#define tx_add       u3.s1.tx_add_ptr_ptr
+#define tx_end       u3.s1.tx_end_ptr_ptr
+#define tx_remove    u3.s1.tx_remove_ptr_ptr
+#define rx_start     u4.s1.rx_start_ptr_ptr
+#define rx_add       u4.s1.rx_add_ptr_ptr
+#define rx_end       u4.s1.rx_end_ptr_ptr
+#define rx_remove    u4.s1.rx_remove_ptr_ptr
+#endif
+typedef struct PHB PHB ;
+struct PHB {
+#ifdef RTA
+        ushort      port;
+#endif
+#ifdef INKERNEL
+        WORD      source;
+#else
+        union       
+        {
+            ushort source;              /* Complete source */
+            struct
+            {
+                unsigned char unit;     /* Source unit */
+                unsigned char port;     /* Source port */
+            } s2;
+        } u2;
+#endif
+        WORD      handshake ;
+        WORD      status ;
+        NUMBER       timeout ;           /* Maximum of 1.9 seconds */
+        WORD      link ;              /* Send down this link */
+#ifdef INKERNEL
+        WORD      destination;
+#else
+        union       
+        {
+            ushort destination;         /* Complete destination */
+            struct
+            {
+                unsigned char unit;     /* Destination unit */
+                unsigned char port;     /* Destination port */
+            } s1;
+        } u1;
+#endif
+#ifdef RTA
+        ushort      tx_pkts_added;
+        ushort      tx_pkts_removed;
+        Q_BUF_ptr   tx_q_start ;        /* Start of the Q list chain */
+        short       num_tx_q_bufs ;     /* Number of Q buffers in the chain */
+        PKT_ptr_ptr tx_add ;            /* Add a new Packet here */
+        Q_BUF_ptr   tx_add_qb;          /* Pointer to the add Q buf */
+        PKT_ptr_ptr tx_add_st_qbb ;     /* Pointer to start of the Q's buf */
+        PKT_ptr_ptr tx_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+        PKT_ptr_ptr tx_remove ;         /* Remove a Packet here */
+        Q_BUF_ptr   tx_remove_qb ;      /* Pointer to the remove Q buf */
+        PKT_ptr_ptr tx_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+        PKT_ptr_ptr tx_remove_end_qbb ; /* Pointer to the end of the Q buf */
+#endif
+#ifdef INKERNEL
+        PKT_ptr_ptr tx_start ;
+        PKT_ptr_ptr tx_end ;
+        PKT_ptr_ptr tx_add ;
+        PKT_ptr_ptr tx_remove ;
+#endif
+#ifdef HOST
+        union
+        {
+            struct
+            {
+                PKT_ptr_ptr tx_start_ptr_ptr;
+                PKT_ptr_ptr tx_end_ptr_ptr;
+                PKT_ptr_ptr tx_add_ptr_ptr;
+                PKT_ptr_ptr tx_remove_ptr_ptr;
+            } s1;
+            struct
+            {
+                ushort * tx_start_ptr;
+                ushort * tx_end_ptr;
+                ushort * tx_add_ptr;
+                ushort * tx_remove_ptr;
+            } s2;
+        } u3;
+#endif
+
+#ifdef  RTA
+        ushort      rx_pkts_added;
+        ushort      rx_pkts_removed;
+        Q_BUF_ptr   rx_q_start ;        /* Start of the Q list chain */
+        short       num_rx_q_bufs ;     /* Number of Q buffers in the chain */
+        PKT_ptr_ptr rx_add ;            /* Add a new Packet here */
+        Q_BUF_ptr   rx_add_qb ;         /* Pointer to the add Q buf */
+        PKT_ptr_ptr rx_add_st_qbb ;     /* Pointer to start of the Q's buf */
+        PKT_ptr_ptr rx_add_end_qbb ;    /* Pointer to the end of the Q's buf */
+        PKT_ptr_ptr rx_remove ;         /* Remove a Packet here */
+        Q_BUF_ptr   rx_remove_qb ;      /* Pointer to the remove Q buf */
+        PKT_ptr_ptr rx_remove_st_qbb ;  /* Pointer to the start of the Q buf */
+        PKT_ptr_ptr rx_remove_end_qbb ; /* Pointer to the end of the Q buf */
+#endif
+#ifdef INKERNEL
+        PKT_ptr_ptr rx_start ;
+        PKT_ptr_ptr rx_end ;
+        PKT_ptr_ptr rx_add ;
+        PKT_ptr_ptr rx_remove ;
+#endif
+#ifdef HOST
+        union
+        {
+            struct
+            {
+                PKT_ptr_ptr rx_start_ptr_ptr;
+                PKT_ptr_ptr rx_end_ptr_ptr;
+                PKT_ptr_ptr rx_add_ptr_ptr;
+                PKT_ptr_ptr rx_remove_ptr_ptr;
+            } s1;
+            struct
+            {
+                ushort * rx_start_ptr;
+                ushort * rx_end_ptr;
+                ushort * rx_add_ptr;
+                ushort * rx_remove_ptr;
+            } s2;
+        } u4;
+#endif
+
+#ifdef RTA                              /* some fields for the remotes */
+        ushort     flush_count;		/* Count of write flushes */
+        ushort     txmode;		/* Modes for tx */
+        ushort     rxmode;		/* Modes for rx */
+        ushort     portmode;		/* Generic modes */
+        ushort     column;		/* TAB3 column count */
+        ushort     tx_subscript;	/* (TX) Subscript into data field */
+        ushort     rx_subscript;	/* (RX) Subscript into data field */
+        PKT_ptr    rx_incomplete;	/* Hold an incomplete packet here */
+        ushort     modem_bits;		/* Modem bits to mask */
+	ushort	   lastModem;		/* Modem control lines. */
+        ushort     addr;		/* Address for sub commands */
+        ushort     MonitorTstate;	/* TRUE if monitoring tstop */
+#endif
+
+        } ;
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/pkt.h linux/drivers/char/rio/pkt.h
--- v2.3.99-pre6/linux/drivers/char/rio/pkt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/pkt.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,120 @@
+/****************************************************************************
+ *******                                                              *******
+ *******            P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_pkt_h_sccs = "@(#)pkt.h	1.8"; */
+#endif
+#endif
+
+#define MAX_TTL         0xf
+#define PKT_CMD_BIT     ((ushort) 0x080)
+#define PKT_CMD_DATA    ((ushort) 0x080)
+
+#define PKT_ACK         ((ushort) 0x040)
+
+#define PKT_TGL         ((ushort) 0x020)
+
+#define PKT_LEN_MASK    ((ushort) 0x07f)
+
+#define DATA_WNDW       ((ushort) 0x10)
+#define PKT_TTL_MASK    ((ushort) 0x0f)
+
+#define PKT_MAX_DATA_LEN   72
+
+#define PKT_LENGTH         sizeof(struct PKT)
+#define SYNC_PKT_LENGTH    (PKT_LENGTH + 4)
+
+#define CONTROL_PKT_LEN_MASK PKT_LEN_MASK
+#define CONTROL_PKT_CMD_BIT  PKT_CMD_BIT
+#define CONTROL_PKT_ACK (PKT_ACK << 8)
+#define CONTROL_PKT_TGL (PKT_TGL << 8)
+#define CONTROL_PKT_TTL_MASK (PKT_TTL_MASK << 8)
+#define CONTROL_DATA_WNDW  (DATA_WNDW << 8)
+
+struct PKT    {
+#ifdef INKERNEL
+                   BYTE    dest_unit ;    /* Destination Unit Id */
+                   BYTE    dest_port ;    /* Destination POrt */
+                   BYTE    src_unit ;     /* Source Unit Id */
+                   BYTE    src_port ;     /* Source POrt */
+#else
+                   union       
+                   {
+                       ushort destination;         /* Complete destination */
+                       struct
+                       {
+                           unsigned char unit;     /* Destination unit */
+                           unsigned char port;     /* Destination port */
+                       } s1;
+                   } u1;
+                   union       
+                   {
+                       ushort source;              /* Complete source */
+                       struct
+                       {
+                           unsigned char unit;     /* Source unit */
+                           unsigned char port;     /* Source port */
+                       } s2;
+                   } u2;
+#endif
+#ifdef INKERNEL
+                   BYTE len ;
+                   BYTE control;
+#else
+                   union
+                   {
+                        ushort      control;
+                        struct
+                        {
+                            unsigned char len;
+                            unsigned char control;
+                        } s3;
+                    } u3;
+#endif
+                   BYTE    data[PKT_MAX_DATA_LEN] ;     
+                                                   /* Actual data :-) */
+                   WORD  csum ;                  /* C-SUM */
+               } ;
+#endif
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/poll.h linux/drivers/char/rio/poll.h
--- v2.3.99-pre6/linux/drivers/char/rio/poll.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/poll.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,76 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      P O L L
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _poll_h
+#define _poll_h
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_poll_h_sccs = "@(#)poll.h	1.2" ;
+#endif
+#endif
+
+
+#ifdef HOST
+#define POLL_STACK            100
+#endif
+#ifdef RTA
+#define POLL_STACK            200
+#endif
+
+#define POLL_PERIOD           (int) SECOND
+
+/* The various poll commands */
+#define POLL_POLL             0            /* We are connected and happy.. */
+#define POLL_INTRO            1            /* Introduction packet */
+#define POLL_TOPOLOGY         2            /* Topology update */
+#define POLL_ASSIGN           3            /* ID assign */
+#define POLL_FOAD             4            /* F*** Off And Die */
+#define POLL_LMD	      5		   /* Let Me Die */
+#define POLL_DYB	      6		   /* Die You Ba***** */
+
+/* The way data fields are split up for POLL packets */
+#define POLL_HOST_SERIAL      2            /* Host who booted me */
+#define POLL_MY_SERIAL        6            /* My serial number */
+#define POLL_YOUR_ID          1            /* Your ID number */
+#define POLL_TOPOLOGY_FIELDS  2            /* Topology maps */
+
+#endif
+
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/port.h linux/drivers/char/rio/port.h
--- v2.3.99-pre6/linux/drivers/char/rio/port.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/port.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,245 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: port.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)port.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_port_h__
+#define	__rio_port_h__
+
+#ifdef SCCS_LABELS
+static char *_port_h_sccs_ = "@(#)port.h	1.3";
+#endif
+
+
+#undef VPIX
+
+
+/*
+** the port data structure - one per port in the system
+*/
+
+#ifdef STATS
+struct RIOStats
+{
+	/*
+	** interrupt statistics
+	*/
+	uint	BreakIntCnt;
+	uint	ModemOffCnt;
+	uint	ModemOnCnt;
+	uint	RxIntCnt;
+	uint	TxIntCnt;
+	/*
+	** throughput statistics
+	*/
+	uint	RxCharCnt;
+	uint	RxPktCnt;
+	uint	RxSaveCnt;
+	uint	TxCharCnt;
+	uint	TxPktCnt;
+	/*
+	** driver entry statistics
+	*/
+	uint	CloseCnt;
+	uint	IoctlCnt;
+	uint	OpenCnt;
+	uint	ReadCnt;
+	uint	WriteCnt;
+	/*
+	** proc statistics
+	*/
+	uint	BlockCnt;
+	uint	OutputCnt;
+	uint	ResumeCnt;
+	uint	RflushCnt;
+	uint	SuspendCnt;
+	uint	TbreakCnt;
+	uint	TimeoutCnt;
+	uint	UnblockCnt;
+	uint	WflushCnt;
+	uint	WFBodgeCnt;
+};
+#endif
+
+/*
+**	Port data structure
+*/
+struct	Port
+{
+  struct gs_port gs; 
+  int				PortNum;	/* RIO port no., 0-511 */
+  struct Host	*HostP;
+  volatile caddr_t		Caddr;
+  ushort			HostPort;  /* Port number on host card */
+  uchar			RupNum;	/* Number of RUP for port */
+  uchar			ID2;	/* Second ID of RTA for port */
+  ulong			State;	/* FLAGS for open & xopen */
+#define	RIO_LOPEN	0x00001		/* Local open */
+#define	RIO_MOPEN	0x00002		/* Modem open */
+#define	RIO_WOPEN	0x00004		/* Waiting for open */
+#define	RIO_CLOSING	0x00008		/* The port is being close */
+#define	RIO_XPBUSY	0x00010		/* Transparent printer busy */
+#define	RIO_BREAKING	0x00020		/* Break in progress */
+#define	RIO_DIRECT	0x00040		/* Doing Direct output */
+#define	RIO_EXCLUSIVE	0x00080		/* Stream open for exclusive use */
+#define	RIO_NDELAY	0x00100		/* Stream is open FNDELAY */
+#define	RIO_CARR_ON	0x00200		/* Stream has carrier present */
+#define	RIO_XPWANTR	0x00400		/* Stream wanted by Xprint */
+#define	RIO_RBLK	0x00800		/* Stream is read-blocked */
+#define	RIO_BUSY	0x01000		/* Stream is BUSY for write */
+#define	RIO_TIMEOUT	0x02000		/* Stream timeout in progress */
+#define	RIO_TXSTOP	0x04000		/* Stream output is stopped */
+#define	RIO_WAITFLUSH	0x08000		/* Stream waiting for flush */
+#define	RIO_DYNOROD	0x10000		/* Drain failed */
+#define	RIO_DELETED	0x20000		/* RTA has been deleted */
+#define RIO_ISSCANCODE	0x40000		/* This line is in scancode mode */
+#define	RIO_USING_EUC	0x100000	/* Using extended Unix chars */
+#define	RIO_CAN_COOK	0x200000	/* This line can do cooking */
+#define RIO_TRIAD_MODE  0x400000        /* Enable TRIAD special ops. */
+#define RIO_TRIAD_BLOCK 0x800000        /* Next read will block */
+#define RIO_TRIAD_FUNC  0x1000000       /* Seen a function key coming in */
+#define RIO_THROTTLE_RX 0x2000000       /* RX needs to be throttled. */
+
+    ulong			Config;	/* FLAGS for NOREAD.... */
+#define	RIO_NOREAD	0x0001		/* Are not allowed to read port */
+#define	RIO_NOWRITE	0x0002		/* Are not allowed to write port */
+#define	RIO_NOXPRINT	0x0004		/* Are not allowed to xprint port */
+#define	RIO_NOMASK	0x0007		/* All not allowed things */
+#define RIO_IXANY	0x0008          /* Port is allowed ixany */
+#define	RIO_MODEM	0x0010		/* Stream is a modem device */
+#define	RIO_IXON	0x0020		/* Port is allowed ixon */
+#define RIO_WAITDRAIN	0x0040		/* Wait for port to completely drain */
+#define RIO_MAP_50_TO_50	0x0080	/* Map 50 baud to 50 baud */
+#define RIO_MAP_110_TO_110	0x0100	/* Map 110 baud to 110 baud */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 prt fix
+** As LynxOS does not appear to support Hardware Flow Control .....
+** Define our own flow control flags in 'Config'.
+*/
+#define RIO_CTSFLOW	0x0200		/* RIO's own CTSFLOW flag */
+#define RIO_RTSFLOW	0x0400		/* RIO's own RTSFLOW flag */
+
+
+    struct PHB			*PhbP;	  /* pointer to PHB for port */
+    WORD                        *TxAdd;   /* Add packets here */
+    WORD                        *TxStart; /* Start of add array */
+    WORD                        *TxEnd;         /* End of add array */
+    WORD                        *RxRemove;      /* Remove packets here */
+    WORD                        *RxStart;       /* Start of remove array */
+    WORD                        *RxEnd;         /* End of remove array */
+    uint			RtaUniqueNum;	/* Unique number of RTA */
+    ushort			PortState;	/* status of port */
+    ushort			ModemState;	/* status of modem lines */
+    ulong			ModemLines;	/* Modem bits sent to RTA */
+    uchar			CookMode;	/* who expands CR/LF? */
+    uchar			ParamSem;	/* Prevent write during param */
+    uchar			Mapped;		/* if port mapped onto host */
+    uchar			SecondBlock;	/* if port belongs to 2nd block
+						   of 16 port RTA */
+    uchar			InUse;		/* how many pre-emptive cmds */
+    uchar			Lock;		/* if params locked */
+    uchar			Store;	/* if params stored across closes */
+    uchar			FirstOpen; /* TRUE if first time port opened */
+    uchar			FlushCmdBodge;	/* if doing a (non)flush */
+    uchar			MagicFlags;	/* require intr processing */
+#define	MAGIC_FLUSH	0x01	/* mirror of WflushFlag */
+#define	MAGIC_REBOOT	0x02	/* RTA re-booted, re-open ports */
+#define	MORE_OUTPUT_EYGOR 0x04	/* riotproc failed to empty clists */
+    uchar			WflushFlag;	/* 1 How many WFLUSHs active */
+/*
+** Transparent print stuff
+*/
+    struct Xprint
+    {
+#ifndef MAX_XP_CTRL_LEN
+#define MAX_XP_CTRL_LEN		16		/* ALSO IN DAEMON.H */
+#endif
+	uint			XpCps;
+	char			XpOn[MAX_XP_CTRL_LEN];
+	char			XpOff[MAX_XP_CTRL_LEN];
+	ushort			XpLen;		/* strlen(XpOn)+strlen(XpOff) */
+	uchar			XpActive;
+	uchar			XpLastTickOk;	/* TRUE if we can process */
+#define	XP_OPEN		00001
+#define	XP_RUNABLE	00002
+	struct ttystatics 		*XttyP;
+    } Xprint;
+#ifdef VPIX
+    v86_t			*StashP;
+    uint			IntMask;
+    struct termss 		VpixSs;
+    uchar			ModemStatusReg;	/* Modem status register */
+#endif
+    uchar			RxDataStart;
+    uchar			Cor2Copy;	/* copy of COR2 */
+    char			*Name;		/* points to the Rta's name */
+#ifdef STATS
+    struct RIOStats 		Stat;		/* ports statistics */
+#endif
+    char			*TxRingBuffer;
+    ushort			TxBufferIn;	/* New data arrives here */
+    ushort			TxBufferOut;	/* Intr removes data here */
+    ushort			OldTxBufferOut;	/* Indicates if draining */
+    int				TimeoutId;	/* Timeout ID */
+    uint			Debug;
+    uchar			WaitUntilBooted; /* True if open should block */
+    uint			statsGather;	/* True if gathering stats */
+    ulong			txchars;	/* Chars transmitted */
+    ulong			rxchars;	/* Chars received */
+    ulong			opens;		/* port open count */
+    ulong			closes;		/* port close count */
+    ulong			ioctls;		/* ioctl count */
+    uchar			LastRxTgl;	/* Last state of rx toggle bit */
+  spinlock_t				portSem;	/* Lock using this sem */
+	int				MonitorTstate;	/* Monitoring ? */
+	int				timeout_id;	/* For calling 100 ms delays */
+	int				timeout_sem;/* For calling 100 ms delays */
+	int				firstOpen;	/* First time open ? */
+	char *			p;			/* save the global struc here .. */
+};
+
+struct ModuleInfo
+{
+	char	*Name;
+	uint	Flags[4];	/* one per port on a module */
+};
+#endif
+
+/*
+** This struct is required because trying to grab an entire Port structure
+** runs into problems with differing struct sizes between driver and config.
+*/
+struct PortParams {
+	uint	Port;
+	ulong	Config;
+	ulong	State;
+	struct ttystatics	*TtyP;
+};
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/proto.h linux/drivers/char/rio/proto.h
--- v2.3.99-pre6/linux/drivers/char/rio/proto.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/proto.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,244 @@
+/*
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef	_prototypes_h
+#define _prototypes_h
+
+
+/*
+** boot.c
+*/
+void init_boot( char *p, short stage);
+
+/*
+** disconct.c
+*/
+void kill_boot ( LPB *link );
+void disconnected( LPB *link );
+short boot_3( LPB *link, PKT *pkt );
+short send_3_pkt( LPB *link, PKT *pkt);
+
+/*
+** error.c
+*/
+void du_error(void);
+
+/*
+** formpkt.c
+*/
+ushort sum_it( PKT *pkt ) ;
+void form_rup_pkt( RUP *form_rup, PKT *pkt );
+void form_poll_pkt ( int type, LPB *link, int node );
+void form_route_pkt ( int type, PKT *pkt, LPB *link );
+
+/*
+** idle.c
+*/
+void idle( Process *idle_p );
+
+/*
+** init.c
+*/
+void general_init(void);
+void mem_halt( int error);
+
+/*
+** linkinit.c
+*/
+void initlink( u_short number, LPB *link);
+void runlink( LPB *link);
+
+/*
+** list.c
+*/
+PKT *get_free_start(void);
+void put_free_start( PKT *pkt);
+
+#ifdef HOST
+int can_remove_transmit ( PKT **pkt, PKT *pointer );
+#endif
+
+#ifdef RTA
+int spl7 ( void );
+int spl0 ( void );
+Q_BUF *get_free_q( void );
+PKT *get_free_end(void);
+int add_end( PKT *pkt, PHB *phb, int type);
+unsigned short free_packets( PHB *phb, int type);
+int can_remove_start( PKT **pkt, PHB *phb, int type);
+int can_add_start( PHB *phb, int type);
+int can_add_end( PHB *phb, int type);
+void put_free_end( PKT *pkt);
+int remove_start( PKT **pkt, PHB *phb, int type);
+#endif
+
+/*
+** Lrt.c
+*/
+void lrt( Process *lrt_p, LPB *link );
+
+#ifdef RTA
+void set_led_red ( LPB *link );
+#endif
+
+/*
+** ltt.c
+*/
+void ltt( Process *ltt_p, LPB *link, PHB *phb_ptr[] );
+void send_poll ( LPB *link );
+void request_id ( LPB *link );
+void send_topology_update ( LPB *link );
+void send_topology ( LPB *link );
+void supply_id ( LPB *link );
+
+#ifdef RTA
+void redirect_queue ( LPB *link, ushort flush );
+int obtain_rup ( int rup_number, PKT **pkt_address, LPB *link );
+#endif
+
+#ifdef TESTING_PERF
+int consume_cpu( void );
+#endif
+
+/*
+** lttwake.c
+*/
+#ifdef HOST
+void ltt_wakeup( Process *ltt_wakeup_p );
+#endif
+
+/*
+** mapgen.c
+*/
+void generate_id_map( short mapping, ROUTE_STR route[] );
+void gen_map( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl );
+void adjust_ttl( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl);
+void init_sys_map(void);
+
+/*
+** mmu.c
+*/
+char *rio_malloc( unsigned int amount);
+char *rio_calloc( unsigned int num, unsigned int size);
+ERROR rio_mmu_init( uint total_mem );
+
+/*
+** partn.c
+*/
+void partition_tx( struct PHB *phb, u_short tx_size, u_short rx_size, u_short rx_limit);
+
+/*
+** poll.c
+*/
+void tx_poll( Process *tx_poll_p);
+
+/*
+** process.c
+*/
+int  get_proc_space( Process **pd, int **pws, int wssize);
+
+/*
+** readrom.c
+*/
+void read_serial_number(char *buf);
+
+/*
+** rio.c
+*/
+int main( void );
+
+/*
+** route.c
+*/
+void route_update ( PKT *pkt, LPB *link);
+
+/*
+** rtainit.c
+*/
+#if defined(RTA)
+void rta_init(ushort RtaType);
+#endif /* defined(RTA) */
+
+/*
+** rupboot.c
+*/
+void rup_boot( PKT *pkt, RUP *this_rup, LPB *link);
+
+#ifdef RTA
+void kill_your_neighbour( int link_to_kill );
+#endif
+
+/*
+** rupcmd.c
+*/
+void rup_command( PKT *pkt, struct RUP *this_rup, LPB *link);
+
+/*
+** ruperr.c
+*/
+void rup_error( PKT *pkt, RUP *this_rup, LPB *link );
+void illegal_cmd( PKT *src_pkt );
+
+/*
+** ruppoll.c
+*/
+void rup_poll( PKT *pkt, RUP *this_rup, LPB *link );
+
+/*
+** ruppower.c
+*/
+void rup_power( PKT *pkt, RUP *this_rup, LPB *link );
+
+/*
+** ruprm.c
+*/
+void rup_route_map( PKT *pkt, RUP *this_rup, LPB *link);
+
+/*
+** rupstat.c
+*/
+void rup_status( PKT *pkt, RUP *this_rup, LPB *link);
+
+/*
+** rupsync.c
+*/
+void rup_sync( PKT *pkt);
+
+/*
+** rxpkt.c
+*/
+ERROR  rx_pkt( PKT_ptr_ptr pkt_address, LPB *link);
+
+/*
+** sendsts.c
+*/
+void send_status( PKT *requesting_pkt, RUP *this_rup);
+
+/*
+** serial.c
+*/
+void assign_serial ( char *ser_in, char *ser_out);
+int cmp_serial ( char *ser_1, char *ser_2);
+
+/*
+** txpkt.c
+*/
+ERROR  tx_pkt( PKT *pkt, LPB *link);
+short send_sync( LPB *link);
+
+#endif	/* _prototypes_h */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/protsts.h linux/drivers/char/rio/protsts.h
--- v2.3.99-pre6/linux/drivers/char/rio/protsts.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/protsts.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,119 @@
+/****************************************************************************
+ *******                                                              *******
+ *******      P R O T O C O L    S T A T U S   S T R U C T U R E      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _protsts_h
+#define _protsts_h 1
+
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_protsts_h_sccs = "@(#)protsts.h	1.4"; */
+#endif
+#endif
+
+/*************************************************
+ * ACK bit. Last Packet received OK. Set by
+ * rxpkt to indicate that the Packet has been
+ * received OK and that the LTT must set the ACK
+ * bit in the next outward bound Packet
+ * and re-set by LTT's after xmit.
+ *
+ * Gets shoved into rx_status
+ ************************************************/
+#define PHB_RX_LAST_PKT_ACKED    ((ushort) 0x080)
+
+/*******************************************************
+ * The Rx TOGGLE bit.
+ * Stuffed into rx_status by RXPKT
+ ******************************************************/
+#define PHB_RX_DATA_WNDW         ((ushort) 0x040)
+
+/*******************************************************
+ * The Rx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into rx_status
+ ******************************************************/
+#define PHB_RX_TGL               ((ushort) 0x2000)
+
+
+/*************************************************
+ * This bit is set by the LRT to indicate that
+ * an ACK (packet) must be returned.
+ *
+ * Gets shoved into tx_status
+ ************************************************/
+#define PHB_TX_SEND_PKT_ACK      ((ushort) 0x08)
+
+/*************************************************
+ * Set by LTT to indicate that an ACK is required
+ *************************************************/
+#define PHB_TX_ACK_RQRD         ((ushort) 0x01)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit.
+ * Stuffed into tx_status by RXPKT from the PKT WndW
+ * field. Looked by the LTT when the NEXT Packet
+ * is going to be sent.
+ ******************************************************/
+#define PHB_TX_DATA_WNDW         ((ushort) 0x04)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into tx_status
+ ******************************************************/
+#define PHB_TX_TGL               ((ushort) 0x02)
+
+/*******************************************************
+ * Request intr bit. Set when the queue has gone quiet
+ * and the PHB has requested an interrupt.
+ ******************************************************/
+#define PHB_TX_INTR             ((ushort) 0x100)
+
+/*******************************************************
+ * SET if the PHB cannot send any more data down the
+ * Link
+ ******************************************************/
+#define PHB_TX_HANDSHAKE         ((ushort) 0x010)
+
+
+#define RUP_SEND_WNDW		 ((ushort) 0x08) ;
+
+#endif
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/qbuf.h linux/drivers/char/rio/qbuf.h
--- v2.3.99-pre6/linux/drivers/char/rio/qbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/qbuf.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,67 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******       Q U E U E    B U F F E R   S T R U C T U R E S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _qbuf_h
+#define _qbuf_h 1
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_qbuf_h_sccs = "@(#)qbuf.h	1.1" ;
+#endif
+#endif
+
+
+
+#ifdef HOST
+#define PKTS_PER_BUFFER    1
+#else
+#define PKTS_PER_BUFFER    (220 / PKT_LENGTH)
+#endif
+
+typedef struct Q_BUF Q_BUF ;
+struct Q_BUF  {
+                  Q_BUF_ptr next ;
+                  Q_BUF_ptr prev ;
+                  PKT_ptr buf[PKTS_PER_BUFFER] ;
+              } ;
+
+
+#endif
+
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rio.h linux/drivers/char/rio/rio.h
--- v2.3.99-pre6/linux/drivers/char/rio/rio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,304 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 1998 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rio.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rio.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_rio_h__
+#define	__rio_rio_h__
+
+#ifdef SCCS_LABELS
+static char *_rio_h_sccs_ = "@(#)rio.h	1.3";
+#endif
+
+/*
+** 30.09.1998 ARG -
+** Introduced driver version and host card type strings
+*/
+#define RIO_DRV_STR "Specialix RIO Driver"
+#define RIO_AT_HOST_STR "ISA"
+#define RIO_PCI_HOST_STR "PCI"
+
+
+/*
+** rio_info_store() commands (arbitary values) :
+*/
+#define RIO_INFO_PUT	0xA4B3C2D1
+#define RIO_INFO_GET	0xF1E2D3C4
+
+
+/*
+** anything that I couldn't cram in somewhere else
+*/
+/*
+#ifndef RIODEBUG
+#define debug
+#else
+#define debug rioprint
+#endif
+*/
+
+
+/*
+**	Maximum numbers of things
+*/
+#define	RIO_SLOTS	4	/* number of configuration slots */
+#define	RIO_HOSTS	4	/* number of hosts that can be found */
+#define	PORTS_PER_HOST	128	/* number of ports per host */
+#define	LINKS_PER_UNIT	4	/* number of links from a host */
+#define	RIO_PORTS	(PORTS_PER_HOST * RIO_HOSTS) /* max. no. of ports */
+#define	RTAS_PER_HOST	(MAX_RUP) /* number of RTAs per host */
+#define	PORTS_PER_RTA	(PORTS_PER_HOST/RTAS_PER_HOST)	/* ports on a rta */
+#define	PORTS_PER_MODULE 4	/* number of ports on a plug-in module */
+				/* number of modules on an RTA */
+#define	MODULES_PER_RTA	 (PORTS_PER_RTA/PORTS_PER_MODULE)
+#define MAX_PRODUCT	16	/* numbr of different product codes */
+#define MAX_MODULE_TYPES 16	/* number of different types of module */
+
+#define RIO_CONTROL_DEV	128	/* minor number of host/control device */
+#define RIO_INVALID_MAJOR 0	/* test first host card's major no for validity */
+
+/*
+** number of RTAs that can be bound to a master
+*/
+#define MAX_RTA_BINDINGS (MAX_RUP * RIO_HOSTS)
+
+/*
+**	Unit types
+*/
+#define PC_RTA16	0x90000000
+#define PC_RTA8		0xe0000000
+#define TYPE_HOST	0
+#define TYPE_RTA8	1
+#define TYPE_RTA16	2
+
+/*
+**	Flag values returned by functions
+*/
+#define	RIO_FAIL	-1
+#define	RIO_SUCCESS	0
+#define	COPYFAIL	-1	/* copy[in|out] failed */
+
+/*
+** SysPort value for something that hasn't any ports
+*/
+#define	NO_PORT	0xFFFFFFFF
+
+/*
+** Unit ID Of all hosts
+*/
+#define	HOST_ID	0
+
+/*
+** Break bytes into nybles
+*/
+#define	LONYBLE(X)	((X) & 0xF)
+#define	HINYBLE(X)	(((X)>>4) & 0xF)
+
+/*
+** Flag values passed into some functions
+*/
+#define	DONT_SLEEP	0
+#define	OK_TO_SLEEP	1
+
+#define	DONT_PRINT	1
+#define	DO_PRINT	0
+
+#define PRINT_TO_LOG_CONS	0
+#define PRINT_TO_CONS	1
+#define PRINT_TO_LOG	2
+
+/*
+** Timeout has trouble with times of less than 3 ticks...
+*/
+#define	MIN_TIMEOUT	3
+
+/*
+**	Generally useful constants
+*/
+#define	HALF_A_SECOND		((HZ)>>1)
+#define	A_SECOND		(HZ)
+#define	HUNDRED_HZ		((HZ/100)?(HZ/100):1)
+#define	FIFTY_HZ		((HZ/50)?(HZ/50):1)
+#define	TWENTY_HZ		((HZ/20)?(HZ/20):1)
+#define	TEN_HZ			((HZ/10)?(HZ/10):1)
+#define	FIVE_HZ			((HZ/5)?(HZ/5):1)
+#define	HUNDRED_MS		TEN_HZ
+#define	FIFTY_MS		TWENTY_HZ
+#define	TWENTY_MS		FIFTY_HZ
+#define	TEN_MS			HUNDRED_HZ
+#define	TWO_SECONDS		((A_SECOND)*2)
+#define	FIVE_SECONDS		((A_SECOND)*5)
+#define	TEN_SECONDS		((A_SECOND)*10)
+#define	FIFTEEN_SECONDS		((A_SECOND)*15)
+#define	TWENTY_SECONDS		((A_SECOND)*20)
+#define	HALF_A_MINUTE		(A_MINUTE>>1)
+#define	A_MINUTE		(A_SECOND*60)
+#define	FIVE_MINUTES		(A_MINUTE*5)
+#define	QUARTER_HOUR		(A_MINUTE*15)
+#define	HALF_HOUR		(A_MINUTE*30)
+#define	HOUR			(A_MINUTE*60)
+
+#define	SIXTEEN_MEG		0x1000000
+#define	ONE_MEG			0x100000
+#define	SIXTY_FOUR_K		0x10000
+
+#define	RIO_AT_MEM_SIZE		SIXTY_FOUR_K
+#define	RIO_EISA_MEM_SIZE	SIXTY_FOUR_K
+#define	RIO_MCA_MEM_SIZE	SIXTY_FOUR_K
+
+#define	POLL_VECTOR		0x100
+
+#define	COOK_WELL		0
+#define	COOK_MEDIUM		1
+#define	COOK_RAW		2
+
+/*
+**	Pointer manipulation stuff
+**	RIO_PTR takes hostp->Caddr and the offset into the DP RAM area
+**	and produces a UNIX caddr_t (pointer) to the object
+**	RIO_OBJ takes hostp->Caddr and a UNIX pointer to an object and
+**	returns the offset into the DP RAM area.
+*/
+#define	RIO_PTR(C,O) (((caddr_t)(C))+(0xFFFF&(O)))
+#define	RIO_OFF(C,O) ((int)(O)-(int)(C))
+
+/*
+**	How to convert from various different device number formats:
+**	DEV is a dev number, as passed to open, close etc - NOT a minor
+**	number!
+**
+**	Note:	LynxOS only gives us 8 bits for the device minor number,
+**		so all this crap here to deal with 'modem' bits etc. is
+**		just a load of irrelevant old bunkum!
+**		This however does not stop us needing to define a value
+**		for RIO_MODEMOFFSET which is required by the 'riomkdev'
+**		utility in the New Config Utilities suite.
+*/
+/* 0-511: direct 512-1023: modem */
+#define	RIO_MODEMOFFSET		0x200	/* doesn't mean anything */
+#define	RIO_MODEM_MASK		0x1FF
+#define	RIO_MODEM_BIT		0x200
+#define	RIO_UNMODEM(DEV)	(minor(DEV) & RIO_MODEM_MASK)
+#define	RIO_ISMODEM(DEV)	(minor(DEV) & RIO_MODEM_BIT)
+#define RIO_PORT(DEV,FIRST_MAJ)	( (major(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \
+					+ minor(DEV)
+
+/*
+**	Min and Max
+*/
+#ifndef min
+#define	min(A,B)	((A)<(B)?(A):(B))
+#endif
+#ifndef max
+#define	max(A,B)	((A)>(B)?(A):(B))
+#endif
+
+#define	splrio	spltty
+
+#define	RIO_IPL	5
+#define	RIO_PRI	(PZERO+10)
+#define RIO_CLOSE_PRI	PZERO-1	/* uninteruptible sleeps for close */
+
+typedef struct DbInf
+{
+	uint	Flag;
+	char	Name[8];
+} DbInf;
+
+#ifndef TRUE
+#define	TRUE (1==1)
+#endif
+#ifndef FALSE
+#define	FALSE	(!TRUE)
+#endif
+
+#define CSUM(pkt_ptr)  (((ushort *)(pkt_ptr))[0] + ((ushort *)(pkt_ptr))[1] + \
+			((ushort *)(pkt_ptr))[2] + ((ushort *)(pkt_ptr))[3] + \
+			((ushort *)(pkt_ptr))[4] + ((ushort *)(pkt_ptr))[5] + \
+			((ushort *)(pkt_ptr))[6] + ((ushort *)(pkt_ptr))[7] + \
+			((ushort *)(pkt_ptr))[8] + ((ushort *)(pkt_ptr))[9] )
+
+/*
+** This happy little macro copies SIZE bytes of data from FROM to TO
+** quite well. SIZE must be a constant.
+*/
+#define CCOPY( FROM, TO, SIZE ) { *(struct s { char data[SIZE]; } *)(TO) = *(struct s *)(FROM); }
+
+/*
+** increment a buffer pointer modulo the size of the buffer...
+*/
+#define	BUMP( P, I )	((P) = (((P)+(I)) & RIOBufferMask))
+
+#define INIT_PACKET( PK, PP ) \
+{ \
+	*((uint *)PK)    = PP->PacketInfo; \
+}
+
+#define	RIO_LINK_ENABLE	0x80FF /* FF is a hack, mainly for Mips, to        */
+			       /* prevent a really stupid race condition.  */
+
+#define	NOT_INITIALISED	0
+#define	INITIALISED	1
+
+#define	NOT_POLLING	0
+#define	POLLING		1
+
+#define	NOT_CHANGED	0
+#define	CHANGED		1
+
+#define	NOT_INUSE	0
+
+#define	DISCONNECT	0
+#define	CONNECT		1
+
+
+/*
+** Machine types - these must NOT overlap with product codes 0-15
+*/
+#define	RIO_MIPS_R3230	31
+#define	RIO_MIPS_R4030	32
+
+#define	RIO_IO_UNKNOWN	-2
+
+#undef	MODERN
+#define	ERROR( E )	do { u.u_error = E; return OPENFAIL } while ( 0 )
+
+/* Defines for MPX line discipline routines */
+
+#define DIST_LINESW_OPEN	0x01
+#define DIST_LINESW_CLOSE	0x02
+#define DIST_LINESW_READ	0x04
+#define DIST_LINESW_WRITE	0x08
+#define DIST_LINESW_IOCTL	0x10
+#define DIST_LINESW_INPUT	0x20
+#define DIST_LINESW_OUTPUT	0x40
+#define DIST_LINESW_MDMINT	0x80
+
+#endif /* __rio_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c
--- v2.3.99-pre6/linux/drivers/char/rio/rio_linux.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio_linux.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1557 @@
+
+/* rio_linux.c -- Linux driver for the Specialix RIO series cards. 
+ *
+ *
+ *   (C) 1999 R.E.Wolff@BitWizard.nl
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (rio.txt) first.
+ *
+ *
+ *
+ *      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.
+ *
+ * Revision history:
+ * $Log: rio.c,v $
+ * Revision 1.1  1999/07/11 10:13:54  wolff
+ * Initial revision
+ *
+ * */
+
+
+#define RCS_ID "$Id: rio.c,v 1.1 1999/07/11 10:13:54 wolff Exp wolff $"
+#define RCS_REV "$Revision: 1.1 $"
+
+
+#include <linux/module.h>
+#include <linux/config.h> 
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+#include "protsts.h"
+#include "rioboard.h"
+
+
+#include "rio_linux.h"
+
+/* I don't think that this driver can handle more than 512 ports on
+one machine.  Specialix specifies max 4 boards in one machine. I don't
+know why. If you want to try anyway you'll have to increase the number
+of boards in rio.h.  You'll have to allocate more majors if you need
+more than 512 ports.... */
+
+
+/* ************************************************************** */
+/* * This section can be removed when 2.0 becomes outdated....  * */
+/* ************************************************************** */
+
+#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020209   /* less than 2.2.x */
+#warning "Please use a recent 2.2.x kernel. "
+#endif
+#endif
+
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source 
+   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
+   and provide for compatibility stuff here if possible. */
+
+#include <linux/bios32.h>
+
+#define Get_user(a,b)                a = get_user(b)
+#define Put_user(a,b)                0,put_user(a,b)
+#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c) 
+{
+  memcpy_fromfs(to, from, c);
+  return 0;
+}
+
+#define pci_present                  pcibios_present
+#define pci_read_config_word         pcibios_read_config_word
+#define pci_read_config_dword        pcibios_read_config_dword
+
+static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
+{
+  unsigned char t; 
+  pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
+  return t;
+}
+
+static inline void *ioremap(unsigned long base, long length)
+{
+  if (base < 0x100000) return (void *)base;
+  return vremap (base, length);
+}
+
+#define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
+
+#define capable(x)                   suser()
+
+#define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+
+#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI  -1
+#define ASYNC_SPD_WARP -1
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+   to the "name" field that does exist. As long as the assignments are
+   done in the right order, there is nothing to worry about. */
+#define driver_name           name 
+
+/* Should be in a header somewhere. They are in tty.h on 2.2 */
+#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
+
+/* The return type of a "close" routine. */
+#define INT                   void
+#define NO_ERROR              /* Nothing */
+
+#else
+
+/* The 2.2.x compatibility section. */
+#include <asm/uaccess.h>
+
+#define Get_user(a,b)         get_user(a,b)
+#define Put_user(a,b)         put_user(a,b)
+#define get_irq(pdev)         pdev->irq
+
+#define INT                   int
+#define NO_ERROR              0              
+
+#define my_iounmap(x,b)       (iounmap((char *)(b)))
+
+#endif
+
+/* ************************************************************** */
+/* *                End of compatibility section..              * */
+/* ************************************************************** */
+
+
+
+/* Why the hell am I defining these here? */
+#define RIO_TYPE_NORMAL 1
+#define RIO_TYPE_CALLOUT 2
+
+#ifndef RIO_NORMAL_MAJOR0
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define RIO_NORMAL_MAJOR0  154
+#define RIO_CALLOUT_MAJOR0 155
+#define RIO_NORMAL_MAJOR1  156
+#define RIO_CALLOUT_MAJOR1 157
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+#ifndef RIO_WINDOW_LEN 
+#define RIO_WINDOW_LEN 0x10000
+#endif
+
+
+/* Configurable options: 
+   (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef RIO_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 1000
+   Hz, but it is user configurable. I don't recommend going above 1000
+   Hz. The interrupt ratelimit might trigger if the interrupt is
+   shared with a very active other device. 
+   undef this if you want to disable the check....
+*/
+#define IRQ_RATE_LIMIT 200
+
+#if 0
+/* Not implemented */
+/* 
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#define RIO_REPORT_FIFO
+#define RIO_REPORT_OVERRUN
+#endif 
+
+
+/* These constants are derived from SCO Source */
+static struct Conf
+RIOConf =
+{
+  /* locator */         "RIO Config here",
+  /* startuptime */     HZ*2,           /* how long to wait for card to run */
+  /* slowcook */        0,              /* TRUE -> always use line disc. */
+  /* intrpolltime */    1,              /* The frequency of OUR polls */
+  /* breakinterval */   25,             /* x10 mS */
+  /* timer */           10,             /* mS */
+  /* RtaLoadBase */     0x7000,
+  /* HostLoadBase */    0x7C00,
+  /* XpHz */            5,              /* number of Xprint hits per second */
+  /* XpCps */           120,            /* Xprint characters per second */
+  /* XpOn */            "\033d#",       /* start Xprint for a wyse 60 */
+  /* XpOff */           "\024",         /* end Xprint for a wyse 60 */
+  /* MaxXpCps */        2000,           /* highest Xprint speed */
+  /* MinXpCps */        10,             /* slowest Xprint speed */
+  /* SpinCmds */        1,              /* non-zero for mega fast boots */
+  /* First Addr */      0x0A0000,       /* First address to look at */
+  /* Last Addr */       0xFF0000,       /* Last address looked at */
+  /* BufferSize */      1024,           /* Bytes per port of buffering */
+  /* LowWater */        256,            /* how much data left before wakeup */
+  /* LineLength */      80,             /* how wide is the console? */
+  /* CmdTimeout */      HZ,             /* how long a close command may take */
+};
+
+
+
+
+/* Function prototypes */
+
+static void rio_disable_tx_interrupts (void * ptr); 
+static void rio_enable_tx_interrupts (void * ptr); 
+static void rio_disable_rx_interrupts (void * ptr); 
+static void rio_enable_rx_interrupts (void * ptr); 
+static int  rio_get_CD (void * ptr); 
+static void rio_shutdown_port (void * ptr);
+static int  rio_set_real_termios (void  *ptr);
+static void rio_hungup (void  *ptr);
+static void rio_close (void  *ptr);
+static int rio_chars_in_buffer (void * ptr);
+static int rio_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg);
+static int rio_fw_open(struct inode *inode, struct file *filp);
+static INT rio_fw_release(struct inode *inode, struct file *filp);
+static int rio_init_drivers(void);
+
+
+void my_hd (void *addr, int len);
+
+
+
+static struct tty_driver rio_driver, rio_callout_driver;
+static struct tty_driver rio_driver2, rio_callout_driver2;
+
+static struct tty_struct * rio_table[RIO_NPORTS] = { NULL, };
+static struct termios ** rio_termios;
+static struct termios ** rio_termios_locked;
+
+/* The name "p" is a bit non-descript. But that's what the rio-lynxos
+sources use all over the place. */
+struct rio_info *p;
+
+/* struct rio_board boards[RIO_HOSTS]; */
+struct rio_port *rio_ports;
+
+int rio_refcount;
+int rio_initialized = 0;
+int rio_nports = 0;
+int rio_debug = 0;
+
+
+/* You can have the driver poll your card. 
+    - Set rio_poll to 1 to poll every timer tick (10ms on Intel). 
+      This is used when the card cannot use an interrupt for some reason.
+*/
+int rio_poll = 1;
+
+
+/* These are the only open spaces in my computer. Yours may have more
+   or less.... */
+int rio_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000};
+
+#define NR_RIO_ADDRS (sizeof(rio_probe_addrs)/sizeof (int))
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts. 
+   Some architectures may need more. -- Changed to LONG to
+   support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
+long rio_irqmask = -1;
+
+#ifndef TWO_ZERO
+#ifdef MODULE
+MODULE_PARM(rio_poll, "i");
+MODULE_PARM(rio_debug, "i");
+MODULE_PARM(rio_irqmask, "i");
+#endif
+#endif
+
+static struct real_driver rio_real_driver = {
+  rio_disable_tx_interrupts,
+  rio_enable_tx_interrupts,
+  rio_disable_rx_interrupts,
+  rio_enable_rx_interrupts,
+  rio_get_CD,
+  rio_shutdown_port, 
+  rio_set_real_termios, 
+  rio_chars_in_buffer,
+  rio_close,
+  rio_hungup,
+  NULL
+};
+
+
+/* 
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile... 
+*/
+#define DEBUG
+
+#ifdef DEBUG
+#define rio_dprintk(f, str...) if (rio_debug & f) printk (str)
+#else
+#define rio_dprintk(f, str...) /* nothing */
+#endif
+
+
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n")
+#define func_exit()  rio_dprintk (RIO_DEBUG_FLOW, "rio: exit  " __FUNCTION__ "\n")
+
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \
+                                  "(port %d)\n", port->line)
+
+
+
+
+/* 
+ *  Firmware loader driver specific routines
+ *
+ */
+
+static struct file_operations rio_fw_fops = {
+	NULL,	/*	lseek	*/
+	NULL,	/*	read	*/
+	NULL,	/*	write	*/
+	NULL,	/*	readdir	*/
+	NULL,	/*	select	*/
+	rio_fw_ioctl,
+	NULL,	/*	mmap	*/
+	rio_fw_open,
+#ifndef TWO_ZERO
+	NULL,	/*	flush	*/
+#endif
+	rio_fw_release,
+	NULL,	/*	fsync	*/
+	NULL,	/*	fasync	*/
+	NULL,	/*	check_media_change	*/
+	NULL,	/*	revalidate	*/
+};
+
+struct miscdevice rio_fw_device = {
+	RIOCTL_MISC_MINOR, "rioctl", &rio_fw_fops
+};
+
+
+
+
+
+#ifdef RIO_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int rio_paranoia_check(struct rio_port const * port,
+				    kdev_t device, const char *routine)
+{
+
+  static const char *badmagic =
+    KERN_ERR "rio: Warning: bad rio port magic number for device %s in %s\n";
+  static const char *badinfo =
+    KERN_ERR "rio: Warning: null rio port for device %s in %s\n";
+ 
+  if (!port) {
+    printk(badinfo, kdevname(device), routine);
+    return 1;
+  }
+  if (port->magic != RIO_MAGIC) {
+    printk(badmagic, kdevname(device), routine);
+    return 1;
+  }
+
+  return 0;
+}
+#else
+#define rio_paranoia_check(a,b,c) 0
+#endif
+
+
+#ifdef DEBUG
+void my_hd (void *ad, int len)
+{
+  int i, j, ch;
+  unsigned char *addr = ad;
+  
+  for (i=0;i<len;i+=16) {
+    printk ("%08x ", (int) addr+i);
+    for (j=0;j<16;j++) {
+      printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+    }
+    for (j=0;j<16;j++) {
+      ch = addr[j+i];
+      printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+    }
+    printk ("\n");
+  }
+}
+#else
+#define my_hd(ad,len) do{/* nothing*/ } while (0)
+#endif
+
+
+/* Delay a number of jiffies, allowing a signal to interrupt */ 
+int RIODelay (struct Port *PortP, int njiffies)
+{
+  func_enter ();
+
+  rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);  
+  current->state = TASK_INTERRUPTIBLE;
+  schedule_timeout(njiffies);
+  current->state = TASK_RUNNING;
+  func_exit();
+
+  if (signal_pending(current))
+    return RIO_FAIL;
+  else
+    return !RIO_FAIL;
+}
+
+
+/* Delay a number of jiffies, disallowing a signal to interrupt */ 
+int RIODelay_ni (struct Port *PortP, int njiffies)
+{
+  func_enter ();
+
+  rio_dprintk (RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);  
+  current->state = TASK_UNINTERRUPTIBLE;
+  schedule_timeout(njiffies);
+  current->state = TASK_RUNNING;
+  func_exit();
+  return !RIO_FAIL;
+}
+
+
+int rio_minor (kdev_t device)
+{
+  return MINOR (device) + 
+    256 * ((MAJOR (device) == RIO_NORMAL_MAJOR1) ||
+	   (MAJOR (device) == RIO_CALLOUT_MAJOR1));
+}
+
+
+int rio_ismodem (kdev_t device)
+{
+  return (MAJOR (device) != RIO_NORMAL_MAJOR0) &&
+         (MAJOR (device) != RIO_NORMAL_MAJOR1);
+}
+
+
+void rio_udelay (int usecs)
+{
+  udelay (usecs);
+}
+
+
+void rio_inc_mod_count (void)
+{
+  func_enter ();
+  MOD_INC_USE_COUNT; 
+  func_exit ();
+}
+
+
+void rio_dec_mod_count (void)
+{
+  func_enter ();
+  MOD_DEC_USE_COUNT; 
+  func_exit ();
+}
+
+
+static int rio_set_real_termios (void *ptr)
+{
+  int rv;
+  func_enter();
+
+  rv = RIOParam( (struct Port *) ptr, CONFIG, 0, 1);
+
+  func_exit ();
+
+  return rv;
+}
+
+
+void rio_reset_interrupt (struct Host *HostP)
+{
+  switch( HostP->Type ) {
+  case RIO_AT:
+  case RIO_MCA:
+  case RIO_PCI:
+    WBYTE(HostP->ResetInt , 0xff);
+  }
+}
+
+
+static void rio_interrupt (int irq, void *ptr, struct pt_regs *regs)
+{
+  struct Host *HostP;
+
+  HostP = &p->RIOHosts[(long)ptr];
+  /*   func_enter ();  */
+  rio_dprintk (RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", 
+               irq, HostP->Ivec); 
+
+  /* AAargh! The order in which to do these things is essential and
+     not trivial. 
+     
+     - Rate limit goes before "recursive". Otherwise a series of
+       recursive calls will hang the machine in the interrupt routine. 
+
+     - hardware twiddling goes before "recursive". Otherwise when we
+       poll the card, and a recursive interrupt happens, we wont
+       ack the card, so it might keep on interrupting us. (especially
+       level sensitive interrupt systems like PCI).
+
+     - Rate limit goes before hardware twiddling. Otherwise we won't
+       catch a card that has gone bonkers.
+
+     - The "initialized" test goes after the hardware twiddling. Otherwise
+       the card will stick us in the interrupt routine again.
+
+     - The initialized test goes before recursive. 
+  */
+
+
+
+#ifdef IRQ_RATE_LIMIT
+  /* Aaargh! I'm ashamed. This costs more lines-of-code than the
+     actual interrupt routine!. (Well, used to when I wrote that comment) */
+  {
+    static int lastjif;
+    static int nintr=0;
+
+    if (lastjif == jiffies) {
+      if (++nintr > IRQ_RATE_LIMIT) {
+        free_irq (HostP->Ivec, ptr);
+        printk (KERN_ERR "rio: Too many interrupts. Turning off interrupt %d.\n", 
+                HostP->Ivec);
+      }
+    } else {
+      lastjif = jiffies;
+      nintr = 0;
+    }
+  }
+#endif
+
+  if (HostP->Ivec == irq) {
+    /* Tell the card we've noticed the interrupt. */
+    rio_reset_interrupt (HostP);
+  }
+
+  if ((HostP->Flags & RUN_STATE) != RC_RUNNING) return;
+
+  if (test_and_set_bit (RIO_BOARD_INTR_LOCK, &HostP->locks)) {
+    printk (KERN_ERR "Recursive interrupt! (host %d/irq%d)\n", 
+            (int) ptr, HostP->Ivec);
+    return;
+  }
+
+  RIOServiceHost(p, HostP, irq);
+
+  rio_dprintk ( RIO_DEBUG_IFLOW, "riointr() doing host %d type %d\n", 
+                (int) ptr, HostP->Type);
+
+  clear_bit (RIO_BOARD_INTR_LOCK, &HostP->locks);
+  rio_dprintk (RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", 
+               irq, HostP->Ivec); 
+  /*  func_exit ();  */
+}
+
+
+static void rio_pollfunc (unsigned long data)
+{
+  func_enter ();
+
+  rio_interrupt (0, (void *)data, NULL);
+  p->RIOHosts[data].timer.expires = jiffies + rio_poll;
+  add_timer (&p->RIOHosts[data].timer);
+
+  func_exit ();
+}
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the Specialix 
+   cards. ....   Hmm. Ok I figured it out. You don't.  -- REW */
+
+static void rio_disable_tx_interrupts (void * ptr) 
+{
+  func_enter();
+
+  /*  port->gs.flags &= ~GS_TX_INTEN; */
+
+  func_exit();
+}
+
+
+static void rio_enable_tx_interrupts (void * ptr) 
+{
+  struct Port *PortP = ptr;
+  /* int hn; */
+
+  func_enter();
+
+  /* hn = PortP->HostP - p->RIOHosts;
+
+     rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn);
+     rio_interrupt (-1,(void *) hn, NULL); */
+
+  RIOTxEnable((char *) PortP);
+
+  /* 
+   * In general we cannot count on "tx empty" interrupts, although
+   * the interrupt routine seems to be able to tell the difference. 
+   */
+  PortP->gs.flags &= ~GS_TX_INTEN;
+
+  func_exit();
+}
+
+
+static void rio_disable_rx_interrupts (void * ptr) 
+{
+  func_enter();
+  func_exit();
+}
+
+static void rio_enable_rx_interrupts (void * ptr) 
+{
+  /*  struct rio_port *port = ptr; */
+  func_enter();
+  func_exit();
+}
+
+
+/* Jeez. Isn't this simple?  */
+static int rio_get_CD (void * ptr) 
+{
+  struct Port *PortP = ptr;
+  int rv;
+
+  func_enter();
+  rv = (PortP->ModemState & MSVR1_CD) != 0;
+
+  rio_dprintk (RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
+  
+  func_exit();  
+  return rv;
+}
+
+
+/* Jeez. Isn't this simple? Actually, we can sync with the actual port
+   by just pushing stuff into the queue going to the port... */
+static int rio_chars_in_buffer (void * ptr) 
+{
+  func_enter();
+
+  func_exit();  
+  return 0;
+}
+
+
+/* Nothing special here... */
+static void rio_shutdown_port (void * ptr) 
+{
+  func_enter();
+
+#if 0
+  port->gs.flags &= ~ GS_ACTIVE;
+  if (!port->gs.tty) {
+    printk ("No tty.\n");
+    return;
+  }
+  if (!port->gs.tty->termios) {
+    printk ("No termios.\n");
+    return;
+  }
+  if (port->gs.tty->termios->c_cflag & HUPCL) {
+    rio_setsignals (port, 0, 0);
+  }
+#endif
+
+  func_exit();
+}
+
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *               interface with the rest of the system                    *
+ * ********************************************************************** */
+
+
+static int rio_fw_open(struct inode *inode, struct file *filp)
+{
+  func_enter ();
+  rio_inc_mod_count ();
+  func_exit ();
+  return 0;
+}
+
+
+static INT rio_fw_release(struct inode *inode, struct file *filp)
+{
+  func_enter ();
+  rio_dec_mod_count ();
+  func_exit ();
+  return NO_ERROR;
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+   here. The whole linux serial drivers stuff needs to be redesigned.
+   My guess is that this is a hack to minimize the impact of a bug
+   elsewhere. Thinking about it some more. (try it sometime) Try
+   running minicom on a serial port that is driven by a modularized
+   driver. Have the modem hangup. Then remove the driver module. Then
+   exit minicom.  I expect an "oops".  -- REW */
+static void rio_hungup (void *ptr)
+{
+  func_enter ();
+  /* rio_dec_mod_count (); */
+  func_exit ();
+}
+
+
+/* The standard serial_close would become shorter if you'd wrap it like
+   this. 
+   rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;}
+ */
+static void rio_close (void *ptr)
+{
+  func_enter ();
+  riotclose (ptr);
+  rio_dec_mod_count ();
+  func_exit ();
+}
+
+
+
+static int rio_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg)
+{
+  int rc = 0;
+  func_enter();
+
+  /* The "dev" argument isn't used. */
+  rc = -riocontrol (p, 0, cmd, (void *)arg, suser ());
+
+  func_exit ();
+  return rc;
+}
+
+
+static int rio_ioctl (struct tty_struct * tty, struct file * filp, 
+                     unsigned int cmd, unsigned long arg)
+{
+#if 0
+  int rc;
+  struct rio_port *port = tty->driver_data;
+  int ival;
+
+  /* func_enter2(); */
+
+
+  rc  = 0;
+  switch (cmd) {
+  case TIOCGSOFTCAR:
+    rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+                  (unsigned int *) arg);
+    break;
+  case TIOCSSOFTCAR:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      tty->termios->c_cflag =
+        (tty->termios->c_cflag & ~CLOCAL) |
+        (ival ? CLOCAL : 0);
+    }
+    break;
+  case TIOCGSERIAL:
+    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                          sizeof(struct serial_struct))) == 0)
+      gs_getserial(&port->gs, (struct serial_struct *) arg);
+    break;
+  case TIOCSSERIAL:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(struct serial_struct))) == 0)
+      rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+    break;
+  case TIOCMGET:
+    if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      ival = rio_getsignals(port);
+      put_user(ival, (unsigned int *) arg);
+    }
+    break;
+  case TIOCMBIS:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
+                           ((ival & TIOCM_RTS) ? 1 : -1));
+    }
+    break;
+  case TIOCMBIC:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
+                           ((ival & TIOCM_RTS) ? 0 : -1));
+    }
+    break;
+  case TIOCMSET:
+    if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                          sizeof(unsigned int))) == 0) {
+      Get_user(ival, (unsigned int *) arg);
+      rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
+                           ((ival & TIOCM_RTS) ? 1 : 0));
+    }
+    break;
+
+  default:
+    rc = -ENOIOCTLCMD;
+    break;
+  }
+  /* func_exit(); */
+  return rc;
+#else
+  return -ENOIOCTLCMD;
+#endif
+
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation. 
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself.  This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here.  When we come to read characters from the
+ * rx buffers on the card (rio_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in rio_rx_throt[]). 
+ * If it can't we simply don't remove chars from the cards buffer. 
+ * When the tty layer can accept chars, we again note that here and when
+ * rio_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void rio_throttle (struct tty_struct * tty)
+{
+  struct Port *port = (struct Port *)tty->driver_data;
+  
+  func_enter();
+  /* If the port is using any type of input flow
+   * control then throttle the port.
+   */
+
+  if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+    port->State |= RIO_THROTTLE_RX;
+  }
+
+  func_exit();
+}
+
+
+static void rio_unthrottle (struct tty_struct * tty)
+{
+  struct Port *port = (struct Port *)tty->driver_data;
+
+  func_enter();
+  /* Always unthrottle even if flow control is not enabled on
+   * this port in case we disabled flow control while the port
+   * was throttled
+   */
+
+  port->State &= ~RIO_THROTTLE_RX;
+
+  func_exit();
+  return;
+}
+
+
+
+
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+
+struct vpd_prom *get_VPD_PROM (struct Host *hp)
+{
+  static struct vpd_prom vpdp;
+  char *p;
+  int i;
+
+  func_enter();
+  rio_dprintk (RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", 
+              hp->Caddr + RIO_VPD_ROM);
+
+  p = (char *) &vpdp;
+  for (i=0;i< sizeof (struct vpd_prom);i++)
+    *p++ = readb (hp->Caddr+RIO_VPD_ROM + i*2);
+      /* read_rio_byte (hp, RIO_VPD_ROM + i*2); */
+
+  /* Terminate the identifier string. 
+     *** requires one extra byte in struct vpd_prom *** */
+  *p++=0; 
+
+  if (rio_debug & RIO_DEBUG_PROBE)
+    my_hd ((char *)&vpdp, 0x20);
+
+  return &vpdp;
+}
+
+
+
+static int rio_init_drivers(void)
+{
+  int error;
+  
+  func_enter();
+
+  memset(&rio_driver, 0, sizeof(rio_driver));
+  rio_driver.magic = TTY_DRIVER_MAGIC;
+  rio_driver.driver_name = "specialix_rio";
+  rio_driver.name = "ttySR";
+  rio_driver.major = RIO_NORMAL_MAJOR0;
+  rio_driver.num = 256;
+  rio_driver.type = TTY_DRIVER_TYPE_SERIAL;
+  rio_driver.subtype = RIO_TYPE_NORMAL;
+  rio_driver.init_termios = tty_std_termios;
+  rio_driver.init_termios.c_cflag =
+    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+  rio_driver.flags = TTY_DRIVER_REAL_RAW;
+  rio_driver.refcount = &rio_refcount;
+  rio_driver.table = rio_table;
+  rio_driver.termios = rio_termios;
+  rio_driver.termios_locked = rio_termios_locked;
+
+  rio_driver.open  = riotopen;
+  rio_driver.close = gs_close;
+  rio_driver.write = gs_write;
+  rio_driver.put_char = gs_put_char;
+  rio_driver.flush_chars = gs_flush_chars;
+  rio_driver.write_room = gs_write_room;
+  rio_driver.chars_in_buffer = gs_chars_in_buffer;
+  rio_driver.flush_buffer = gs_flush_buffer;
+  rio_driver.ioctl = rio_ioctl;
+  rio_driver.throttle = rio_throttle;
+  rio_driver.unthrottle = rio_unthrottle;
+  rio_driver.set_termios = gs_set_termios;
+  rio_driver.stop = gs_stop;
+  rio_driver.start = gs_start;
+  rio_driver.hangup = gs_hangup;
+
+  rio_driver2 = rio_driver;
+  rio_driver.major = RIO_NORMAL_MAJOR1;
+
+  rio_callout_driver = rio_driver;
+  rio_callout_driver.name = "cusr";
+  rio_callout_driver.major = RIO_CALLOUT_MAJOR0;
+  rio_callout_driver.subtype = RIO_TYPE_CALLOUT;
+
+  rio_callout_driver2 = rio_callout_driver;
+  rio_callout_driver2.major = RIO_CALLOUT_MAJOR1;
+
+  rio_dprintk (RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
+
+  if ((error = tty_register_driver(&rio_driver))) goto bad1;
+  if ((error = tty_register_driver(&rio_driver2))) goto bad2;
+  if ((error = tty_register_driver(&rio_callout_driver))) goto bad3;
+  if ((error = tty_register_driver(&rio_callout_driver2))) goto bad4;
+
+  func_exit();
+  return 0;
+  /* 
+ bad5:tty_unregister_driver (&rio_callout_driver2); */
+ bad4:tty_unregister_driver (&rio_callout_driver);
+ bad3:tty_unregister_driver (&rio_driver2);
+ bad2:tty_unregister_driver (&rio_driver);
+ bad1:printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n",
+             error);
+  return 1;
+}
+
+
+static void * ckmalloc (int size)
+{
+  void *p;
+
+  p = kmalloc(size, GFP_KERNEL);
+  if (p) 
+    memset(p, 0, size);
+  return p;
+}
+
+
+
+static int rio_init_datastructures (void)
+{
+  int i;
+  struct Port *port;
+  func_enter();
+
+  /* Many drivers statically allocate the maximum number of ports
+     There is no reason not to allocate them dynamically. Is there? -- REW */
+  /* However, the RIO driver allows users to configure their first
+     RTA as the ports numbered 504-511. We therefore need to allocate 
+     the whole range. :-(   -- REW */
+
+#define RI_SZ   sizeof(struct rio_info)
+#define HOST_SZ sizeof(struct Host)
+#define PORT_SZ sizeof(struct Port *)
+#define TMIO_SZ sizeof(struct termios *)
+  rio_dprintk (RIO_DEBUG_INIT, "getting : %d %d %d %d %d bytes\n", 
+               RI_SZ, 
+               RIO_HOSTS * HOST_SZ,
+               RIO_PORTS * PORT_SZ,
+               RIO_PORTS * TMIO_SZ,
+               RIO_PORTS * TMIO_SZ);
+  
+  if (!(p                  = ckmalloc (              RI_SZ))) goto free0;
+  if (!(p->RIOHosts        = ckmalloc (RIO_HOSTS * HOST_SZ))) goto free1;
+  if (!(p->RIOPortp        = ckmalloc (RIO_PORTS * PORT_SZ))) goto free2;
+  if (!(rio_termios        = ckmalloc (RIO_PORTS * TMIO_SZ))) goto free3;
+  if (!(rio_termios_locked = ckmalloc (RIO_PORTS * TMIO_SZ))) goto free4;
+  p->RIOConf = RIOConf;
+  rio_dprintk (RIO_DEBUG_INIT, "Got : %p %p %p %p %p\n", 
+               p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+
+  /* Adjust the values in the "driver" */
+  rio_driver.termios = rio_termios;
+  rio_driver.termios_locked = rio_termios_locked;
+  
+#if 1
+  for (i = 0; i < RIO_PORTS; i++) {
+    port = p->RIOPortp[i] = ckmalloc (sizeof (struct Port));
+    if (!port) {
+      goto free6;
+    }
+    rio_dprintk (RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
+    port->PortNum = i;
+    port->gs.callout_termios = tty_std_termios;
+    port->gs.normal_termios  = tty_std_termios;
+    port->gs.magic = RIO_MAGIC;
+    port->gs.close_delay = HZ/2;
+    port->gs.closing_wait = 30 * HZ;
+    port->gs.rd = &rio_real_driver;
+  }
+#else
+  /* We could postpone initializing them to when they are configured. */
+#endif
+
+  if (rio_debug & RIO_DEBUG_INIT) {
+    my_hd (&rio_real_driver, sizeof (rio_real_driver));
+  }
+
+  
+  func_exit();
+  return 0;
+
+ free6:for (i--;i>=0;i--)
+        kfree (p->RIOPortp[i]);
+/*free5: */
+       kfree (rio_termios_locked); 
+ free4:kfree (rio_termios);
+ free3:kfree (p->RIOPortp);
+ free2:kfree (p->RIOHosts);
+ free1:kfree (p);
+ free0:
+  rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
+               p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+  return -ENOMEM;
+}
+
+
+#ifdef MODULE
+static void rio_release_drivers(void)
+{
+  func_enter();
+  tty_unregister_driver (&rio_callout_driver2);
+  tty_unregister_driver (&rio_callout_driver);
+  tty_unregister_driver (&rio_driver2);
+  tty_unregister_driver (&rio_driver);
+  func_exit();
+}
+#endif
+
+#ifdef TWO_ZERO
+#define PDEV unsigned char pci_bus, unsigned pci_fun
+#define pdev pci_bus, pci_fun
+#else
+#define PDEV   struct pci_dev *pdev
+#endif
+
+
+#ifdef CONFIG_PCI
+ /* This was written for SX, but applies to RIO too...
+    (including bugs....)
+
+    There is another bit besides Bit 17. Turning that bit off
+    (on boards shipped with the fix in the eeprom) results in a 
+    hang on the next access to the card. 
+ */
+
+ /******************************************************** 
+ * Setting bit 17 in the CNTRL register of the PLX 9050  * 
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon  *
+ * multiprocessor systems with the NX chipset.    -- NV  *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+   EEprom.  As the bit is read/write for the CPU, we can fix it here,
+   if we detect that it isn't set correctly. -- REW */
+
+void fix_rio_pci (PDEV)
+{
+  unsigned int hwbase;
+  unsigned long rebase;
+  unsigned int t;
+
+#define CNTRL_REG_OFFSET        0x50
+#define CNTRL_REG_GOODVALUE     0x00260000
+
+  pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
+  hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
+  rebase =  (ulong) ioremap(hwbase, 0x80);
+  t = readl (rebase + CNTRL_REG_OFFSET);
+  if (t != CNTRL_REG_GOODVALUE) {
+    printk (KERN_DEBUG "rio: performing cntrl reg fix: %08x -> %08x\n", 
+            t, CNTRL_REG_GOODVALUE); 
+    writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);  
+  }
+  my_iounmap (hwbase, rebase);
+}
+#endif
+
+
+#ifdef MODULE
+#define rio_init init_module
+#endif
+
+extern int gs_debug;
+
+int rio_init(void) 
+{
+  int found = 0;
+  int i;
+  struct Host *hp;
+  int retval;
+  struct vpd_prom *vpdp;
+  int okboard;
+
+
+#ifdef CONFIG_PCI
+#ifndef TWO_ZERO
+  struct pci_dev *pdev = NULL;
+#else
+  unsigned char pci_bus, pci_fun;
+  /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */
+#endif
+  unsigned int tint;
+  unsigned short tshort;
+#endif
+
+  func_enter();
+  rio_dprintk (RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n", 
+	       rio_debug);
+  gs_debug = rio_debug >> 24;
+
+  if (abs ((long) (&rio_debug) - rio_debug) < 0x10000) {
+    printk (KERN_WARNING "rio: rio_debug is an address, instead of a value. "
+            "Assuming -1. Was %x/%p.\n", rio_debug, &rio_debug);
+    rio_debug=-1;
+  }
+
+  retval = rio_init_datastructures ();
+  if (retval < 0) return retval;
+
+#ifdef CONFIG_PCI
+  if (pci_present ()) {
+    /* First look for the JET devices: */
+#ifndef TWO_ZERO
+    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+                                    PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
+                                    pdev))) {
+#else
+    for (i=0;i< RIO_NBOARDS;i++) {
+      if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+			       PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i,
+			       &pci_bus, &pci_fun)) break;
+#endif
+      /* Specialix has a whole bunch of cards with
+         0x2000 as the device ID. They say its because
+         the standard requires it. Stupid standard. */
+      /* It seems that reading a word doesn't work reliably on 2.0.
+         Also, reading a non-aligned dword doesn't work. So we read the
+         whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+         ourselves */
+      /* I don't know why the define doesn't work, constant 0x2c does --REW */ 
+      pci_read_config_dword (pdev, 0x2c, &tint);
+      tshort = (tint >> 16) & 0xffff;
+      rio_dprintk (RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+      /* rio_dprintk (RIO_DEBUG_PROBE, "pdev = %d/%d  (%x)\n", pdev, tint); */ 
+      if (tshort != 0x0100) {
+        rio_dprintk (RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", 
+                    tshort);
+        continue;
+      }
+      rio_dprintk (RIO_DEBUG_PROBE, "cp1\n");
+
+      pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+
+      hp = &p->RIOHosts[p->RIONumHosts];
+      hp->PaddrP =  tint & PCI_BASE_ADDRESS_MEM_MASK;
+      hp->Ivec = get_irq (pdev);
+      if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0;
+      hp->CardP	= (struct DpRam *)
+      hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+      hp->Type  = RIO_PCI;
+      hp->Copy  = rio_pcicopy; 
+      hp->Mode  = RIO_PCI_DEFAULT_MODE;
+ 
+      rio_dprintk (RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n",
+                   (void *)p->RIOHosts[p->RIONumHosts].PaddrP,
+                   p->RIOHosts[p->RIONumHosts].Caddr);
+      if (RIOBoardTest( p->RIOHosts[p->RIONumHosts].PaddrP,
+                        p->RIOHosts[p->RIONumHosts].Caddr, 
+                        RIO_PCI, 0 ) == RIO_SUCCESS) {
+        WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff);
+        p->RIOHosts[p->RIONumHosts].UniqueNum  =
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0]) &0xFF)<< 0)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1]) &0xFF)<< 8)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2]) &0xFF)<<16)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3]) &0xFF)<<24);
+        rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n",
+                   p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+#if 1
+        fix_rio_pci (pdev);
+#endif
+        p->RIOLastPCISearch = RIO_SUCCESS;
+        p->RIONumHosts++;
+        found++;
+      } else {
+        my_iounmap (p->RIOHosts[p->RIONumHosts].PaddrP, 
+                    p->RIOHosts[p->RIONumHosts].Caddr);
+      }
+
+#ifdef TWO_ZERO
+    }  /* We have two variants with the opening brace, so to prevent */
+#else
+    }  /* Emacs from getting confused we have two closing braces too. */
+#endif
+    
+
+    /* Then look for the older PCI card.... : */
+#ifndef TWO_ZERO
+
+  /* These older PCI cards have problems (only byte-mode access is
+     supported), which makes them a bit awkward to support. 
+     They also have problems sharing interrupts. Be careful. 
+     (The driver now refuses to share interrupts for these
+     cards. This should be sufficient).
+  */
+
+    /* Then look for the older RIO/PCI devices: */
+    while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+                                    PCI_DEVICE_ID_SPECIALIX_RIO, 
+                                    pdev))) {
+#else
+    for (i=0;i< RIO_NBOARDS;i++) {
+      if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+			       PCI_DEVICE_ID_SPECIALIX_RIO, i,
+			       &pci_bus, &pci_fun)) break;
+#endif
+
+#ifdef CONFIG_RIO_OLDPCI
+      pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &tint);
+
+      hp = &p->RIOHosts[p->RIONumHosts];
+      hp->PaddrP =  tint & PCI_BASE_ADDRESS_MEM_MASK;
+      hp->Ivec = get_irq (pdev);
+      if (((1 << hp->Ivec) & rio_irqmask) == 0) hp->Ivec = 0;
+      hp->Ivec |= 0x8000; /* Mark as non-sharable */
+      hp->CardP	= (struct DpRam *)
+      hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+      hp->Type  = RIO_PCI;
+      hp->Copy  = rio_pcicopy;
+      hp->Mode  = RIO_PCI_DEFAULT_MODE;
+ 
+      rio_dprintk (RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n",
+                   (void *)p->RIOHosts[p->RIONumHosts].PaddrP,
+                   p->RIOHosts[p->RIONumHosts].Caddr);
+      if (RIOBoardTest( p->RIOHosts[p->RIONumHosts].PaddrP,
+                        p->RIOHosts[p->RIONumHosts].Caddr, 
+                        RIO_PCI, 0 ) == RIO_SUCCESS) {
+        WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff);
+        p->RIOHosts[p->RIONumHosts].UniqueNum  =
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0]) &0xFF)<< 0)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1]) &0xFF)<< 8)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2]) &0xFF)<<16)|
+          ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3]) &0xFF)<<24);
+        rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n",
+                   p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+        p->RIOLastPCISearch = RIO_SUCCESS;
+        p->RIONumHosts++;
+        found++;
+      } else {
+        my_iounmap (p->RIOHosts[p->RIONumHosts].PaddrP, 
+                    p->RIOHosts[p->RIONumHosts].Caddr);
+      }
+#else
+      printk (KERN_ERR "Found an older RIO PCI card, but the driver is not "
+              "compiled to support it.\n");
+#endif
+#ifdef TWO_ZERO
+    }  /* We have two variants with the opening brace, so to prevent */
+#else
+    }  /* Emacs from getting confused we have two closing braces too. */
+#endif
+  }
+#endif /* PCI */
+
+  /* Now probe for ISA cards... */
+  for (i=0;i<NR_RIO_ADDRS;i++) {
+    hp = &p->RIOHosts[p->RIONumHosts];
+    hp->PaddrP = rio_probe_addrs[i];
+    /* There was something about the IRQs of these cards. 'Forget what.--REW */
+    hp->Ivec = 0;
+    hp->CardP = (struct DpRam *)
+    hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+    hp->Type = RIO_AT;
+    hp->Copy = rio_pcicopy;
+    hp->Mode = 0;
+
+    vpdp = get_VPD_PROM (hp);
+
+    okboard = 0;
+    if ((strncmp (vpdp->identifier, RIO_ISA_IDENT, 16) == 0) ||
+        (strncmp (vpdp->identifier, RIO_ISA2_IDENT, 16) == 0) ||
+        (strncmp (vpdp->identifier, RIO_ISA3_IDENT, 16) == 0)) {
+      /* Board is present... */
+      if (RIOBoardTest (hp->PaddrP, 
+                        hp->Caddr, RIO_AT, 0) == RIO_SUCCESS) {
+        /* ... and feeling fine!!!! */
+        rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n",
+                   p->RIOHosts[p->RIONumHosts].UniqueNum);
+        if (RIOAssignAT(p, hp->PaddrP, hp->Caddr, 0)) {        
+          rio_dprintk (RIO_DEBUG_PROBE, "Hmm Tested ok, host%d uniqid = %x.\n",
+                       p->RIONumHosts, 
+                       p->RIOHosts[p->RIONumHosts-1].UniqueNum);
+          okboard++;
+          found++;
+        }
+      }
+
+    if (!okboard)
+      my_iounmap (hp->PaddrP, hp->Caddr);
+    }
+  }
+
+
+  for (i=0;i<p->RIONumHosts;i++) {
+    hp = &p->RIOHosts[i];
+    if (hp->Ivec) {
+      int mode = SA_SHIRQ;
+      if (hp->Ivec & 0x8000) {mode = 0; hp->Ivec &= 0x7fff;}
+      if (request_irq (hp->Ivec, rio_interrupt, mode, "rio", (void *)i)) {
+        printk(KERN_ERR "rio: Cannot allocate irq %d.\n", hp->Ivec);
+        hp->Ivec = 0;
+      }
+      rio_dprintk (RIO_DEBUG_INIT, "Got irq %d.\n", hp->Ivec);
+    }
+    /* Init the timer "always" to make sure that it can safely be 
+       deleted when we unload... */
+
+    init_timer (&hp->timer);
+    if (!hp->Ivec) {
+      rio_dprintk (RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", 
+                   rio_poll);
+      hp->timer.data = i;
+      hp->timer.function = rio_pollfunc;
+      hp->timer.expires = jiffies + rio_poll;
+      add_timer (&hp->timer);
+    }
+  }
+
+  if (found) {
+    printk (KERN_INFO "rio: total of %d boards detected.\n", found);
+
+    if (misc_register(&rio_fw_device) < 0) {
+      printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n");
+      return -EIO;
+    }
+    rio_init_drivers ();
+  }
+
+  func_exit();
+  return found?0:-EIO;
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+  int i; 
+  struct Host *hp;
+  
+  func_enter();
+
+  for (i=0,hp=p->RIOHosts;i<p->RIONumHosts;i++, hp++) {
+    RIOHostReset (hp->Type, hp->CardP, hp->Slot);
+    if (hp->Ivec) {
+      free_irq (hp->Ivec, (void *)i);
+      rio_dprintk (RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
+    }
+    /* It is safe/allowed to del_timer a non-active timer */
+    del_timer (&hp->timer);
+  }
+
+  if (misc_deregister(&rio_fw_device) < 0) {
+    printk (KERN_INFO "rio: couldn't deregister control-device\n");
+  }
+
+
+  rio_dprintk (RIO_DEBUG_CLEANUP, "Cleaning up drivers\n");
+
+  rio_release_drivers ();
+
+  /* Release dynamically allocated memory */
+  kfree (rio_termios_locked); 
+  kfree (rio_termios);
+  kfree (p->RIOPortp);
+  kfree (p->RIOHosts);
+  kfree (p);
+
+  func_exit();
+}
+#endif
+
+
+
+/*
+ * Anybody who knows why this doesn't work for me, please tell me -- REW.
+ * Snatched from scsi.c (fixed one spelling error):
+ * Overrides for Emacs so that we follow Linus' tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local Variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h
--- v2.3.99-pre6/linux/drivers/char/rio/rio_linux.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rio_linux.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,162 @@
+
+/*
+ *  rio_linux.h
+ *
+ *  Copyright (C) 1998,1999,2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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.
+ *
+ *  RIO serial driver.
+ *
+ *  Version 1.0 -- July, 1999. 
+ * 
+ */
+
+#define RIO_NBOARDS        4
+#define RIO_PORTSPERBOARD 128
+#define RIO_NPORTS        (RIO_NBOARDS * RIO_PORTSPERBOARD)
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+
+#define RIO_MAGIC 0x12345678
+
+
+struct vpd_prom {
+  unsigned short id;
+  char hwrev;
+  char hwass;
+  int uniqid;
+  char myear;
+  char mweek;
+  char hw_feature[5];
+  char oem_id;
+  char identifier[16];
+};
+
+
+#define RIO_DEBUG_ALL           0xffffffff
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+
+#endif /* __KERNEL__ */
+
+
+#define RIO_BOARD_INTR_LOCK  1
+
+
+#ifndef RIOCTL_MISC_MINOR 
+/* Allow others to gather this into "major.h" or something like that */
+#define RIOCTL_MISC_MINOR    169
+#endif
+
+
+/* Allow us to debug "in the field" without requiring clients to
+   recompile.... */
+#if 1
+#define rio_spin_lock_irqsave(sem, flags) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlockirqsave: %p %s:%d\n", \
+					sem, __FILE__, __LINE__));\
+        spin_lock_irqsave(sem, flags);\
+        } while (0)
+
+#define rio_spin_unlock_irqrestore(sem, flags) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlockirqrestore: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_unlock_irqrestore(sem, flags);\
+        } while (0)
+
+
+#define rio_spin_lock(sem) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlock: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_lock(sem);\
+        } while (0)
+
+#define rio_spin_unlock(sem) do { \
+	rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlock: %p %s:%d\n",\
+					sem, __FILE__, __LINE__));\
+        spin_unlock(sem);\
+        } while (0)
+#else
+#define rio_spin_lock_irqsave(sem, flags) \
+            spin_lock_irqsave(sem, flags)
+
+#define rio_spin_unlock_irqrestore(sem, flags) \
+            spin_unlock_irqrestore(sem, flags)
+
+#define rio_spin_lock(sem) \
+            spin_lock(sem) 
+
+#define rio_spin_unlock(sem) \
+            spin_unlock(sem) 
+
+#endif
+
+
+
+#ifdef CONFIG_RIO_OLDPCI
+static inline void *rio_memcpy_toio (void *dummy, void *dest, void *source, int n)
+{
+  char *dst = dest;
+  char *src = source;
+
+  while (n--) {
+    writeb (*src++, dst++);
+    (void) readb (dummy);
+  }
+
+  return dest;
+}
+
+
+static inline void *rio_memcpy_fromio (void *dest, void *source, int n)
+{
+  char *dst = dest;
+  char *src = source;
+
+  while (n--) 
+    *dst++ = readb (src++);
+
+  return dest;
+}
+
+#else
+#define rio_memcpy_toio(dummy,dest,source,n)   memcpy_toio(dest, source, n)
+#define rio_memcpy_fromio                      memcpy_fromio
+#endif
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioboard.h linux/drivers/char/rio/rioboard.h
--- v2.3.99-pre6/linux/drivers/char/rio/rioboard.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioboard.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,281 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	RIO Host Card Hardware Definitions	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	26th April 1999				*/
+/*									*/
+/*	Version		:	1.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1999	*
+ *
+ *      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.
+ *									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the RIO board hardware	*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+1.0.0	26/04/99 NPV	Creation.
+
+*/
+
+#ifndef	_rioboard_h				/* If RIOBOARD.H not already defined */
+#define	_rioboard_h    1
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   Hardware Control Registers   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* Hardware Registers... */
+
+#define	RIO_REG_BASE	0x7C00			/* Base of control registers */
+
+#define	RIO_CONFIG	RIO_REG_BASE + 0x0000	/* WRITE: Configuration Register */
+#define	RIO_INTSET	RIO_REG_BASE + 0x0080	/* WRITE: Interrupt Set */
+#define	RIO_RESET	RIO_REG_BASE + 0x0100	/* WRITE: Host Reset */
+#define	RIO_INTRESET	RIO_REG_BASE + 0x0180	/* WRITE: Interrupt Reset */
+
+#define	RIO_VPD_ROM	RIO_REG_BASE + 0x0000	/* READ: Vital Product Data ROM */
+#define	RIO_INTSTAT	RIO_REG_BASE + 0x0080	/* READ: Interrupt Status (Jet boards only) */
+#define	RIO_RESETSTAT	RIO_REG_BASE + 0x0100	/* READ: Reset Status (Jet boards only) */
+
+/* RIO_VPD_ROM definitions... */
+#define	VPD_SLX_ID1	0x00			/* READ: Specialix Identifier #1 */
+#define	VPD_SLX_ID2	0x01			/* READ: Specialix Identifier #2 */
+#define	VPD_HW_REV	0x02			/* READ: Hardware Revision */
+#define	VPD_HW_ASSEM	0x03			/* READ: Hardware Assembly Level */
+#define	VPD_UNIQUEID4	0x04			/* READ: Unique Identifier #4 */
+#define	VPD_UNIQUEID3	0x05			/* READ: Unique Identifier #3 */
+#define	VPD_UNIQUEID2	0x06			/* READ: Unique Identifier #2 */
+#define	VPD_UNIQUEID1	0x07			/* READ: Unique Identifier #1 */
+#define	VPD_MANU_YEAR	0x08			/* READ: Year Of Manufacture (0 = 1970) */
+#define	VPD_MANU_WEEK	0x09			/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	VPD_HWFEATURE1	0x0A			/* READ: Hardware Feature Byte 1 */
+#define	VPD_HWFEATURE2	0x0B			/* READ: Hardware Feature Byte 2 */
+#define	VPD_HWFEATURE3	0x0C			/* READ: Hardware Feature Byte 3 */
+#define	VPD_HWFEATURE4	0x0D			/* READ: Hardware Feature Byte 4 */
+#define	VPD_HWFEATURE5	0x0E			/* READ: Hardware Feature Byte 5 */
+#define	VPD_OEMID	0x0F			/* READ: OEM Identifier */
+#define	VPD_IDENT	0x10			/* READ: Identifier string (16 bytes) */
+#define	VPD_IDENT_LEN	0x10
+
+/* VPD ROM Definitions... */
+#define	SLX_ID1		0x4D
+#define	SLX_ID2		0x98
+
+#define	PRODUCT_ID(a)	((a>>4)&0xF)		/* Use to obtain Product ID from VPD_UNIQUEID1 */
+
+#define	ID_SX_ISA	0x2
+#define	ID_RIO_EISA	0x3
+#define	ID_SX_PCI	0x5
+#define	ID_SX_EISA	0x7
+#define	ID_RIO_RTA16	0x9
+#define	ID_RIO_ISA	0xA
+#define	ID_RIO_MCA	0xB
+#define	ID_RIO_SBUS	0xC
+#define	ID_RIO_PCI	0xD
+#define	ID_RIO_RTA8	0xE
+
+/* Transputer bootstrap definitions... */
+
+#define	BOOTLOADADDR		(0x8000 - 6)
+#define	BOOTINDICATE		(0x8000 - 2)
+
+/* Firmware load position... */
+
+#define	FIRMWARELOADADDR	0x7C00		/* Firmware is loaded _before_ this address */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev1) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_ISA_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA_CFG_IRQMASK	0x30		/* Interrupt mask */
+#define	  RIO_ISA_CFG_IRQ12	0x10		/* Interrupt Level 12 */
+#define	  RIO_ISA_CFG_IRQ11	0x20		/* Interrupt Level 11 */
+#define	  RIO_ISA_CFG_IRQ9	0x30		/* Interrupt Level 9 */
+#define	RIO_ISA_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA_CFG_WAITSTATE0	0x80		/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev2) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA2_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA2_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_ISA2_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA2_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_ISA2_CFG_16BIT	0x08		/* 16bit mode, else 8bit */
+#define	RIO_ISA2_CFG_IRQMASK	0x30		/* Interrupt mask */
+#define	  RIO_ISA2_CFG_IRQ15	0x00		/* Interrupt Level 15 */
+#define	  RIO_ISA2_CFG_IRQ12	0x10		/* Interrupt Level 12 */
+#define	  RIO_ISA2_CFG_IRQ11	0x20		/* Interrupt Level 11 */
+#define	  RIO_ISA2_CFG_IRQ9	0x30		/* Interrupt Level 9 */
+#define	RIO_ISA2_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA2_CFG_WAITSTATE0	0x80		/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) ISA   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA3_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_ISA3_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_ISA3_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_ISA32_CFG_IRQMASK	0xF30		/* Interrupt mask */
+#define	  RIO_ISA3_CFG_IRQ15	0xF0		/* Interrupt Level 15 */
+#define	  RIO_ISA3_CFG_IRQ12	0xC0		/* Interrupt Level 12 */
+#define	  RIO_ISA3_CFG_IRQ11	0xB0		/* Interrupt Level 11 */
+#define	  RIO_ISA3_CFG_IRQ10	0xA0		/* Interrupt Level 10 */
+#define	  RIO_ISA3_CFG_IRQ9	0x90		/* Interrupt Level 9 */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO MCA   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_MCA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_MCA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_MCA_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_MCA_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO EISA   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* EISA Configuration Space Definitions... */
+#define	EISA_PRODUCT_ID1	0xC80
+#define	EISA_PRODUCT_ID2	0xC81
+#define	EISA_PRODUCT_NUMBER	0xC82
+#define	EISA_REVISION_NUMBER	0xC83
+#define	EISA_CARD_ENABLE	0xC84
+#define	EISA_VPD_UNIQUEID4	0xC88		/* READ: Unique Identifier #4 */
+#define	EISA_VPD_UNIQUEID3	0xC8A		/* READ: Unique Identifier #3 */
+#define	EISA_VPD_UNIQUEID2	0xC90		/* READ: Unique Identifier #2 */
+#define	EISA_VPD_UNIQUEID1	0xC92		/* READ: Unique Identifier #1 */
+#define	EISA_VPD_MANU_YEAR	0xC98		/* READ: Year Of Manufacture (0 = 1970) */
+#define	EISA_VPD_MANU_WEEK	0xC9A		/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	EISA_MEM_ADDR_23_16	0xC00
+#define	EISA_MEM_ADDR_31_24	0xC01
+#define	EISA_RIO_CONFIG		0xC02		/* WRITE: Configuration Register */
+#define	EISA_RIO_INTSET		0xC03		/* WRITE: Interrupt Set */
+#define	EISA_RIO_INTRESET	0xC03		/* READ:  Interrupt Reset */
+
+/* Control Register Definitions... */
+#define	RIO_EISA_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_EISA_CFG_LINK20	0x02		/* 20Mbps link, else 10Mbps */
+#define	RIO_EISA_CFG_BUSENABLE	0x04		/* Enable processor bus */
+#define	RIO_EISA_CFG_PROCRUN	0x08		/* Processor running, else reset */
+#define	RIO_EISA_CFG_IRQMASK	0xF0		/* Interrupt mask */
+#define	  RIO_EISA_CFG_IRQ15	0xF0		/* Interrupt Level 15 */
+#define	  RIO_EISA_CFG_IRQ14	0xE0		/* Interrupt Level 14 */
+#define	  RIO_EISA_CFG_IRQ12	0xC0		/* Interrupt Level 12 */
+#define	  RIO_EISA_CFG_IRQ11	0xB0		/* Interrupt Level 11 */
+#define	  RIO_EISA_CFG_IRQ10	0xA0		/* Interrupt Level 10 */
+#define	  RIO_EISA_CFG_IRQ9	0x90		/* Interrupt Level 9 */
+#define	  RIO_EISA_CFG_IRQ7	0x70		/* Interrupt Level 7 */
+#define	  RIO_EISA_CFG_IRQ6	0x60		/* Interrupt Level 6 */
+#define	  RIO_EISA_CFG_IRQ5	0x50		/* Interrupt Level 5 */
+#define	  RIO_EISA_CFG_IRQ4	0x40		/* Interrupt Level 4 */
+#define	  RIO_EISA_CFG_IRQ3	0x30		/* Interrupt Level 3 */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO SBus   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_SBUS_IDENT	"JBPGK#\0\0\0\0\0\0\0\0\0\0"
+
+#define	RIO_SBUS_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_SBUS_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_SBUS_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_SBUS_CFG_IRQMASK	0x38		/* Interrupt mask */
+#define	  RIO_SBUS_CFG_IRQNONE	0x00		/* No Interrupt */
+#define	  RIO_SBUS_CFG_IRQ7	0x38		/* Interrupt Level 7 */
+#define	  RIO_SBUS_CFG_IRQ6	0x30		/* Interrupt Level 6 */
+#define	  RIO_SBUS_CFG_IRQ5	0x28		/* Interrupt Level 5 */
+#define	  RIO_SBUS_CFG_IRQ4	0x20		/* Interrupt Level 4 */
+#define	  RIO_SBUS_CFG_IRQ3	0x18		/* Interrupt Level 3 */
+#define	  RIO_SBUS_CFG_IRQ2	0x10		/* Interrupt Level 2 */
+#define	  RIO_SBUS_CFG_IRQ1	0x08		/* Interrupt Level 1 */
+#define	RIO_SBUS_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_SBUS_CFG_PROC25	0x80		/* 25Mhz processor clock, else 20Mhz */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO PCI   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI_IDENT	"ECDDPGJGJHJRGSK#"
+
+#define	RIO_PCI_CFG_BOOTRAM	0x01		/* Boot from RAM, else Link */
+#define	RIO_PCI_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_PCI_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+#define	RIO_PCI_CFG_LINK20	0x40		/* 20Mbps link, else 10Mbps */
+#define	RIO_PCI_CFG_PROC25	0x80		/* 25Mhz processor clock, else 20Mhz */
+
+/* PCI Definitions... */
+#define	SPX_VENDOR_ID		0x11CB		/* Assigned by the PCI SIG */
+#define	SPX_DEVICE_ID		0x8000		/* RIO bridge boards */
+#define	SPX_PLXDEVICE_ID	0x2000		/* PLX bridge boards */
+#define	SPX_SUB_VENDOR_ID	SPX_VENDOR_ID	/* Same as vendor id */
+#define	RIO_SUB_SYS_ID		0x0800		/* RIO PCI board */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) PCI   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI2_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_PCI2_CFG_BUSENABLE	0x02		/* Enable processor bus */
+#define	RIO_PCI2_CFG_INTENABLE	0x04		/* Interrupt enable, else disable */
+
+/* PCI Definitions... */
+#define	RIO2_SUB_SYS_ID		0x0100		/* RIO (Jet) PCI board */
+
+#endif						/*_rioboard_h */
+
+/* End of RIOBOARD.H */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c
--- v2.3.99-pre6/linux/drivers/char/rio/rioboot.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioboot.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1329 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioboot.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:36
+**	Retrieved	: 11/6/98 10:33:48
+**
+**  ident @(#)rioboot.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifdef SCCS_LABELS
+static char *_rioboot_c_sccs_ = "@(#)rioboot.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+
+
+static uchar
+RIOAtVec2Ctrl[] =
+{
+	/* 0 */  INTERRUPT_DISABLE,
+	/* 1 */  INTERRUPT_DISABLE,
+	/* 2 */  INTERRUPT_DISABLE,
+	/* 3 */  INTERRUPT_DISABLE,
+	/* 4 */  INTERRUPT_DISABLE,
+	/* 5 */  INTERRUPT_DISABLE,
+	/* 6 */  INTERRUPT_DISABLE,
+	/* 7 */  INTERRUPT_DISABLE,
+	/* 8 */  INTERRUPT_DISABLE,
+	/* 9 */  IRQ_9|INTERRUPT_ENABLE,
+	/* 10 */ INTERRUPT_DISABLE,
+	/* 11 */ IRQ_11|INTERRUPT_ENABLE,
+	/* 12 */ IRQ_12|INTERRUPT_ENABLE,
+	/* 13 */ INTERRUPT_DISABLE,
+	/* 14 */ INTERRUPT_DISABLE,
+	/* 15 */ IRQ_15|INTERRUPT_ENABLE
+};
+
+/*
+** Load in the RTA boot code.
+*/
+int
+RIOBootCodeRTA(p, rbp)
+struct rio_info *	p;
+struct DownLoad *	rbp; 
+{
+	int offset;
+
+	/* Linux doesn't allow you to disable interrupts during a
+	   "copyin". (Crash when a pagefault occurs). */
+	/* disable(oldspl); */
+	
+	rio_dprint(RIO_DEBUG_BOOT, ("Data at user address 0x%x\n",(int)rbp->DataP));
+
+	/*
+	** Check that we have set asside enough memory for this
+	*/
+	if ( rbp->Count > SIXTY_FOUR_K ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code Too Large!\n"));
+		p->RIOError.Error = HOST_FILE_TOO_LARGE;
+		/* restore(oldspl); */
+		return ENOMEM;
+	}
+
+	if ( p->RIOBooting ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code : BUSY BUSY BUSY!\n"));
+		p->RIOError.Error = BOOT_IN_PROGRESS;
+		/* restore(oldspl); */
+		return EBUSY;
+	}
+
+	/*
+	** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary,
+	** so calculate how far we have to move the data up the buffer
+	** to achieve this.
+	*/
+	offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % 
+							RTA_BOOT_DATA_SIZE;
+
+	/*
+	** Be clean, and clear the 'unused' portion of the boot buffer,
+	** because it will (eventually) be part of the Rta run time environment
+	** and so should be zeroed.
+	*/
+	bzero( (caddr_t)p->RIOBootPackets, offset );
+
+	/*
+	** Copy the data from user space.
+	*/
+
+	if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset,
+				rbp->Count) ==COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Bad data copy from user space\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		/* restore(oldspl); */
+		return EFAULT;
+	}
+
+	/*
+	** Make sure that our copy of the size includes that offset we discussed
+	** earlier.
+	*/
+	p->RIONumBootPkts = (rbp->Count+offset)/RTA_BOOT_DATA_SIZE;
+	p->RIOBootCount   = rbp->Count;
+
+	/* restore(oldspl); */
+	return 0;
+}
+
+
+/*
+** Load in the host boot code - load it directly onto all halted hosts
+** of the correct type.
+**
+** Put your rubber pants on before messing with this code - even the magic
+** numbers have trouble understanding what they are doing here.
+*/
+int
+RIOBootCodeHOST(p, rbp)
+struct rio_info *	p;
+register struct DownLoad *rbp;
+{
+	register struct Host *HostP;
+	register caddr_t Cad;
+	register PARM_MAP *ParmMapP;
+	register int RupN;
+	int PortN;
+	uint host;
+	caddr_t StartP;
+	BYTE *DestP;
+	int wait_count;
+	ushort OldParmMap;
+	ushort offset;	/* It is very important that this is a ushort */
+	/* uint byte; */
+	caddr_t DownCode = NULL;
+	unsigned long flags;
+
+	HostP = NULL; /* Assure the compiler we've initialized it */
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Attempt to boot host %d\n",host));
+		HostP = &p->RIOHosts[host];
+
+		if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("%s %d already running\n","Host",host));
+			continue;
+		}
+
+		/*
+		** Grab a 32 bit pointer to the card.
+		*/
+		Cad = HostP->Caddr;
+
+		/*
+		** We are going to (try) and load in rbp->Count bytes.
+		** The last byte will reside at p->RIOConf.HostLoadBase-1;
+		** Therefore, we need to start copying at address
+		** (caddr+p->RIOConf.HostLoadBase-rbp->Count)
+		*/
+		StartP = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count];
+
+		rio_dprint(RIO_DEBUG_BOOT,  ("kernel virtual address for host is 0x%x\n", (int)Cad ) );
+		rio_dprint(RIO_DEBUG_BOOT,  ("kernel virtual address for download is 0x%x\n", (int)StartP ) );
+		rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase));
+		rio_dprint(RIO_DEBUG_BOOT,  ("size of download is 0x%x\n", rbp->Count ) );
+
+		if ( p->RIOConf.HostLoadBase < rbp->Count ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Bin too large\n"));
+			p->RIOError.Error = HOST_FILE_TOO_LARGE;
+			return EFBIG;
+		}
+		/*
+		** Ensure that the host really is stopped.
+		** Disable it's external bus & twang its reset line.
+		*/
+		RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );
+
+		/*
+		** Copy the data directly from user space to the SRAM.
+		** This ain't going to be none too clever if the download
+		** code is bigger than this segment.
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Copy in code\n"));
+
+		/*
+		** PCI hostcard can't cope with 32 bit accesses and so need to copy 
+		** data to a local buffer, and then dripfeed the card.
+		*/
+		if ( HostP->Type == RIO_PCI ) {
+		  /* int offset; */
+
+			DownCode = sysbrk(rbp->Count);
+			if ( !DownCode ) {
+				rio_dprint(RIO_DEBUG_BOOT, ("No system memory available\n"));
+				p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;
+				return ENOMEM;
+			}
+			bzero(DownCode, rbp->Count);
+
+			if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n"));
+				p->RIOError.Error = COPYIN_FAILED;
+				return EFAULT;
+			}
+
+			HostP->Copy( DownCode, StartP, rbp->Count );
+
+			sysfree( DownCode, rbp->Count );
+		}
+		else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n"));
+			p->RIOError.Error = COPYIN_FAILED;
+			return EFAULT;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Copy completed\n"));
+
+		/*
+		**			S T O P !
+		**
+		** Upto this point the code has been fairly rational, and possibly
+		** even straight forward. What follows is a pile of crud that will
+		** magically turn into six bytes of transputer assembler. Normally
+		** you would expect an array or something, but, being me, I have
+		** chosen [been told] to use a technique whereby the startup code
+		** will be correct if we change the loadbase for the code. Which
+		** brings us onto another issue - the loadbase is the *end* of the
+		** code, not the start.
+		**
+		** If I were you I wouldn't start from here.
+		*/
+
+		/*
+		** We now need to insert a short boot section into
+		** the memory at the end of Sram2. This is normally (de)composed
+		** of the last eight bytes of the download code. The
+		** download has been assembled/compiled to expect to be
+		** loaded from 0x7FFF downwards. We have loaded it
+		** at some other address. The startup code goes into the small
+		** ram window at Sram2, in the last 8 bytes, which are really
+		** at addresses 0x7FF8-0x7FFF.
+		**
+		** If the loadbase is, say, 0x7C00, then we need to branch to
+		** address 0x7BFE to run the host.bin startup code. We assemble
+		** this jump manually.
+		**
+		** The two byte sequence 60 08 is loaded into memory at address
+		** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0,
+		** which adds '0' to the .O register, complements .O, and then shifts
+		** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will
+		** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new
+		** location. Now, the branch starts from the value of .PC (or .IP or
+		** whatever the bloody register is called on this chip), and the .PC
+		** will be pointing to the location AFTER the branch, in this case
+		** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8.
+		**
+		** A long branch is coded at 0x7FF8. This consists of loading a four
+		** byte offset into .O using nfix (as above) and pfix operators. The
+		** pfix operates in exactly the same way as the nfix operator, but
+		** without the complement operation. The offset, of course, must be
+		** relative to the address of the byte AFTER the branch instruction,
+		** which will be (urm) 0x7FFC, so, our final destination of the branch
+		** (loadbase-2), has to be reached from here. Imagine that the loadbase
+		** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which
+		** is the first byte of the initial two byte short local branch of the
+		** download code).
+		**
+		** To code a jump from 0x7FFC (which is where the branch will start
+		** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)=
+		** 0x7BFE.
+		** This will be coded as four bytes:
+		** 60 2C 20 02
+		** being nfix .O+0
+		**	   pfix .O+C
+		**	   pfix .O+0
+		**	   jump .O+2
+		**
+		** The nfix operator is used, so that the startup code will be
+		** compatible with the whole Tp family. (lies, damn lies, it'll never
+		** work in a month of Sundays).
+		**
+		** The nfix nyble is the 1s compliment of the nyble value you
+		** want to load - in this case we wanted 'F' so we nfix loaded '0'.
+		*/
+
+
+		/*
+		** Dest points to the top 8 bytes of Sram2. The Tp jumps
+		** to 0x7FFE at reset time, and starts executing. This is
+		** a short branch to 0x7FF8, where a long branch is coded.
+		*/
+
+		DestP = (BYTE *)&Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */
+
+#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */
+#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */
+#define	JUMP(N)	(0x00 | (N))	/* .PC =   .PC + .O	 */
+
+		/*
+		** 0x7FFC is the address of the location following the last byte of
+		** the four byte jump instruction.
+		** READ THE ABOVE COMMENTS
+		**
+		** offset is (TO-FROM) % MEMSIZE, but with compound buggering about.
+		** Memsize is 64K for this range of Tp, so offset is a short (unsigned,
+		** cos I don't understand 2's complement).
+		*/
+		offset = (p->RIOConf.HostLoadBase-2)-0x7FFC;
+		WBYTE( DestP[0] , NFIX(((ushort)(~offset) >> (ushort)12) & 0xF) );
+		WBYTE( DestP[1] , PFIX(( offset >> 8) & 0xF) );
+		WBYTE( DestP[2] , PFIX(( offset >> 4) & 0xF) );
+		WBYTE( DestP[3] , JUMP( offset & 0xF) );
+
+		WBYTE( DestP[6] , NFIX(0) );
+		WBYTE( DestP[7] , JUMP(8) );
+
+		rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase));
+		rio_dprint(RIO_DEBUG_BOOT, ("startup offset is 0x%x\n",offset));
+
+		/*
+		** Flag what is going on
+		*/
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_STARTUP;
+
+		/*
+		** Grab a copy of the current ParmMap pointer, so we
+		** can tell when it has changed.
+		*/
+		OldParmMap = RWORD(HostP->__ParmMapR);
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Original parmmap is 0x%x\n",OldParmMap));
+
+		/*
+		** And start it running (I hope).
+		** As there is nothing dodgy or obscure about the
+		** above code, this is guaranteed to work every time.
+		*/
+		rio_dprint(RIO_DEBUG_BOOT,  ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n",
+		    HostP->Type, HostP->Mode, HostP->Ivec ) );
+
+		switch ( HostP->Type ) {
+			case RIO_AT:
+				rio_dprint(RIO_DEBUG_BOOT, ("Start ISA card running\n"));
+				WBYTE(HostP->Control, 
+					BOOT_FROM_RAM | EXTERNAL_BUS_ON
+					| HostP->Mode
+					| RIOAtVec2Ctrl[HostP->Ivec & 0xF] );
+				break;
+
+#ifdef FUTURE_RELEASE
+			case RIO_MCA:
+				/*
+				** MCA handles IRQ vectors differently, so we don't write 
+				** them to this register.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, ("Start MCA card running\n"));
+				WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode);
+				break;
+
+			case RIO_EISA:
+				/*
+				** EISA is totally different and expects OUTBZs to turn it on.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_DAEMON,"Start EISA card running\n");
+				OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM );
+				break;
+#endif
+
+			case RIO_PCI:
+				/*
+				** PCI is much the same as MCA. Everything is once again memory
+				** mapped, so we are writing to memory registers instead of io
+				** ports.
+				*/
+				rio_dprint(RIO_DEBUG_BOOT, ("Start PCI card running\n"));
+				WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode);
+				break;
+			default:
+				rio_dprint(RIO_DEBUG_BOOT, ("Unknown host type %d\n",HostP->Type));
+				break;
+		}
+		rio_dprint(RIO_DEBUG_BOOT, ("Set control port\n"));
+
+		/*
+		** Now, wait for upto five seconds for the Tp to setup the parmmap
+		** pointer:
+		*/
+		for ( wait_count=0; (wait_count<p->RIOConf.StartupTime)&&
+				(RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)));
+			delay(HostP, HUNDRED_MS);
+		}
+
+		/*
+		** If the parmmap pointer is unchanged, then the host code
+		** has crashed & burned in a really spectacular way
+		*/
+		if ( RWORD(HostP->__ParmMapR) == OldParmMap ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("parmmap 0x%x\n", RWORD(HostP->__ParmMapR)));
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail\n"));
+
+#define	HOST_DISABLE \
+		HostP->Flags &= ~RUN_STATE; \
+		HostP->Flags |= RC_STUFFED; \
+		RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );\
+		continue
+
+			HOST_DISABLE;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Running 0x%x\n",RWORD(HostP->__ParmMapR)));
+
+		/*
+		** Well, the board thought it was OK, and setup its parmmap
+		** pointer. For the time being, we will pretend that this
+		** board is running, and check out what the error flag says.
+		*/
+
+		/*
+		** Grab a 32 bit pointer to the parmmap structure
+		*/
+		ParmMapP = (PARM_MAP *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR));
+		rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP));
+		ParmMapP = (PARM_MAP *)((unsigned long)Cad + 
+						(unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); 
+		rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP));
+
+		/*
+		** The links entry should be 0xFFFF; we set it up
+		** with a mask to say how many PHBs to use, and 
+		** which links to use.
+		*/
+		if ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name));
+			rio_dprint(RIO_DEBUG_BOOT, ("Links = 0x%x\n",RWORD(ParmMapP->links)));
+			HOST_DISABLE;
+		}
+
+		WWORD(ParmMapP->links , RIO_LINK_ENABLE);
+
+		/*
+		** now wait for the card to set all the parmmap->XXX stuff
+		** this is a wait of upto two seconds....
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Looking for init_done - %d ticks\n",p->RIOConf.StartupTime));
+		HostP->timeout_id = 0;
+		for ( wait_count=0; (wait_count<p->RIOConf.StartupTime) && 
+						!RWORD(ParmMapP->init_done); wait_count++ ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Waiting for init_done\n"));
+			delay(HostP, HUNDRED_MS);
+		}
+		rio_dprint(RIO_DEBUG_BOOT, ("OK! init_done!\n"));
+
+		if (RWORD(ParmMapP->error) != E_NO_ERROR || 
+							!RWORD(ParmMapP->init_done) ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name));
+			rio_dprint(RIO_DEBUG_BOOT, ("Timedout waiting for init_done\n"));
+			HOST_DISABLE;
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Got init_done\n"));
+
+		/*
+		** It runs! It runs!
+		*/
+		rio_dprint(RIO_DEBUG_BOOT, ("Host ID %x Running\n",HostP->UniqueNum));
+
+		/*
+		** set the time period between interrupts.
+		*/
+		WWORD(ParmMapP->timer, (short)p->RIOConf.Timer );
+
+		/*
+		** Translate all the 16 bit pointers in the __ParmMapR into
+		** 32 bit pointers for the driver.
+		*/
+		HostP->ParmMapP	 =	ParmMapP;
+		HostP->PhbP		 =	(PHB*)RIO_PTR(Cad,RWORD(ParmMapP->phb_ptr));
+		HostP->RupP		 =	(RUP*)RIO_PTR(Cad,RWORD(ParmMapP->rups));
+		HostP->PhbNumP	  = (ushort*)RIO_PTR(Cad,RWORD(ParmMapP->phb_num_ptr));
+		HostP->LinkStrP	 =	(LPB*)RIO_PTR(Cad,RWORD(ParmMapP->link_str_ptr));
+
+		/*
+		** point the UnixRups at the real Rups
+		*/
+		for ( RupN = 0; RupN<MAX_RUP; RupN++ ) {
+			HostP->UnixRups[RupN].RupP		= &HostP->RupP[RupN];
+			HostP->UnixRups[RupN].Id		  = RupN+1;
+			HostP->UnixRups[RupN].BaseSysPort = NO_PORT;
+		}
+
+		for ( RupN = 0; RupN<LINKS_PER_UNIT; RupN++ ) {
+			HostP->UnixRups[RupN+MAX_RUP].RupP	= &HostP->LinkStrP[RupN].rup;
+			HostP->UnixRups[RupN+MAX_RUP].Id  = 0;
+			HostP->UnixRups[RupN+MAX_RUP].BaseSysPort = NO_PORT;
+		}
+
+		/*
+		** point the PortP->Phbs at the real Phbs
+		*/
+		for ( PortN=p->RIOFirstPortsMapped; 
+				PortN<p->RIOLastPortsMapped+PORTS_PER_RTA; PortN++ ) {
+			if ( p->RIOPortp[PortN]->HostP == HostP ) {
+				struct Port *PortP = p->RIOPortp[PortN];
+				struct PHB *PhbP;
+				/* int oldspl; */
+
+				if ( !PortP->Mapped )
+					continue;
+
+				PhbP = &HostP->PhbP[PortP->HostPort];
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				PortP->PhbP = PhbP;
+
+				PortP->TxAdd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_add));
+				PortP->TxStart  = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_start));
+				PortP->TxEnd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_end));
+				PortP->RxRemove = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_remove));
+				PortP->RxStart  = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_start));
+				PortP->RxEnd	= (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_end));
+
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				/*
+				** point the UnixRup at the base SysPort
+				*/
+				if ( !(PortN % PORTS_PER_RTA) )
+					HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;
+			}
+		}
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Set the card running... \n"));
+		/*
+		** last thing - show the world that everything is in place
+		*/
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_RUNNING;
+	}
+	/*
+	** MPX always uses a poller. This is actually patched into the system
+	** configuration and called directly from each clock tick.
+	**
+	*/
+	p->RIOPolling = 1;
+
+	p->RIOSystemUp++;
+	
+	rio_dprint(RIO_DEBUG_BOOT, ("Done everything %x\n", HostP->Ivec));
+	return 0;
+}
+
+
+
+/*
+** Boot an RTA. If we have successfully processed this boot, then
+** return 1. If we havent, then return 0.
+*/
+int
+RIOBootRup( p, Rup, HostP, PacketP)
+struct rio_info *	p;
+uint Rup;
+struct Host *HostP;
+struct PKT *PacketP; 
+{
+	struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+	struct PktCmd_M *PktReplyP;
+	struct CmdBlk *CmdBlkP;
+	uint sequence;
+
+#ifdef CHECK
+	CheckHost(Host);
+	CheckRup(Rup);
+	CheckHostP(HostP);
+	CheckPacketP(PacketP);
+#endif
+
+	/*
+	** If we haven't been told what to boot, we can't boot it.
+	*/
+	if ( p->RIONumBootPkts == 0 ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("No RTA code to download yet\n"));
+		return 0;
+	}
+
+	/* rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_BOOT,"Incoming command packet\n"); */
+	/* ShowPacket( DBG_BOOT, PacketP ); */
+
+	/*
+	** Special case of boot completed - if we get one of these then we
+	** don't need a command block. For all other cases we do, so handle
+	** this first and then get a command block, then handle every other
+	** case, relinquishing the command block if disaster strikes!
+	*/
+	if ( (RBYTE(PacketP->len) & PKT_CMD_BIT) && 
+			(RBYTE(PktCmdP->Command)==BOOT_COMPLETED) )
+		return RIOBootComplete(p, HostP, Rup, PktCmdP );
+
+	/*
+	** try to unhook a command block from the command free list.
+	*/
+	if ( !(CmdBlkP = RIOGetCmdBlk()) ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("No command blocks to boot RTA! come back later.\n"));
+		return 0;
+	}
+
+	/*
+	** Fill in the default info on the command block
+	*/
+	CmdBlkP->Packet.dest_unit = Rup < (ushort)MAX_RUP ? Rup : 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+
+	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+	PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data;
+
+	/*
+	** process COMMANDS on the boot rup!
+	*/
+	if ( RBYTE(PacketP->len) & PKT_CMD_BIT ) {
+		/*
+		** We only expect one type of command - a BOOT_REQUEST!
+		*/
+		if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) {
+			rio_dprint(RIO_DEBUG_BOOT, ("Unexpected command %d on BOOT RUP %d of host %d\n", 
+						PktCmdP->Command,Rup,HostP-p->RIOHosts));
+			ShowPacket( DBG_BOOT, PacketP );
+			RIOFreeCmdBlk( CmdBlkP );
+			return 1;
+		}
+
+		/*
+		** Build a Boot Sequence command block
+		**
+		** 02.03.1999 ARG - ESIL 0820 fix
+		** We no longer need to use "Boot Mode", we'll always allow
+		** boot requests - the boot will not complete if the device
+		** appears in the bindings table.
+		** So, this conditional is not required ...
+		**
+		if (p->RIOBootMode == RC_BOOT_NONE)
+			**
+			** If the system is in slave mode, and a boot request is
+			** received, set command to BOOT_ABORT so that the boot
+			** will not complete.
+			**
+			PktReplyP->Command			 = BOOT_ABORT;
+		else
+		**
+		** We'll just (always) set the command field in packet reply
+		** to allow an attempted boot sequence :
+		*/
+		PktReplyP->Command = BOOT_SEQUENCE;
+
+		PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;
+		PktReplyP->BootSequence.LoadBase   = p->RIOConf.RtaLoadBase;
+		PktReplyP->BootSequence.CodeSize   = p->RIOBootCount;
+
+		CmdBlkP->Packet.len				= BOOT_SEQUENCE_LEN | PKT_CMD_BIT;
+
+		bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4);
+
+		rio_dprint(RIO_DEBUG_BOOT, ("Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n",
+			HostP-p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, 
+								p->RIOConf.RtaLoadBase));
+
+		/*
+		** If this host is in slave mode, send the RTA an invalid boot
+		** sequence command block to force it to kill the boot. We wait
+		** for half a second before sending this packet to prevent the RTA
+		** attempting to boot too often. The master host should then grab
+		** the RTA and make it its own.
+		*/
+		p->RIOBooting++;
+		RIOQueueCmdBlk( HostP, Rup, CmdBlkP );
+		return 1;
+	}
+
+	/*
+	** It is a request for boot data.
+	*/
+	sequence = RWORD(PktCmdP->Sequence);
+
+	rio_dprint(RIO_DEBUG_BOOT, ("Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup));
+
+	if ( sequence >= p->RIONumBootPkts ) {
+		rio_dprint(RIO_DEBUG_BOOT, ("Got a request for packet %d, max is %d\n", sequence, 
+					p->RIONumBootPkts));
+		ShowPacket( DBG_BOOT, PacketP );
+	}
+
+	PktReplyP->Sequence = sequence;
+
+	bcopy( p->RIOBootPackets[ p->RIONumBootPkts - sequence - 1 ], 
+				PktReplyP->BootData, RTA_BOOT_DATA_SIZE );
+
+	CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;
+	ShowPacket( DBG_BOOT, &CmdBlkP->Packet );
+	RIOQueueCmdBlk( HostP, Rup, CmdBlkP );
+	return 1;
+}
+
+/*
+** This function is called when an RTA been booted.
+** If booted by a host, HostP->HostUniqueNum is the booting host.
+** If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA.
+** RtaUniq is the booted RTA.
+*/
+int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP )
+{
+	struct Map	*MapP = NULL;
+	struct Map	*MapP2 = NULL;
+	int	Flag;
+	int	found;
+	int	host, rta;
+	int	EmptySlot = -1;
+	int	entry, entry2;
+	char	*MyType, *MyName;
+	uint	MyLink;
+	ushort	RtaType;
+	uint	RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) +
+			  (RBYTE(PktCmdP->UniqNum[1]) << 8) +
+			  (RBYTE(PktCmdP->UniqNum[2]) << 16) +
+			  (RBYTE(PktCmdP->UniqNum[3]) << 24);
+
+	/* Was RIOBooting-- . That's bad. If an RTA sends two of them, the
+	   driver will never think that the RTA has booted... -- REW */
+	p->RIOBooting = 0;
+
+	rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot completed - BootInProgress now %d\n", p->RIOBooting));
+
+	/*
+	** Determine type of unit (16/8 port RTA).
+	*/
+	RtaType = GetUnitType(RtaUniq);
+        if ( Rup >= (ushort)MAX_RUP ) {
+	    rio_dprint(RIO_DEBUG_BOOT, ("RIO: Host %s has booted an RTA(%d) on link %c\n",
+	     HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A' ));
+	} else {
+	    rio_dprint(RIO_DEBUG_BOOT, ("RIO: RTA %s has booted an RTA(%d) on link %c\n",
+	     HostP->Mapping[Rup].Name, 8 * RtaType,
+	     RBYTE(PktCmdP->LinkNum)+'A'));
+	}
+
+	rio_dprint(RIO_DEBUG_BOOT, ("UniqNum is 0x%x\n",RtaUniq));
+
+        if ( ( RtaUniq == 0x00000000 ) || ( RtaUniq == 0xffffffff ) )
+	{
+	    rio_dprint(RIO_DEBUG_BOOT, ( "Illegal RTA Uniq Number\n"));
+	    return TRUE;
+	}
+
+	/*
+	** If this RTA has just booted an RTA which doesn't belong to this
+	** system, or the system is in slave mode, do not attempt to create
+	** a new table entry for it.
+	*/
+	if (!RIOBootOk(p, HostP, RtaUniq))
+	{
+	    MyLink = RBYTE(PktCmdP->LinkNum);
+	    if (Rup < (ushort) MAX_RUP)
+	    {
+		/*
+		** RtaUniq was clone booted (by this RTA). Instruct this RTA
+		** to hold off further attempts to boot on this link for 30
+		** seconds.
+		*/
+		if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink))
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, ("RTA failed to suspend booting on link %c\n",
+		     'A' + MyLink));
+		}
+	    }
+	    else
+	    {
+		/*
+		** RtaUniq was booted by this host. Set the booting link
+		** to hold off for 30 seconds to give another unit a
+		** chance to boot it.
+		*/
+		WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30);
+	    }
+	    rio_dprint(RIO_DEBUG_BOOT, ("RTA %x not owned - suspend booting down link %c on unit %x\n",
+	      RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum));
+	    return TRUE;
+	}
+
+	/*
+	** Check for a SLOT_IN_USE entry for this RTA attached to the
+	** current host card in the driver table.
+	**
+	** If it exists, make a note that we have booted it. Other parts of
+	** the driver are interested in this information at a later date,
+	** in particular when the booting RTA asks for an ID for this unit,
+	** we must have set the BOOTED flag, and the NEWBOOT flag is used
+	** to force an open on any ports that where previously open on this
+	** unit.
+	*/
+        for ( entry=0; entry<MAX_RUP; entry++ )
+	{
+	    uint sysport;
+
+	    if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && 
+	       (HostP->Mapping[entry].RtaUniqueNum==RtaUniq))
+	    {
+	        HostP->Mapping[entry].Flags |= RTA_BOOTED|RTA_NEWBOOT;
+#if NEED_TO_FIX
+		RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		if ( (sysport=HostP->Mapping[entry].SysPort) != NO_PORT )
+		{
+		   if ( sysport < p->RIOFirstPortsBooted )
+			p->RIOFirstPortsBooted = sysport;
+		   if ( sysport > p->RIOLastPortsBooted )
+			p->RIOLastPortsBooted = sysport;
+		   /*
+		   ** For a 16 port RTA, check the second bank of 8 ports
+		   */
+		   if (RtaType == TYPE_RTA16)
+		   {
+			entry2 = HostP->Mapping[entry].ID2 - 1;
+			HostP->Mapping[entry2].Flags |= RTA_BOOTED|RTA_NEWBOOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+			sysport = HostP->Mapping[entry2].SysPort;
+			if ( sysport < p->RIOFirstPortsBooted )
+			    p->RIOFirstPortsBooted = sysport;
+			if ( sysport > p->RIOLastPortsBooted )
+			    p->RIOLastPortsBooted = sysport;
+		   }
+		}
+		if (RtaType == TYPE_RTA16) {
+		   rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given IDs %d+%d\n",
+		    entry+1, entry2+1));
+		} else {
+		   rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given ID %d\n",entry+1));
+		}
+		return TRUE;
+	    }
+	}
+
+	rio_dprint(RIO_DEBUG_BOOT, ("RTA not configured for this host\n"));
+
+	if ( Rup >= (ushort)MAX_RUP )
+	{
+	    /*
+	    ** It was a host that did the booting
+	    */
+	    MyType = "Host";
+	    MyName = HostP->Name;
+	}
+	else
+	{
+	    /*
+	    ** It was an RTA that did the booting
+	    */
+	    MyType = "RTA";
+	    MyName = HostP->Mapping[Rup].Name;
+	}
+#ifdef CHECK
+	CheckString(MyType);
+	CheckString(MyName);
+#endif
+
+	MyLink = RBYTE(PktCmdP->LinkNum);
+
+	/*
+	** There is no SLOT_IN_USE entry for this RTA attached to the current
+	** host card in the driver table.
+	**
+	** Check for a SLOT_TENTATIVE entry for this RTA attached to the
+	** current host card in the driver table.
+	**
+	** If we find one, then we re-use that slot.
+	*/
+	for ( entry=0; entry<MAX_RUP; entry++ )
+	{
+	    if ( (HostP->Mapping[entry].Flags & SLOT_TENTATIVE) &&
+		 (HostP->Mapping[entry].RtaUniqueNum == RtaUniq) )
+	    {
+		if (RtaType == TYPE_RTA16)
+		{
+		    entry2 = HostP->Mapping[entry].ID2 - 1;
+		    if ( (HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) &&
+			 (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq) )
+			rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slots (%d+%d)\n",
+			 entry, entry2));
+		    else
+			continue;
+		}
+		else
+			rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slot (%d)\n",entry));
+		if (! p->RIONoMessage)
+		    cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A');
+		return TRUE;
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another
+	** host for this RTA in the driver table.
+	**
+	** For a SLOT_IN_USE entry on another host, we need to delete the RTA
+	** entry from the other host and add it to this host (using some of
+	** the functions from table.c which do this).
+	** For a SLOT_TENTATIVE entry on another host, we must cope with the
+	** following scenario:
+	**
+	** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry
+	**   in table)
+	** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE
+	**   entries)
+	** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE)
+	** + Unplug RTA and plug back into host A.
+	** + Configure RTA on host A. We now have the same RTA configured
+	**   with different ports on two different hosts.
+	*/
+	rio_dprint(RIO_DEBUG_BOOT, ("Have we seen RTA %x before?\n", RtaUniq ));
+	found = 0;
+	Flag = 0; /* Convince the compiler this variable is initialized */
+	for ( host = 0; !found && (host < p->RIONumHosts); host++ )
+	{
+	    for ( rta=0; rta<MAX_RUP; rta++ )
+	    {
+		if ((p->RIOHosts[host].Mapping[rta].Flags &
+		 (SLOT_IN_USE | SLOT_TENTATIVE)) &&
+		 (p->RIOHosts[host].Mapping[rta].RtaUniqueNum==RtaUniq))
+		{
+		    Flag = p->RIOHosts[host].Mapping[rta].Flags;
+		    MapP = &p->RIOHosts[host].Mapping[rta];
+		    if (RtaType == TYPE_RTA16)
+		    {
+			MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1];
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is units %d+%d from host %s\n",
+			 rta+1, MapP->ID2, p->RIOHosts[host].Name ));
+		    }
+		    else
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is unit %d from host %s\n",
+			 rta+1, p->RIOHosts[host].Name ));
+		    found = 1;
+		    break;
+		}
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on
+	** another host for this RTA in the driver table...
+	**
+	** Check for a SLOT_IN_USE entry for this RTA in the config table.
+	*/
+	if ( !MapP )
+	{
+	    rio_dprint(RIO_DEBUG_BOOT, ("Look for RTA %x in RIOSavedTable\n",RtaUniq));
+	    for ( rta=0; rta < TOTAL_MAP_ENTRIES; rta++ )
+	    {
+		rio_dprint(RIO_DEBUG_BOOT, ("Check table entry %d (%x)",
+		      rta,
+		      p->RIOSavedTable[rta].RtaUniqueNum ));
+
+		if ( (p->RIOSavedTable[rta].Flags & SLOT_IN_USE) &&
+		 (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq) )
+		{
+		    MapP = &p->RIOSavedTable[rta];
+		    Flag = p->RIOSavedTable[rta].Flags;
+		    if (RtaType == TYPE_RTA16)
+		    {
+                        for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES;
+                         entry2++)
+                        {
+                            if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq)
+                                break;
+                        }
+                        MapP2 = &p->RIOSavedTable[entry2];
+                        rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entries %d+%d\n",
+                              rta, entry2));
+		    }
+		    else
+			rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entry %d\n", rta));
+		    break;
+		}
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** We may have found a SLOT_IN_USE entry on another host for this
+	** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry
+	** on another host for this RTA in the driver table.
+	**
+	** Check the driver table for room to fit this newly discovered RTA.
+	** RIOFindFreeID() first looks for free slots and if it does not
+	** find any free slots it will then attempt to oust any
+	** tentative entry in the table.
+	*/
+	EmptySlot = 1;
+	if (RtaType == TYPE_RTA16)
+	{
+	    if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0)
+	    {
+		RIODefaultName(p, HostP, entry);
+		FillSlot(entry, entry2, RtaUniq, HostP);
+		EmptySlot = 0;
+	    }
+	}
+	else
+	{
+	    if (RIOFindFreeID(p, HostP, &entry, NULL) == 0)
+	    {
+		RIODefaultName(p, HostP, entry);
+		FillSlot(entry, 0, RtaUniq, HostP);
+		EmptySlot = 0;
+	    }
+	}
+
+	/*
+	** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	** attached to the current host card in the driver table.
+	**
+	** If we found a SLOT_IN_USE entry on another host for this
+	** RTA in the config or driver table, and there are enough free
+	** slots in the driver table, then we need to move it over and
+	** delete it from the other host.
+	** If we found a SLOT_TENTATIVE entry on another host for this
+	** RTA in the driver table, just delete the other host entry.
+	*/
+	if (EmptySlot == 0)
+	{
+	    if ( MapP )
+	    {
+		if (Flag & SLOT_IN_USE)
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, (
+    "This RTA configured on another host - move entry to current host (1)\n"));
+		    HostP->Mapping[entry].SysPort = MapP->SysPort;
+		    CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN );
+		    HostP->Mapping[entry].Flags =
+		     SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT;
+#if NEED_TO_FIX
+		    RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		    RIOReMapPorts( p, HostP, &HostP->Mapping[entry] );
+		    if ( HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted )
+			p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort;
+		    if ( HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted )
+			p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort;
+		    rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name));
+		}
+		else
+		{
+		    rio_dprint(RIO_DEBUG_BOOT, (
+   "This RTA has a tentative entry on another host - delete that entry (1)\n"));
+		    HostP->Mapping[entry].Flags =
+		     SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT;
+#if NEED_TO_FIX
+		    RIO_SV_BROADCAST(HostP->svFlags[entry]);
+#endif
+		}
+		if (RtaType == TYPE_RTA16)
+		{
+		    if (Flag & SLOT_IN_USE)
+		    {
+			HostP->Mapping[entry2].Flags = SLOT_IN_USE |
+			 RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+			HostP->Mapping[entry2].SysPort = MapP2->SysPort;
+			/*
+			** Map second block of ttys for 16 port RTA
+			*/
+			RIOReMapPorts( p, HostP, &HostP->Mapping[entry2] );
+		       if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted)
+			 p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort;
+		       if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted)
+			 p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort;
+			rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",
+			       (int)HostP->Mapping[entry2].SysPort,
+			       HostP->Mapping[entry].Name));
+		    }
+		    else
+			HostP->Mapping[entry2].Flags = SLOT_TENTATIVE |
+			 RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+#if NEED_TO_FIX
+			RIO_SV_BROADCAST(HostP->svFlags[entry2]);
+#endif
+		    bzero( (caddr_t)MapP2, sizeof(struct Map) );
+		}
+		bzero( (caddr_t)MapP, sizeof(struct Map) );
+		if (! p->RIONoMessage)
+		    cprintf("An orphaned RTA has been adopted by %s '%s' (%c).\n",MyType,MyName,MyLink+'A');
+	    }
+	    else if (! p->RIONoMessage)
+		cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A');
+	    RIOSetChange(p);
+	    return TRUE;
+	}
+
+	/*
+	** There is no room in the driver table to make an entry for the
+	** booted RTA. Keep a note of its Uniq Num in the overflow table,
+	** so we can ignore it's ID requests.
+	*/
+	if (! p->RIONoMessage)
+	    cprintf("The RTA connected to %s '%s' (%c) cannot be configured.  You cannot configure more than 128 ports to one host card.\n",MyType,MyName,MyLink+'A');
+	for ( entry=0; entry<HostP->NumExtraBooted; entry++ )
+	{
+	    if ( HostP->ExtraUnits[entry] == RtaUniq )
+	    {
+		/*
+		** already got it!
+		*/
+		return TRUE;
+	    }
+	}
+	/*
+	** If there is room, add the unit to the list of extras
+	*/
+	if ( HostP->NumExtraBooted < MAX_EXTRA_UNITS )
+	    HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq;
+	return TRUE;
+}
+
+
+/*
+** If the RTA or its host appears in the RIOBindTab[] structure then
+** we mustn't boot the RTA and should return FALSE.
+** This operation is slightly different from the other drivers for RIO
+** in that this is designed to work with the new utilities
+** not config.rio and is FAR SIMPLER.
+** We no longer support the RIOBootMode variable. It is all done from the
+** "boot/noboot" field in the rio.cf file.
+*/
+int
+RIOBootOk(p, HostP, RtaUniq)
+struct rio_info *	p;
+struct Host *		HostP;
+ulong RtaUniq;
+{
+    int		Entry;
+    uint HostUniq = HostP->UniqueNum;
+
+	/*
+	** Search bindings table for RTA or its parent.
+	** If it exists, return 0, else 1.
+	*/
+	for (Entry = 0;
+	    ( Entry < MAX_RTA_BINDINGS ) && ( p->RIOBindTab[Entry] != 0 );
+	    Entry++)
+	{
+		if ( (p->RIOBindTab[Entry] == HostUniq) ||
+		     (p->RIOBindTab[Entry] == RtaUniq) )
+			return 0;
+	}
+	return 1;
+}
+
+/*
+** Make an empty slot tentative. If this is a 16 port RTA, make both
+** slots tentative, and the second one RTA_SECOND_SLOT as well.
+*/
+
+void
+FillSlot(entry, entry2, RtaUniq, HostP)
+int entry;
+int entry2;
+uint RtaUniq;
+struct Host *HostP;
+{
+	int		link;
+
+	rio_dprint(RIO_DEBUG_BOOT, ("FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq));
+
+	HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE);
+	HostP->Mapping[entry].SysPort = NO_PORT;
+	HostP->Mapping[entry].RtaUniqueNum = RtaUniq;
+	HostP->Mapping[entry].HostUniqueNum = HostP->UniqueNum;
+	HostP->Mapping[entry].ID = entry + 1;
+	HostP->Mapping[entry].ID2 = 0;
+	if (entry2) {
+		HostP->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | 
+								SLOT_TENTATIVE | RTA16_SECOND_SLOT);
+		HostP->Mapping[entry2].SysPort = NO_PORT;
+		HostP->Mapping[entry2].RtaUniqueNum = RtaUniq;
+		HostP->Mapping[entry2].HostUniqueNum = HostP->UniqueNum;
+		HostP->Mapping[entry2].Name[0] = '\0';
+		HostP->Mapping[entry2].ID = entry2 + 1;
+		HostP->Mapping[entry2].ID2 = entry + 1;
+		HostP->Mapping[entry].ID2 = entry2 + 1;
+	}
+	/*
+	** Must set these up, so that utilities show
+	** topology of 16 port RTAs correctly
+	*/
+	for ( link=0; link<LINKS_PER_UNIT; link++ ) {
+		HostP->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT;
+		HostP->Mapping[entry].Topology[link].Link = NO_LINK;
+		if (entry2) {
+			HostP->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT;
+			HostP->Mapping[entry2].Topology[link].Link = NO_LINK;
+		}
+	}
+}
+
+#if 0
+/*
+	Function:	This function is to disable the disk interrupt 
+    Returns :   Nothing
+*/
+void
+disable_interrupt(vector)
+int	vector;
+{
+	int	ps;
+	int	val;
+
+	disable(ps);
+	if (vector > 40)  {
+		val = 1 << (vector - 40);
+		__outb(S8259+1, __inb(S8259+1) | val);
+	}
+	else {
+		val = 1 << (vector - 32);
+		__outb(M8259+1, __inb(M8259+1) | val);
+	}
+	restore(ps);
+}
+
+/*
+	Function:	This function is to enable the disk interrupt 
+    Returns :   Nothing
+*/
+void
+enable_interrupt(vector)
+int	vector;
+{
+	int	ps;
+	int	val;
+
+	disable(ps);
+	if (vector > 40)  {
+		val = 1 << (vector - 40);
+		val = ~val;
+		__outb(S8259+1, __inb(S8259+1) & val);
+	}
+	else {
+		val = 1 << (vector - 32);
+		val = ~val;
+		__outb(M8259+1, __inb(M8259+1) & val);
+	}
+	restore(ps);
+}
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c
--- v2.3.99-pre6/linux/drivers/char/rio/riocmd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riocmd.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1144 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  ported from the existing SCO driver source
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riocmd.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:41
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riocmd.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riocmd_c_sccs_ = "@(#)riocmd.c	1.2";
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+
+
+static struct IdentifyRta IdRta;
+static struct KillNeighbour KillUnit;
+
+int
+RIOFoadRta(HostP, MapP)
+struct Host *	HostP;
+struct Map *	MapP;
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA\n"));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = IFOAD;
+	CmdBlkP->Packet.data[1]   = 0;
+	CmdBlkP->Packet.data[2]   = IFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (IFOAD_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: Failed to queue foad command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOZombieRta(HostP, MapP)
+struct Host *	HostP;
+struct Map *	MapP;
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA\n"));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = ZOMBIE;
+	CmdBlkP->Packet.data[1]   = 0;
+	CmdBlkP->Packet.data[2]   = ZOMBIE_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (ZOMBIE_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: Failed to queue zombie command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOCommandRta(p, RtaUnique, func)
+struct rio_info *	p;
+uint RtaUnique;
+int (* func)( struct Host *HostP, struct Map *MapP );
+{
+	uint Host;
+
+	rio_dprint(RIO_DEBUG_CMD, ("Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func ));
+
+	if ( !RtaUnique )
+		return(0);
+
+	for ( Host = 0; Host < p->RIONumHosts; Host++ ) {
+		uint Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if ( MapP->RtaUniqueNum == RtaUnique ) {
+				uint Link;
+
+				/*
+				** now, lets just check we have a route to it...
+				** IF the routing stuff is working, then one of the
+				** topology entries for this unit will have a legit
+				** route *somewhere*. We care not where - if its got
+				** any connections, we can get to it.
+				*/
+				for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) {
+					if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) {
+						/*
+						** Its worth trying the operation...
+						*/
+						return (*func)( HostP, MapP );
+					}
+				}
+			}
+		}
+	}
+	return ENXIO;
+}
+
+
+int
+RIOIdentifyRta(p, arg)
+struct rio_info *	p;
+caddr_t arg;
+{
+	uint Host;
+
+	if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("RIO_IDENTIFY_RTA copy failed\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		return EFAULT;
+	}
+
+	for ( Host = 0 ; Host < p->RIONumHosts; Host++ ) {
+		uint Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if ( MapP->RtaUniqueNum == IdRta.RtaUnique ) {
+				uint Link;
+				/*
+				** now, lets just check we have a route to it...
+				** IF the routing stuff is working, then one of the
+				** topology entries for this unit will have a legit
+				** route *somewhere*. We care not where - if its got
+				** any connections, we can get to it.
+				*/
+				for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) {
+					if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) {
+						/*
+						** Its worth trying the operation...
+						*/
+						struct CmdBlk *CmdBlkP;
+
+						rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA\n"));
+
+						CmdBlkP = RIOGetCmdBlk();
+
+						if ( !CmdBlkP ) {
+							rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: GetCmdBlk failed\n"));
+							return ENXIO;
+						}
+		
+						CmdBlkP->Packet.dest_unit = MapP->ID;
+						CmdBlkP->Packet.dest_port = BOOT_RUP;
+						CmdBlkP->Packet.src_unit  = 0;
+						CmdBlkP->Packet.src_port  = BOOT_RUP;
+						CmdBlkP->Packet.len	   = 0x84;
+						CmdBlkP->Packet.data[0]   = IDENTIFY;
+						CmdBlkP->Packet.data[1]   = 0;
+						CmdBlkP->Packet.data[2]   = IdRta.ID;
+		
+						if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) 
+										== RIO_FAIL ) {
+							rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: Failed to queue command\n"));
+							return EIO;
+						}
+						return 0;
+					}
+				}
+			}
+		}
+	} 
+	return ENOENT;
+}
+
+
+int
+RIOKillNeighbour(p, arg)
+struct rio_info *	p;
+caddr_t arg;
+{
+	uint Host;
+	uint ID;
+	struct Host *HostP;
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("KILL HOST NEIGHBOUR\n"));
+
+	if ( copyin( (int)arg, (caddr_t)&KillUnit, 
+					sizeof(KillUnit) ) == COPYFAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("RIO_KILL_NEIGHBOUR copy failed\n"));
+		p->RIOError.Error = COPYIN_FAILED;
+		return EFAULT;
+	}
+
+	if ( KillUnit.Link > 3 )
+		return ENXIO;
+ 
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("UFOAD: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = 0;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = UFOAD;
+	CmdBlkP->Packet.data[1]   = KillUnit.Link;
+	CmdBlkP->Packet.data[2]   = UFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (UFOAD_MAGIC >> 8) & 0xFF;
+
+	for ( Host = 0; Host < p->RIONumHosts; Host++ ) {
+		ID = 0;
+		HostP = &p->RIOHosts[Host];
+
+		if ( HostP->UniqueNum == KillUnit.UniqueNum ) {
+			if ( RIOQueueCmdBlk( HostP, RTAS_PER_HOST+KillUnit.Link,
+							CmdBlkP) == RIO_FAIL ) {
+				rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n"));
+				return EIO;
+			}
+			return 0;
+		}
+
+		for ( ID=0; ID < RTAS_PER_HOST; ID++ ) {
+			if ( HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum ) {
+				CmdBlkP->Packet.dest_unit = ID+1;
+				if ( RIOQueueCmdBlk( HostP, ID, CmdBlkP) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n"));
+					return EIO;
+				}
+				return 0;
+			}
+		}
+	}
+	RIOFreeCmdBlk( CmdBlkP );
+	return ENXIO;
+}
+
+int
+RIOSuspendBootRta(HostP, ID, Link)
+struct Host *HostP;
+int ID;
+int Link; 
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link));
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if ( !CmdBlkP ) {
+		rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: GetCmdBlk failed\n"));
+		return ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit  = 0;
+	CmdBlkP->Packet.src_port  = BOOT_RUP;
+	CmdBlkP->Packet.len	   = 0x84;
+	CmdBlkP->Packet.data[0]   = IWAIT;
+	CmdBlkP->Packet.data[1]   = Link;
+	CmdBlkP->Packet.data[2]   = IWAIT_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3]   = (IWAIT_MAGIC >> 8) & 0xFF;
+
+	if ( RIOQueueCmdBlk( HostP, ID - 1, CmdBlkP) == RIO_FAIL ) {
+		rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: Failed to queue iwait command\n"));
+		return EIO;
+	}
+	return 0;
+}
+
+int
+RIOFoadWakeup(p)
+struct rio_info *	p;
+{
+	int port;
+	register struct Port *PortP;
+	unsigned long flags;
+
+	for ( port=0; port<RIO_PORTS; port++) {
+		PortP = p->RIOPortp[port];
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->Config = 0;
+		PortP->State = 0;
+		PortP->InUse = NOT_INUSE;
+		PortP->PortState = 0;
+		PortP->FlushCmdBodge = 0;
+		PortP->ModemLines = 0;
+		PortP->ModemState = 0;
+		PortP->CookMode = 0;
+		PortP->ParamSem = 0;
+		PortP->Mapped = 0;
+		PortP->WflushFlag = 0;
+		PortP->MagicFlags = 0;
+		PortP->RxDataStart = 0;
+		PortP->TxBufferIn = 0;
+		PortP->TxBufferOut = 0;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	return(0);
+}
+
+/*
+** Incoming command on the COMMAND_RUP to be processed.
+*/
+int
+RIOCommandRup(p, Rup, HostP, PacketP)
+struct rio_info *	p;
+uint Rup;
+struct Host *HostP;
+PKT *PacketP; 
+{
+	struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+	struct Port *PortP;
+	struct UnixRup *UnixRupP;
+	ushort SysPort;
+	ushort ReportedModemStatus;
+	ushort rup;
+	ushort subCommand;
+	unsigned long flags;
+
+
+#ifdef CHECK
+	CheckHost( Host );
+	CheckHostP( HostP );
+	CheckPacketP( PacketP );
+#endif
+
+	/*
+	** 16 port RTA note:
+	** Command rup packets coming from the RTA will have pkt->data[1] (which
+	** translates to PktCmdP->PhbNum) set to the host port number for the
+	** particular unit. To access the correct BaseSysPort for a 16 port RTA,
+	** we can use PhbNum to get the rup number for the appropriate 8 port
+	** block (for the first block, this should be equal to 'Rup').
+	*/
+	rup = RBYTE(PktCmdP->PhbNum) / (ushort)PORTS_PER_RTA;
+	UnixRupP = &HostP->UnixRups[rup];
+	SysPort = UnixRupP->BaseSysPort + 
+			(RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA);
+	rio_dprint(RIO_DEBUG_CMD, ("Command on rup %d, port %d\n", rup, SysPort));
+
+#ifdef CHECK
+	CheckRup( rup );
+	CheckUnixRupP( UnixRupP );
+#endif
+	if ( UnixRupP->BaseSysPort == NO_PORT ) {
+		rio_dprint(RIO_DEBUG_CMD, ("OBSCURE ERROR!\n"));
+		rio_dprint(RIO_DEBUG_CMD, ("Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"));
+		rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Host number %d, name ``%s''\n", 
+					HostP-p->RIOHosts, HostP->Name ));
+		rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Rup number  0x%x\n", rup));
+
+		if ( Rup >= (ushort)MAX_RUP )
+			rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for RTA ``%s''\n",
+						HostP->Mapping[Rup].Name ));
+		else
+			rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", 'A' + Rup - MAX_RUP, HostP->Name ));
+
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Destination 0x%x:0x%x\n",
+					PacketP->dest_unit, PacketP->dest_port ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Source	  0x%x:0x%x\n",
+					PacketP->src_unit, PacketP->src_port ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Length	  0x%x (%d)\n", PacketP->len,PacketP->len ));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Control	 0x%x (%d)\n", PacketP->control, PacketP->control));
+		rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Check	   0x%x (%d)\n", PacketP->csum, PacketP->csum ));
+		rio_dprint(RIO_DEBUG_CMD, ("COMMAND information: Host Port Number 0x%x, 
+					Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ));
+		return TRUE;
+	}
+
+#ifdef CHECK
+	CheckSysPort( SysPort );
+#endif
+	PortP = p->RIOPortp[ SysPort ];
+#if 0
+	ttyP = PortP->TtyP;
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	switch( RBYTE(PktCmdP->Command) ) {
+		case BREAK_RECEIVED:
+			rio_dprint(RIO_DEBUG_CMD, ("Received a break!\n"));
+			/* If the current line disc. is not multi-threading and
+	   			the current processor is not the default, reset rup_intr
+	   			and return FALSE to ensure that the command packet is
+	   			not freed. */
+			/* Call tmgr HANGUP HERE */
+			/* Fix this later when every thing works !!!! RAMRAJ */
+			break;
+
+		case COMPLETE:
+			rio_dprint(RIO_DEBUG_CMD, ("Command complete on phb %d host %d\n",
+							RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts));
+			subCommand = 1;
+			switch (RBYTE(PktCmdP->SubCommand)) {
+				case MEMDUMP :
+					rio_dprint(RIO_DEBUG_CMD, ("Memory dump cmd (0x%x) from addr 0x%x\n",
+		 				RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)));
+					break;
+				case READ_REGISTER :
+					rio_dprint(RIO_DEBUG_CMD, ("Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)));
+					p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST);
+					break;
+				default :
+					subCommand = 0;
+				break;
+			}
+			if (subCommand)
+				break;
+			rio_dprint(RIO_DEBUG_CMD, ("New status is 0x%x was 0x%x\n",
+					 RBYTE(PktCmdP->PortStatus),PortP->PortState));
+			if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Mark status & wakeup\n"));
+				PortP->PortState = RBYTE(PktCmdP->PortStatus);
+				/* What should we do here ...
+				wakeup( &PortP->PortState );
+				*/
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("No change\n"));
+			}
+
+			/* FALLTHROUGH */
+		case MODEM_STATUS:
+			/*
+			** Knock out the tbusy and tstop bits, as these are not relevant
+			** to the check for modem status change (they're just there because
+			** it's a convenient place to put them!).
+			*/
+			ReportedModemStatus = RBYTE(PktCmdP->ModemStatus);
+			if ((PortP->ModemState & MSVR1_HOST) ==
+					(ReportedModemStatus & MSVR1_HOST)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Modem status unchanged 0x%x\n", PortP->ModemState));
+				/*
+				** Update ModemState just in case tbusy or tstop states have
+				** changed.
+				*/
+				PortP->ModemState = ReportedModemStatus;
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("Modem status change from 0x%x to 0x%x\n",
+							 PortP->ModemState, ReportedModemStatus));
+				PortP->ModemState = ReportedModemStatus;
+#ifdef MODEM_SUPPORT
+				if ( PortP->Mapped ) {
+				/***********************************************************\
+				*************************************************************
+				***													   ***
+				***		  M O D E M   S T A T E   C H A N G E		  ***
+				***													   ***
+				*************************************************************
+				\***********************************************************/
+				/*
+				** If the device is a modem, then check the modem
+				** carrier.
+				*/
+				if(!(ttyP->t_cflag & CLOCAL) && 
+					((PortP->State & (RIO_MOPEN|RIO_WOPEN))))
+				{
+			/*
+			** Is there a carrier?
+			*/
+			if ( PortP->ModemState & MSVR1_CD )
+			{
+			/*
+			** Has carrier just appeared?
+			*/
+			if (!(ttyP->t_state & CARR_ON))
+			{
+				rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just came up.\n");
+				ttyP->t_state |=CARR_ON;
+				/*
+				** wakeup anyone in WOPEN
+				*/
+				if ( ttyP->t_state & (ISOPEN|WOPEN) )
+				wakeup((caddr_t)&ttyP->t_canq);
+#ifdef STATS
+				PortP->Stat.ModemOnCnt++;
+#endif
+			}
+			}
+			else
+			{
+			/*
+			** Has carrier just dropped?
+			*/
+			if (ttyP->t_state & CARR_ON)
+			{
+				/*
+				** send SIGHUP to the process group
+				*/
+				if ( ttyP->t_state & (ISOPEN|WOPEN) )
+				{
+				signal(ttyP->t_pgrp,SIGHUP);
+				ttyflush(ttyP,(FREAD|FWRITE));
+				}
+				ttyP->t_state &= ~CARR_ON;
+				wakeup( (caddr_t)&PortP->TxBufferOut );
+				wakeup( (caddr_t)&PortP->TxBufferIn );
+				rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just went down.\n");
+#ifdef STATS
+				PortP->Stat.ModemOffCnt++;
+#endif
+			}
+			}
+		}
+		}
+#endif
+			}
+			break;
+
+		default:
+			rio_dprint(RIO_DEBUG_CMD, ("Unknown command %d on CMD_RUP of host %d\n",
+				RBYTE(PktCmdP->Command),HostP-p->RIOHosts));
+			break;
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return TRUE;
+}
+/*
+** The command mechanism:
+**	Each rup has a chain of commands associated with it.
+**	This chain is maintained by routines in this file.
+**	Periodically we are called and we run a quick check of all the
+**	active chains to determine if there is a command to be executed,
+**	and if the rup is ready to accept it.
+**
+*/
+
+/*
+** Allocate an empty command block.
+*/
+struct CmdBlk *
+RIOGetCmdBlk()
+{
+	struct CmdBlk *CmdBlkP;
+
+	CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk));
+	bzero(CmdBlkP, sizeof(struct CmdBlk));
+
+	return CmdBlkP;
+}
+
+/*
+** Return a block to the head of the free list.
+*/
+void
+RIOFreeCmdBlk(CmdBlkP)
+struct CmdBlk *CmdBlkP;
+{
+	sysfree((void *)CmdBlkP, sizeof(struct CmdBlk));
+}
+
+/*
+** attach a command block to the list of commands to be performed for
+** a given rup.
+*/
+int
+RIOQueueCmdBlk(HostP, Rup, CmdBlkP)
+struct Host *HostP;
+uint Rup;
+struct CmdBlk *CmdBlkP;
+{
+	struct CmdBlk **Base;
+	struct UnixRup *UnixRupP;
+	unsigned long flags;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckRup( Rup );
+	CheckCmdBlkP( CmdBlkP );
+#endif
+
+	rio_dprint(RIO_DEBUG_CMD, ("RIOQueueCmdBlk(Host, Rup %d, 0x%x)\n", Rup, (int)CmdBlkP ));
+
+	if ( Rup >= (ushort)(MAX_RUP+LINKS_PER_UNIT) ) {
+		rio_dprint(RIO_DEBUG_CMD, ("Illegal rup number %d in RIOQueueCmdBlk\n",Rup));
+		RIOFreeCmdBlk( CmdBlkP );
+		return RIO_FAIL;
+	}
+
+	UnixRupP = &HostP->UnixRups[Rup];
+
+	rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+	/*
+	** If the RUP is currently inactive, then put the request
+	** straight on the RUP....
+	*/
+	if ( (UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && 
+		(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) &&
+		(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP)
+							:TRUE)) {
+		rio_dprint(RIO_DEBUG_CMD, ("RUP inactive-placing command straight on. Cmd byte is 0x%x\n",
+					CmdBlkP->Packet.data[0]));
+
+		/*
+		** Whammy! blat that pack!
+		*/
+		HostP->Copy( (caddr_t)&CmdBlkP->Packet, 
+			RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt ), sizeof(PKT) );
+
+		/*
+		** place command packet on the pending position.
+		*/
+		UnixRupP->CmdPendingP = CmdBlkP;
+
+		/*
+		** set the command register
+		*/
+		WWORD(UnixRupP->RupP->txcontrol , TX_PACKET_READY);
+
+		rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+		return RIO_SUCCESS;
+	}
+
+	rio_dprint(RIO_DEBUG_CMD, ("RUP active - en-queing\n"));
+
+	if ( UnixRupP->CmdsWaitingP != NULL)
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command waiting\n"));
+	if ( UnixRupP->CmdPendingP != NULL )
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command pending\n"));
+	if ( RWORD(UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE )
+		rio_dprint(RIO_DEBUG_CMD, ("Rup active - command rup not ready\n"));
+
+	Base = &UnixRupP->CmdsWaitingP;
+
+	rio_dprint(RIO_DEBUG_CMD, ("First try to queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base));
+
+	while ( *Base ) {
+		rio_dprint(RIO_DEBUG_CMD, ("Command cmdblk 0x%x here\n",(int)(*Base)));
+		Base = &((*Base)->NextP);
+		rio_dprint(RIO_DEBUG_CMD, ("Now try to queue cmd cmdblk 0x%x at 0x%x\n",
+		       (int)CmdBlkP,(int)Base));
+	}
+
+	rio_dprint(RIO_DEBUG_CMD, ("Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base));
+
+	*Base = CmdBlkP;
+
+	CmdBlkP->NextP = NULL;
+
+	rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+	return RIO_SUCCESS;
+}
+
+/*
+** Here we go - if there is an empty rup, fill it!
+** must be called at splrio() or higher.
+*/
+void
+RIOPollHostCommands(p, HostP)
+struct rio_info *	p;
+struct Host *		HostP;
+{
+	register struct CmdBlk *CmdBlkP;
+	register struct UnixRup *UnixRupP;
+	struct PKT *PacketP;
+	ushort Rup;
+	unsigned long flags;
+
+
+	Rup = MAX_RUP+LINKS_PER_UNIT;
+
+	do {	/* do this loop for each RUP */
+		/*
+		** locate the rup we are processing & lock it
+		*/
+		UnixRupP = &HostP->UnixRups[--Rup];
+
+		spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+		/*
+		** First check for incoming commands:
+		*/
+		if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) {
+			int FreeMe;
+
+			/* rio_dprint(RIO_DEBUG_CMD, ("RIORupCmd( %d, %d )\n", HostP-p->RIOHosts, Rup )); */
+
+			PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt));
+
+			ShowPacket( DBG_CMD, PacketP );
+
+			switch ( RBYTE(PacketP->dest_port) ) {
+				case BOOT_RUP:
+					rio_dprint(RIO_DEBUG_CMD, ("Incoming Boot %s packet '%x'\n", 
+						RBYTE(PacketP->len) & 0x80 ? "Command":"Data", 
+						RBYTE(PacketP->data[0]) )); 
+					rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+					FreeMe= RIOBootRup(p, Rup,HostP,PacketP);
+					rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+					break;
+
+				case COMMAND_RUP:
+					/*
+					** Free the RUP lock as loss of carrier causes a
+					** ttyflush which will (eventually) call another
+					** routine that uses the RUP lock.
+					*/
+					rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+					FreeMe= RIOCommandRup(p, Rup,HostP,PacketP);
+					if (PacketP->data[5] == MEMDUMP) {
+						rio_dprint(RIO_DEBUG_CMD, ("Memdump from 0x%x complete\n",
+			 				*(ushort *) &(PacketP->data[6])));
+						HostP->Copy( (caddr_t)&(PacketP->data[8]), 
+								(caddr_t)p->RIOMemDump, 32 );
+					}
+					rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+					break;
+
+				case ROUTE_RUP:
+					rio_spin_unlock_irqrestore( &UnixRupP->RupLock, flags);
+					FreeMe = RIORouteRup(p, Rup, HostP, PacketP );
+					rio_spin_lock_irqsave( &UnixRupP->RupLock, flags );
+					break;
+
+				default:
+					rio_dprint(RIO_DEBUG_CMD, ("Unknown RUP %d\n", RBYTE(PacketP->dest_port)));
+					FreeMe = 1;
+					break;
+			}
+
+			if ( FreeMe ) {
+				rio_dprint(RIO_DEBUG_CMD, ("Free processed incoming command packet\n"));
+				put_free_end(HostP,PacketP);
+
+				WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE);
+
+				if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) {
+					rio_dprint(RIO_DEBUG_CMD, ("Handshake rup %d\n",Rup));
+					WWORD(UnixRupP->RupP->handshake,
+						PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET);
+				}
+			}
+		}
+
+		/*
+		** IF a command was running on the port, 
+		** and it has completed, then tidy it up.
+		*/
+		if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */
+			(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) {
+			/*
+			** we are idle.
+			** there is a command in pending.
+			** Therefore, this command has finished.
+			** So, wakeup whoever is waiting for it (and tell them
+			** what happened).
+			*/
+			if ( CmdBlkP->Packet.dest_port == BOOT_RUP )
+				rio_dprint(RIO_DEBUG_CMD, ("Free Boot %s Command Block '%x'\n", 
+						CmdBlkP->Packet.len & 0x80 ? "Command":"Data", 
+							CmdBlkP->Packet.data[0] ));
+
+			rio_dprint(RIO_DEBUG_CMD, ("Command 0x%x completed\n",(int)CmdBlkP));
+
+			/*
+			** Clear the Rup lock to prevent mutual exclusion.
+			*/
+			if ( CmdBlkP->PostFuncP ) {
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				(*CmdBlkP->PostFuncP) (CmdBlkP->PostArg,CmdBlkP);
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+			}
+
+			/*
+			** ....clear the pending flag....
+			*/
+			UnixRupP->CmdPendingP = NULL;
+
+			/*
+			** ....and return the command block to the freelist.
+			*/
+			RIOFreeCmdBlk( CmdBlkP );
+		}
+
+		/*
+		** If there is a command for this rup, and the rup
+		** is idle, then process the command
+		*/
+		if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */
+			(UnixRupP->CmdPendingP == NULL) &&
+				(RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) {
+			/*
+			** if the pre-function is non-zero, call it.
+			** If it returns RIO_FAIL then don't
+			** send this command yet!
+			*/
+#ifdef CHECK
+CheckCmdBlkP( CmdBlkP );
+#endif
+			if ( !(CmdBlkP->PreFuncP ?
+				(*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) {
+				rio_dprint(RIO_DEBUG_CMD, ("Not ready to start command 0x%x\n",(int)CmdBlkP));
+			}
+			else {
+				rio_dprint(RIO_DEBUG_CMD, ("Start new command 0x%x Cmd byte is 0x%x\n",
+						(int)CmdBlkP, CmdBlkP->Packet.data[0]));
+				/*
+				** Whammy! blat that pack!
+				*/
+#ifdef CHECK
+CheckPacketP( (PKT *)RIO_PTR(HostP->Caddr,UnixRupP->RupP->txpkt) );
+#endif
+				HostP->Copy( (caddr_t)&CmdBlkP->Packet, 
+					RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT));
+
+				/*
+				** remove the command from the rup command queue...
+				*/
+				UnixRupP->CmdsWaitingP = CmdBlkP->NextP;
+
+				/*
+				** ...and place it on the pending position.
+				*/
+				UnixRupP->CmdPendingP = CmdBlkP;
+
+				/*
+				** set the command register
+				*/
+				WWORD(UnixRupP->RupP->txcontrol,TX_PACKET_READY);
+
+				/*
+				** the command block will be freed
+				** when the command has been processed.
+				*/
+			}
+		}
+		spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+	} while ( Rup );
+}
+
+
+/*
+** Return the length of the named string
+*/
+int
+RIOStrlen(Str)
+register char *Str;
+{
+	register int len = 0;
+
+	while ( *Str++ )
+		len++;
+	return len;
+}
+
+/*
+** compares s1 to s2 and return 0 if they match.
+*/
+int
+RIOStrCmp(s1, s2)
+register char *s1;
+register char *s2;
+{
+	while ( *s1 && *s2 && *s1==*s2 )
+		s1++, s2++;
+	return *s1-*s2;
+}
+
+/*
+** compares s1 to s2 for upto n bytes and return 0 if they match.
+*/
+int
+RIOStrnCmp(s1, s2, n)
+register char *s1;
+register char *s2;
+int n;
+{
+	while ( n && *s1 && *s2 && *s1==*s2 )
+		n--, s1++, s2++;
+	return n ? *s1!=*s2 : 0;
+}
+
+/*
+** copy up to 'len' bytes from 'from' to 'to'.
+*/
+void
+RIOStrNCpy(to, from, len)
+char *to;
+char *from;
+int len; 
+{
+	while ( len-- && (*to++ = *from++) )
+		;
+	to[-1]='\0';
+}
+
+int
+RIOWFlushMark(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP;
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+	PortP->WflushFlag++;
+	PortP->MagicFlags |= MAGIC_FLUSH;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse( iPortP, CmdBlkP );
+}
+
+int
+RIORFlushEnable(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP; 
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	PKT *PacketP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	while ( can_remove_receive(&PacketP, PortP) ) {
+		remove_receive(PortP);
+		ShowPacket(DBG_PROC, PacketP );
+		put_free_end( PortP->HostP, PacketP );
+	}
+
+	if ( RWORD(PortP->PhbP->handshake)==PHB_HANDSHAKE_SET ) {
+		/*
+		** MAGIC! (Basically, handshake the RX buffer, so that
+		** the RTAs upstream can be re-enabled.)
+		*/
+		rio_dprint(RIO_DEBUG_CMD, ("Util: Set RX handshake bit\n"));
+		WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET);
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse( iPortP, CmdBlkP );
+}
+
+int
+RIOUnUse(iPortP, CmdBlkP)
+int iPortP;
+struct CmdBlk *CmdBlkP; 
+{
+	struct Port *	PortP = (struct Port *)iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+	rio_dprint(RIO_DEBUG_CMD, ("Decrement in use count for port\n"));
+
+	if (PortP->InUse) {
+		if ( --PortP->InUse != NOT_INUSE ) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+		}
+	}
+	/*
+	** While PortP->InUse is set (i.e. a preemptive command has been sent to
+	** the RTA and is awaiting completion), any transmit data is prevented from
+	** being transferred from the write queue into the transmit packets
+	** (add_transmit) and no furthur transmit interrupt will be sent for that
+	** data. The next interrupt will occur up to 500ms later (RIOIntr is called
+	** twice a second as a saftey measure). This was the case when kermit was
+	** used to send data into a RIO port. After each packet was sent, TCFLSH
+	** was called to flush the read queue preemptively. PortP->InUse was
+	** incremented, thereby blocking the 6 byte acknowledgement packet
+	** transmitted back. This acknowledgment hung around for 500ms before
+	** being sent, thus reducing input performance substantially!.
+	** When PortP->InUse becomes NOT_INUSE, we must ensure that any data
+	** hanging around in the transmit buffer is sent immediately.
+	*/
+	WWORD(PortP->HostP->ParmMapP->tx_intr, 1);
+	/* What to do here ..
+	wakeup( (caddr_t)&(PortP->InUse) );
+	*/
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return 0;
+}
+
+void
+ShowPacket(Flags, PacketP)
+uint Flags;
+struct PKT *PacketP; 
+{
+}
+
+/*
+** 
+** How to use this file:
+** 
+** To send a command down a rup, you need to allocate a command block, fill
+** in the packet information, fill in the command number, fill in the pre-
+** and post- functions and arguments, and then add the command block to the
+** queue of command blocks for the port in question. When the port is idle,
+** then the pre-function will be called. If this returns RIO_FAIL then the
+** command will be re-queued and tried again at a later date (probably in one
+** clock tick). If the pre-function returns NOT RIO_FAIL, then the command
+** packet will be queued on the RUP, and the txcontrol field set to the
+** command number. When the txcontrol field has changed from being the
+** command number, then the post-function will be called, with the argument
+** specified earlier, a pointer to the command block, and the value of
+** txcontrol.
+** 
+** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer
+** to the command block structure allocated, or NULL if there aren't any.
+** The block will have been zeroed for you.
+** 
+** The structure has the following fields:
+** 
+** struct CmdBlk
+** {
+**	 struct CmdBlk *NextP;		  ** Pointer to next command block   **
+**	 struct PKT	 Packet;		** A packet, to copy to the rup	**
+**			int	 (*PreFuncP)();  ** The func to call to check if OK **
+**			int	 PreArg;		** The arg for the func			**
+**			int	 (*PostFuncP)(); ** The func to call when completed **
+**			int	 PostArg;	   ** The arg for the func			**
+** };
+** 
+** You need to fill in ALL fields EXCEPT NextP, which is used to link the
+** blocks together either on the free list or on the Rup list.
+** 
+** Packet is an actual packet structure to be filled in with the packet
+** information associated with the command. You need to fill in everything,
+** as the command processore doesn't process the command packet in any way.
+** 
+** The PreFuncP is called before the packet is enqueued on the host rup.
+** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must
+** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL
+** if the packet is NOT to be queued.
+** 
+** The PostFuncP is called when the command has completed. It is called
+** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected
+** to return a value. PostFuncP does NOT need to free the command block,
+** as this happens automatically after PostFuncP returns.
+** 
+** Once the command block has been filled in, it is attached to the correct
+** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is
+** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer
+** to it!), and CmdBlkP is the pointer to the command block allocated using
+** RIOGetCmdBlk().
+** 
+*/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioctrl.c linux/drivers/char/rio/rioctrl.c
--- v2.3.99-pre6/linux/drivers/char/rio/rioctrl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioctrl.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1898 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioctrl.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:42
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioctrl.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioctrl_c_sccs_ = "@(#)rioctrl.c	1.3";
+#endif
+
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static struct LpbReq	 LpbReq;
+static struct RupReq	 RupReq;
+static struct PortReq	PortReq;
+static struct HostReq	HostReq;
+static struct HostDpRam HostDpRam;
+static struct DebugCtrl DebugCtrl;
+static struct Map		 MapEnt;
+static struct PortSetup PortSetup;
+static struct DownLoad	DownLoad;
+static struct SendPack  SendPack;
+/* static struct StreamInfo	StreamInfo; */
+/* static char modemtable[RIO_PORTS]; */
+static struct SpecialRupCmd SpecialRupCmd;
+static struct PortParams PortParams;
+static struct portStats portStats;
+
+static struct SubCmdStruct {
+	ushort	Host;
+	ushort	Rup;
+	ushort	Port;
+	ushort	Addr;
+} SubCmd;
+
+struct PortTty {
+	uint		port;
+	struct ttystatics	Tty;
+};
+
+static struct PortTty	PortTty;
+typedef struct ttystatics TERMIO;
+
+/*
+** This table is used when the config.rio downloads bin code to the
+** driver. We index the table using the product code, 0-F, and call
+** the function pointed to by the entry, passing the information
+** about the boot.
+** The RIOBootCodeUNKNOWN entry is there to politely tell the calling
+** process to bog off.
+*/
+static int 
+(*RIOBootTable[MAX_PRODUCT])(struct rio_info *, struct DownLoad *) =
+{
+/* 0 */	RIOBootCodeHOST,	/* Host Card */
+/* 1 */	RIOBootCodeRTA,		/* RTA */
+};
+
+#define drv_makedev(maj, min) ((((uint) maj & 0xff) << 8) | ((uint) min & 0xff))
+
+#ifdef linux
+int copyin (int arg, caddr_t dp, int siz)
+{
+  int rv;
+
+  rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes from user %p to %p.\n", siz, (void *) arg, dp));
+  rv = copy_from_user (dp, (void *)arg, siz);
+  if (rv < 0) return COPYFAIL;
+  else return rv;
+}
+
+
+int copyout (caddr_t dp, int arg, int siz)
+{
+  int rv;
+
+  rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes to user %p from %p.\n", siz, (void *) arg, dp));
+  rv = copy_to_user ((void *)arg, dp, siz);
+  if (rv < 0) return COPYFAIL;
+  else return rv;
+}
+
+#else
+
+int
+copyin(arg, dp, siz)
+int arg;
+caddr_t dp;
+int siz; 
+{
+	if (rbounds ((unsigned long) arg) >= siz) {
+		bcopy ( arg, dp, siz );
+		return OK;
+	} else
+		return ( COPYFAIL );
+}
+
+int
+copyout (dp, arg, siz)
+caddr_t dp;
+int arg;
+int siz;
+{
+	if (wbounds ((unsigned long) arg) >=  siz ) {
+		bcopy ( dp, arg, siz );
+		return OK;
+	} else
+		return ( COPYFAIL );
+}
+#endif
+
+int
+riocontrol(p, dev, cmd, arg, su)
+struct rio_info	* p;
+dev_t		dev;
+int		cmd;
+caddr_t		arg;
+int		su;
+{
+	uint	Host;	/* leave me unsigned! */
+	uint	port;	/* and me! */
+	struct Host	*HostP;
+	ushort	loop;
+	int		Entry;
+	struct Port	*PortP;
+	PKT	*PacketP;
+	int		retval = 0;
+	unsigned long flags;
+	
+	/* Confuse teh compiler to think that we've initialized these */
+	Host=0;
+	PortP = NULL;
+
+	rio_dprint(RIO_DEBUG_CTRL, ("control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg));
+
+	switch (cmd) {
+		/*
+		** RIO_SET_TIMER
+		**
+		** Change the value of the host card interrupt timer.
+		** If the host card number is -1 then all host cards are changed
+		** otherwise just the specified host card will be changed.
+		*/
+		case RIO_SET_TIMER:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_TIMER to %dms\n", (uint)arg));
+			{
+				int host, value;
+				host = (uint)arg >> 16;
+				value = (uint)arg & 0x0000ffff;
+				if (host == -1) {
+					for (host = 0; host < p->RIONumHosts; host++) {
+						if (p->RIOHosts[host].Flags == RC_RUNNING) {
+							WWORD(p->RIOHosts[host].ParmMapP->timer , value);
+						}
+					}
+				} else if (host >= p->RIONumHosts) {
+					return EINVAL;
+				} else {
+					if ( p->RIOHosts[host].Flags == RC_RUNNING ) {
+						WWORD(p->RIOHosts[host].ParmMapP->timer , value);
+					}
+				}
+			}
+			return 0;
+
+		case RIO_IDENTIFY_DRIVER:
+			/*
+			** 15.10.1998 ARG - ESIL 0760 part fix
+			** Added driver ident string output.
+			**
+#ifndef __THIS_RELEASE__
+#warning Driver Version string not defined !
+#endif
+			cprintf("%s %s %s %s\n",
+				RIO_DRV_STR,
+				__THIS_RELEASE__,
+				__DATE__, __TIME__ );
+
+			return 0;
+
+		case RIO_DISPLAY_HOST_CFG:
+			**
+			** 15.10.1998 ARG - ESIL 0760 part fix
+			** Added driver host card ident string output.
+			**
+			** Note that the only types currently supported
+			** are ISA and PCI. Also this driver does not
+			** (yet) distinguish between the Old PCI card
+			** and the Jet PCI card. In fact I think this
+			** driver only supports JET PCI !
+			**
+
+			for (Host = 0; Host < p->RIONumHosts; Host++)
+			{
+				HostP = &(p->RIOHosts[Host]);
+
+				switch ( HostP->Type )
+				{
+				    case RIO_AT :
+					strcpy( host_type, RIO_AT_HOST_STR );
+					break;
+
+				    case RIO_PCI :
+					strcpy( host_type, RIO_PCI_HOST_STR );
+					break;
+
+				    default :
+					strcpy( host_type, "Unknown" );
+					break;
+				}
+
+				cprintf(
+				  "RIO Host %d - Type:%s Addr:%X IRQ:%d\n",
+					Host, host_type,
+					(uint)HostP->PaddrP,
+					(int)HostP->Ivec - 32  );
+			}
+			return 0;
+			**
+			*/
+
+		case RIO_FOAD_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_FOAD_RTA\n"));
+			return RIOCommandRta(p, (uint)arg, RIOFoadRta);
+
+		case RIO_ZOMBIE_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_ZOMBIE_RTA\n"));
+			return RIOCommandRta(p, (uint)arg, RIOZombieRta);
+
+		case RIO_IDENTIFY_RTA:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_IDENTIFY_RTA\n"));
+			return RIOIdentifyRta(p, arg);
+
+		case RIO_KILL_NEIGHBOUR:
+			rio_dprint(RIO_DEBUG_CTRL, ("RIO_KILL_NEIGHBOUR\n"));
+			return RIOKillNeighbour(p, arg);
+
+		case SPECIAL_RUP_CMD:
+			{
+				struct CmdBlk *CmdBlkP;
+
+				rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD\n"));
+				if (copyin((int)arg, (caddr_t)&SpecialRupCmd, 
+							sizeof(SpecialRupCmd)) == COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD copy failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				CmdBlkP = RIOGetCmdBlk();
+				if ( !CmdBlkP ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD GetCmdBlk failed\n"));
+					return ENXIO;
+				}
+				CmdBlkP->Packet = SpecialRupCmd.Packet;
+				if ( SpecialRupCmd.Host >= p->RIONumHosts )
+					SpecialRupCmd.Host = 0;
+					rio_dprint(RIO_DEBUG_CTRL, ("Queue special rup command for host %d rup %d\n",
+						SpecialRupCmd.Host, SpecialRupCmd.RupNum));
+					if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], 
+							SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) {
+						cprintf("FAILED TO QUEUE SPECIAL RUP COMMAND\n");
+					}
+					return 0;
+				}
+
+			case RIO_DEBUG_MEM:
+#ifdef DEBUG_MEM_SUPPORT
+RIO_DEBUG_CTRL, 				if (su)
+					return rio_RIODebugMemory(RIO_DEBUG_CTRL, arg);
+				else
+#endif
+					return EPERM;
+
+			case RIO_ALL_MODEM:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_ALL_MODEM\n"));
+				p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+				return EINVAL;
+
+			case RIO_GET_TABLE:
+				/*
+				** Read the routing table from the device driver to user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE\n"));
+
+				if ((retval = RIOApel(p)) != 0)
+		 			return retval;
+
+				if (copyout((caddr_t)p->RIOConnectTable, (int)arg,
+						TOTAL_MAP_ENTRIES*sizeof(struct Map)) == COPYFAIL) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE copy failed\n"));
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+
+				{
+					int entry;
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nMAP ENTRIES\n") );
+					for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+					{
+					  if ((p->RIOConnectTable[entry].ID == 0) &&
+					      (p->RIOConnectTable[entry].HostUniqueNum == 0) &&
+					      (p->RIOConnectTable[entry].RtaUniqueNum == 0)) continue;
+					      
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+					}
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nEND MAP ENTRIES\n") );
+				}
+				p->RIOQuickCheck = NOT_CHANGED;	/* a table has been gotten */
+				return 0;
+
+			case RIO_PUT_TABLE:
+				/*
+				** Write the routing table to the device driver from user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE\n"));
+
+				if ( !su ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&p->RIOConnectTable[0], 
+					TOTAL_MAP_ENTRIES*sizeof(struct Map) ) == COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE copy failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+/*
+***********************************
+				{
+					int entry;
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nMAP ENTRIES\n") );
+					for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+					{
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Flags = 0x%x\n", entry, p->RIOConnectTable[entry].Flags ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.SysPort = 0x%x\n", entry, p->RIOConnectTable[entry].SysPort ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[3].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[4].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+					}
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nEND MAP ENTRIES\n") );
+				}
+***********************************
+*/
+				return RIONewTable(p);
+
+	 		case RIO_GET_BINDINGS :
+				/*
+				** Send bindings table, containing unique numbers of RTAs owned
+				** by this system to user space
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS\n"));
+
+				if ( !su )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyout((caddr_t) p->RIOBindTab, (int)arg, 
+						(sizeof(ulong) * MAX_RTA_BINDINGS)) == COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS copy failed\n"));
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return 0;
+
+	 		case RIO_PUT_BINDINGS :
+			/*
+			** Receive a bindings table, containing unique numbers of RTAs owned
+			** by this system
+			*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS\n"));
+
+				if ( !su )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&p->RIOBindTab[0], 
+						(sizeof(ulong) * MAX_RTA_BINDINGS))==COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS copy failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				return 0;
+
+			case RIO_BIND_RTA :
+				{
+					int	EmptySlot = -1;
+					/*
+					** Bind this RTA to host, so that it will be booted by 
+					** host in 'boot owned RTAs' mode.
+					*/
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA\n"));
+
+					if ( !su ) {
+		 				rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA !Root\n"));
+		 				p->RIOError.Error = NOT_SUPER_USER;
+		 				return EPERM;
+					}
+					for (Entry = 0; Entry < MAX_RTA_BINDINGS; Entry++) {
+		 				if ((EmptySlot == -1) && (p->RIOBindTab[Entry] == 0L))
+							EmptySlot = Entry;
+		 				else if (p->RIOBindTab[Entry] == (int) arg) {
+							/*
+							** Already exists - delete
+							*/
+							p->RIOBindTab[Entry] = 0L;
+							rio_dprint(RIO_DEBUG_CTRL, ("Removing Rta %x from p->RIOBindTab\n",
+		 												(int) arg));
+							return 0;
+		 				}
+					}
+					/*
+					** Dosen't exist - add
+					*/
+					if (EmptySlot != -1) {
+		 				p->RIOBindTab[EmptySlot] = (int) arg;
+		 				rio_dprint(RIO_DEBUG_CTRL, ("Adding Rta %x to p->RIOBindTab\n",
+		  					(int) arg));
+					}
+					else {
+		 				rio_dprint(RIO_DEBUG_CTRL, ("p->RIOBindTab full! - Rta %x not added\n",
+		  					(int) arg));
+		 				return 1;
+					}
+					return 0;
+				}
+
+			case RIO_RESUME :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME\n"));
+				port = (uint) arg;
+				if ((port < 0) || (port > 511)) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Bad port number %d\n", port));
+		 			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+		 			return EINVAL;
+				}
+				PortP = p->RIOPortp[port];
+				if (!PortP->Mapped) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not mapped\n", port));
+		 			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+		 			return EINVAL;
+				}
+				if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not open\n", port));
+		 			return EINVAL;
+				}
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == 
+										RIO_FAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME failed\n"));
+					rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					return EBUSY;
+				}
+				else {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d resumed\n", port));
+					PortP->State |= RIO_BUSY;
+				}
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return retval;
+
+			case RIO_ASSIGN_RTA:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA\n"));
+				if ( !su ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA !Root\n"));
+					p->RIOError.Error = NOT_SUPER_USER;
+					return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+									== COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				return RIOAssignRta(p, &MapEnt);
+
+			case RIO_CHANGE_NAME:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME\n"));
+				if ( !su ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME !Root\n"));
+					p->RIOError.Error = NOT_SUPER_USER;
+					return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+						== COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				return RIOChangeName(p, &MapEnt);
+
+			case RIO_DELETE_RTA:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA\n"));
+				if ( !su ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA !Root\n"));
+		 			p->RIOError.Error = NOT_SUPER_USER;
+		 			return EPERM;
+				}
+				if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt))
+							== COPYFAIL ) {
+		 			rio_dprint(RIO_DEBUG_CTRL, ("Copy from data space failed\n"));
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				return RIODeleteRta(p, &MapEnt);
+
+			case RIO_QUICK_CHECK:
+				/*
+				** 09.12.1998 ARG - ESIL 0776 part fix
+				** A customer was using this to get the RTAs
+				** connect/disconnect status.
+				** RIOConCon() had been botched use RIOHalted
+				** to keep track of RTA connections and
+				** disconnections. That has been changed and
+				** RIORtaDisCons in the rio_info struct now
+				** does the job. So we need to return the value
+				** of RIORtaCons instead of RIOHalted.
+				**
+				if (copyout((caddr_t)&p->RIOHalted,(int)arg,
+							sizeof(uint))==COPYFAIL) {
+				**
+				*/
+
+				if (copyout((caddr_t)&p->RIORtaDisCons,(int)arg,
+							sizeof(uint))==COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return 0;
+
+			case RIO_LAST_ERROR:
+				if (copyout((caddr_t)&p->RIOError, (int)arg, 
+						sizeof(struct Error)) ==COPYFAIL )
+					return EFAULT;
+				return 0;
+
+			case RIO_GET_LOG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_LOG\n"));
+#ifdef LOGGING
+				RIOGetLog(arg);
+				return 0;
+#else
+				return EINVAL;
+#endif
+
+			case RIO_GET_MODTYPE:
+				if ( copyin( (int)arg, (caddr_t)&port, 
+									sizeof(uint)) == COPYFAIL )
+				{
+		 			p->RIOError.Error = COPYIN_FAILED;
+		 			return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Get module type for port %d\n", port));
+				if ( port < 0 || port > 511 )
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Bad port number %d\n", port));
+		 			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+		 			return EINVAL;
+				}
+				PortP = (p->RIOPortp[port]);
+				if (!PortP->Mapped)
+				{
+		 			rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Port %d not mapped\n", port));
+		 			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+		 			return EINVAL;
+				}
+				/*
+				** Return module type of port
+				*/
+				port = PortP->HostP->UnixRups[PortP->RupNum].ModTypes;
+				if (copyout((caddr_t)&port, (int)arg, 
+							sizeof(uint)) == COPYFAIL) {
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return(0);
+			/*
+			** 02.03.1999 ARG - ESIL 0820 fix
+			** We are no longer using "Boot Mode", so these ioctls
+			** are not required :
+			**
+	 		case RIO_GET_BOOT_MODE :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get boot mode - %x\n", p->RIOBootMode));
+				**
+				** Return boot state of system - BOOT_ALL, BOOT_OWN or BOOT_NONE
+				**
+				if (copyout((caddr_t)&p->RIOBootMode, (int)arg, 
+						sizeof(p->RIOBootMode)) == COPYFAIL) {
+		 			p->RIOError.Error = COPYOUT_FAILED;
+		 			return EFAULT;
+				}
+				return(0);
+			
+ 			case RIO_SET_BOOT_MODE :
+				p->RIOBootMode = (uint) arg;
+				rio_dprint(RIO_DEBUG_CTRL, ("Set boot mode to 0x%x\n", p->RIOBootMode));
+				return(0);
+			**
+			** End ESIL 0820 fix
+			*/
+
+	 		case RIO_BLOCK_OPENS:
+				rio_dprint(RIO_DEBUG_CTRL, ("Opens block until booted\n"));
+				for ( Entry=0; Entry < RIO_PORTS; Entry++ ) {
+		 			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		 			p->RIOPortp[Entry]->WaitUntilBooted = 1;
+		 			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				}
+				return 0;
+			
+	 		case RIO_SETUP_PORTS:
+				rio_dprint(RIO_DEBUG_CTRL, ("Setup ports\n"));
+				if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) 
+						== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("EFAULT"));
+					 return EFAULT;
+				}
+				if ( PortSetup.From > PortSetup.To || 
+								PortSetup.To >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("ENXIO"));
+					 return ENXIO;
+				}
+				if ( PortSetup.XpCps > p->RIOConf.MaxXpCps ||
+					 PortSetup.XpCps < p->RIOConf.MinXpCps ) {
+					 p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("EINVAL"));
+					 return EINVAL;
+				}
+				if ( !p->RIOPortp ) {
+					 cprintf("No p->RIOPortp array!\n");
+					 rio_dprint(RIO_DEBUG_CTRL, ("No p->RIOPortp array!\n"));
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("entering loop (%d %d)!\n", PortSetup.From, PortSetup.To));
+				for (loop=PortSetup.From; loop<=PortSetup.To; loop++) {
+				rio_dprint(RIO_DEBUG_CTRL, ("in loop (%d)!\n", loop));
+#if 0
+					PortP = p->RIOPortp[loop];
+					if ( !PortP->TtyP )
+						PortP->TtyP = &p->channel[loop];
+
+		 				rio_spin_lock_irqsave(&PortP->portSem, flags);
+						if ( PortSetup.IxAny )
+							PortP->Config |= RIO_IXANY;
+						else
+							PortP->Config &= ~RIO_IXANY;
+						if ( PortSetup.IxOn )
+							PortP->Config |= RIO_IXON;
+						else
+							PortP->Config &= ~RIO_IXON;
+					 
+					 /*
+					 ** If the port needs to wait for all a processes output
+					 ** to drain before closing then this flag will be set.
+					 */
+					 	if (PortSetup.Drain) {
+							PortP->Config |= RIO_WAITDRAIN;
+					 	} else {
+							PortP->Config &= ~RIO_WAITDRAIN;
+					 	}
+					 /*
+					 ** Store setings if locking or unlocking port or if the
+					 ** port is not locked, when setting the store option.
+					 */
+					 if (PortP->Mapped &&
+						 ((PortSetup.Lock && !PortP->Lock) ||
+							(!PortP->Lock &&
+							(PortSetup.Store && !PortP->Store)))) {
+						PortP->StoredTty.iflag = PortP->TtyP->tm.c_iflag;
+						PortP->StoredTty.oflag = PortP->TtyP->tm.c_oflag;
+						PortP->StoredTty.cflag = PortP->TtyP->tm.c_cflag;
+						PortP->StoredTty.lflag = PortP->TtyP->tm.c_lflag;
+						PortP->StoredTty.line = PortP->TtyP->tm.c_line;
+						bcopy(PortP->TtyP->tm.c_cc, PortP->StoredTty.cc,
+					 		NCC + 5);
+					 }
+					 PortP->Lock = PortSetup.Lock;
+					 PortP->Store = PortSetup.Store;
+					 PortP->Xprint.XpCps = PortSetup.XpCps;
+					 bcopy(PortSetup.XpOn,PortP->Xprint.XpOn,MAX_XP_CTRL_LEN);
+					 bcopy(PortSetup.XpOff,PortP->Xprint.XpOff,MAX_XP_CTRL_LEN);
+					 PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+					 PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+					 PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+								RIOStrlen(PortP->Xprint.XpOff);
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+#endif
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("after loop (%d)!\n", loop));
+				rio_dprint(RIO_DEBUG_CTRL,  ("Retval:%x\n", retval ) );
+				return retval;
+
+			case RIO_GET_PORT_SETUP :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port setup\n"));
+				if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) 
+							== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( PortSetup.From >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				port = PortSetup.To = PortSetup.From;
+				PortSetup.IxAny = (p->RIOPortp[port]->Config & RIO_IXANY) ? 
+													1 : 0;
+				PortSetup.IxOn = (p->RIOPortp[port]->Config & RIO_IXON) ? 
+													1 : 0;
+				PortSetup.Drain = (p->RIOPortp[port]->Config & RIO_WAITDRAIN) ?
+												 	1 : 0;
+				PortSetup.Store = p->RIOPortp[port]->Store;
+				PortSetup.Lock = p->RIOPortp[port]->Lock;
+				PortSetup.XpCps = p->RIOPortp[port]->Xprint.XpCps;
+				bcopy(p->RIOPortp[port]->Xprint.XpOn, PortSetup.XpOn,
+													MAX_XP_CTRL_LEN);
+				bcopy(p->RIOPortp[port]->Xprint.XpOff, PortSetup.XpOff,
+													MAX_XP_CTRL_LEN);
+				PortSetup.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+				PortSetup.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+
+				if ( copyout((caddr_t)&PortSetup,(int)arg,sizeof(PortSetup))
+														==COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_GET_PORT_PARAMS :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port params\n"));
+				if (copyin( (int)arg, (caddr_t)&PortParams,
+					sizeof(struct PortParams)) == COPYFAIL) {
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				if (PortParams.Port >= RIO_PORTS) {
+					p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortParams.Port]);
+				PortParams.Config = PortP->Config;
+				PortParams.State = PortP->State;
+				rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortParams.Port));
+
+				if (copyout((caddr_t)&PortParams, (int)arg, 
+						sizeof(struct PortParams)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_GET_PORT_TTY :
+				rio_dprint(RIO_DEBUG_CTRL, ("Get port tty\n"));
+				if (copyin((int)arg, (caddr_t)&PortTty, sizeof(struct PortTty)) 
+						== COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( PortTty.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortTty.port));
+				PortP = (p->RIOPortp[PortTty.port]);
+#if 0
+				PortTty.Tty.tm.c_iflag = PortP->TtyP->tm.c_iflag;
+				PortTty.Tty.tm.c_oflag = PortP->TtyP->tm.c_oflag;
+				PortTty.Tty.tm.c_cflag = PortP->TtyP->tm.c_cflag;
+				PortTty.Tty.tm.c_lflag = PortP->TtyP->tm.c_lflag;
+#endif
+				if (copyout((caddr_t)&PortTty, (int)arg, 
+							sizeof(struct PortTty)) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return retval;
+
+			case RIO_SET_PORT_TTY :
+				if (copyin((int)arg, (caddr_t)&PortTty, 
+						sizeof(struct PortTty)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Set port %d tty\n", PortTty.port));
+				if (PortTty.port >= (ushort) RIO_PORTS) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortTty.port]);
+#if 0
+		 		rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->TtyP->tm.c_iflag = PortTty.Tty.tm.c_iflag;
+				PortP->TtyP->tm.c_oflag = PortTty.Tty.tm.c_oflag;
+				PortP->TtyP->tm.c_cflag = PortTty.Tty.tm.c_cflag;
+				PortP->TtyP->tm.c_lflag = PortTty.Tty.tm.c_lflag;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+#endif
+
+				RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP);
+				return retval;
+
+			case RIO_SET_PORT_PARAMS :
+				rio_dprint(RIO_DEBUG_CTRL, ("Set port params\n"));
+				if ( copyin((int)arg, (caddr_t)&PortParams, sizeof(PortParams))
+					== COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (PortParams.Port >= (ushort) RIO_PORTS) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[PortParams.Port]);
+		 		rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->Config = PortParams.Config;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_GET_PORT_STATS :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_PORT_STATS\n"));
+				if ( copyin((int)arg, (caddr_t)&portStats, 
+						sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( portStats.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[portStats.port]);
+				portStats.gather = PortP->statsGather;
+				portStats.txchars = PortP->txchars;
+				portStats.rxchars = PortP->rxchars;
+				portStats.opens = PortP->opens;
+				portStats.closes = PortP->closes;
+				portStats.ioctls = PortP->ioctls;
+				if ( copyout((caddr_t)&portStats, (int)arg, 
+							sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_RESET_PORT_STATS :
+				port = (uint) arg;
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESET_PORT_STATS\n"));
+				if ( port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[port]);
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->txchars	= 0;
+				PortP->rxchars	= 0;
+				PortP->opens	= 0;
+				PortP->closes	= 0;
+				PortP->ioctls	= 0;
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return retval;
+
+			case RIO_GATHER_PORT_STATS :
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_GATHER_PORT_STATS\n"));
+				if ( copyin( (int)arg, (caddr_t)&portStats, 
+						sizeof(struct portStats)) == COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( portStats.port >= RIO_PORTS ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				PortP = (p->RIOPortp[portStats.port]);
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				PortP->statsGather = portStats.gather;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+#ifdef DEBUG_SUPPORTED
+			case RIO_READ_LEVELS:
+				{
+					 int num;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_LEVELS\n"));
+					 for ( num=0; RIODbInf[num].Flag; num++ ) ;
+					 rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copy\n",num));
+					 if (copyout((caddr_t)RIODbInf,(int)arg,
+						sizeof(struct DbInf)*(num+1))==COPYFAIL) {
+						rio_dprint(RIO_DEBUG_CTRL, ("ReadLevels Copy failed\n"));
+						p->RIOError.Error = COPYOUT_FAILED;
+						return EFAULT;
+					 }
+					 rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copied\n",num));
+					 return retval;
+				}
+#endif
+
+			 case RIO_READ_CONFIG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_CONFIG\n"));
+				if (copyout((caddr_t)&p->RIOConf, (int)arg, 
+							sizeof(struct Conf)) ==COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_SET_CONFIG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_CONFIG\n"));
+				if ( !su ) {
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&p->RIOConf, sizeof(struct Conf) )
+						==COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				/*
+				** move a few value around
+				*/
+				for (Host=0; Host < p->RIONumHosts; Host++)
+					 if ( (p->RIOHosts[Host].Flags & RUN_STATE) == RC_RUNNING )
+					 	WWORD(p->RIOHosts[Host].ParmMapP->timer , 
+								p->RIOConf.Timer);
+				return retval;
+
+			case RIO_START_POLLER:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_START_POLLER\n"));
+				return EINVAL;
+
+			case RIO_STOP_POLLER:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_STOP_POLLER\n"));
+				if ( !su ) {
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				p->RIOPolling = NOT_POLLING;
+				return retval;
+
+			case RIO_SETDEBUG:
+			case RIO_GETDEBUG:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG/RIO_GETDEBUG\n"));
+				if ( copyin( (int)arg, (caddr_t)&DebugCtrl, sizeof(DebugCtrl) )
+							==COPYFAIL ) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( DebugCtrl.SysPort == NO_PORT ) {
+					if ( cmd == RIO_SETDEBUG ) {
+						if ( !su ) {
+							p->RIOError.Error = NOT_SUPER_USER;
+							return EPERM;
+						}
+						p->rio_debug = DebugCtrl.Debug;
+						p->RIODebugWait = DebugCtrl.Wait;
+						rio_dprint(RIO_DEBUG_CTRL, ("Set global debug to 0x%x set wait to 0x%x\n",
+							p->rio_debug,p->RIODebugWait));
+					}
+				 	else {
+						rio_dprint(RIO_DEBUG_CTRL, ("Get global debug 0x%x wait 0x%x\n",
+										p->rio_debug,p->RIODebugWait));
+						DebugCtrl.Debug = p->rio_debug;
+						DebugCtrl.Wait  = p->RIODebugWait;
+						if ( copyout((caddr_t)&DebugCtrl,(int)arg,
+								sizeof(DebugCtrl)) == COPYFAIL ) {
+							rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n",
+									DebugCtrl.SysPort));
+						 	p->RIOError.Error = COPYOUT_FAILED;
+						 	return EFAULT;
+						}
+					}
+				}
+				else if ( DebugCtrl.SysPort >= RIO_PORTS && 
+							DebugCtrl.SysPort != NO_PORT ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n",
+									DebugCtrl.SysPort));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				else if ( cmd == RIO_SETDEBUG ) {
+					if ( !su ) {
+						p->RIOError.Error = NOT_SUPER_USER;
+						return EPERM;
+					}
+					rio_spin_lock_irqsave(&PortP->portSem, flags);
+					p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug;
+					rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG 0x%x\n",
+								p->RIOPortp[DebugCtrl.SysPort]->Debug));
+				}
+				else {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG 0x%x\n",
+									 p->RIOPortp[DebugCtrl.SysPort]->Debug));
+					DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug;
+					if ( copyout((caddr_t)&DebugCtrl,(int)arg,
+								sizeof(DebugCtrl))==COPYFAIL ) {
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG: Bad copy to user space\n"));
+						p->RIOError.Error = COPYOUT_FAILED;
+						return EFAULT;
+					}
+				}
+				return retval;
+
+			case RIO_VERSID:
+				/*
+				** Enquire about the release and version.
+				** We return MAX_VERSION_LEN bytes, being a
+				** textual null terminated string.
+				*/
+				rio_dprint(RIO_DEBUG_CTRL,  ("RIO_VERSID\n") );
+				if ( copyout(	(caddr_t)RIOVersid(),
+						(int)arg,
+						sizeof(struct rioVersion) ) == COPYFAIL )
+				{
+					 rio_dprint(RIO_DEBUG_CTRL,  ("RIO_VERSID: Bad copy to user space (host=%d)\n",Host) );
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			/*
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			** !! commented out previous 'RIO_VERSID' functionality !!
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			**
+			case RIO_VERSID:
+				**
+				** Enquire about the release and version.
+				** We return MAX_VERSION_LEN bytes, being a textual null
+				** terminated string.
+				**
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID\n"));
+				if (copyout((caddr_t)RIOVersid(), 
+						(int)arg, MAX_VERSION_LEN ) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID: Bad copy to user space\n",Host));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+			**
+			** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+			*/
+
+			case RIO_NUM_HOSTS:
+				/*
+				** Enquire as to the number of hosts located
+				** at init time.
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS\n"));
+				if (copyout((caddr_t)&p->RIONumHosts, (int)arg, 
+							sizeof(p->RIONumHosts) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS: Bad copy to user space\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_FOAD:
+				/*
+				** Kill host. This may not be in the final version...
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD %d\n", (int)arg));
+				if ( !su ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD: Not super user\n"));
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				p->RIOHalted = 1;
+				p->RIOSystemUp = 0;
+
+				for ( Host=0; Host<p->RIONumHosts; Host++ ) {
+					 (void)RIOBoardTest( p->RIOHosts[Host].PaddrP, 
+						p->RIOHosts[Host].Caddr, p->RIOHosts[Host].Type, 
+								p->RIOHosts[Host].Slot );
+					 bzero( (caddr_t)&p->RIOHosts[Host].Flags, 
+							((int)&p->RIOHosts[Host].____end_marker____) -
+								 ((int)&p->RIOHosts[Host].Flags) );
+					 p->RIOHosts[Host].Flags  = RC_WAITING;
+#if 0
+					 RIOSetupDataStructs(p);
+#endif
+				}
+				RIOFoadWakeup(p);
+				p->RIONumBootPkts = 0;
+				p->RIOBooting = 0;
+
+#ifdef RINGBUFFER_SUPPORT
+				for( loop=0; loop<RIO_PORTS; loop++ )
+					if ( p->RIOPortp[loop]->TxRingBuffer )
+						sysfree((void *)p->RIOPortp[loop]->TxRingBuffer, 
+							RIOBufferSize );
+#endif
+#if 0
+				bzero((caddr_t)&p->RIOPortp[0],RIO_PORTS*sizeof(struct Port));
+#else
+				printk ("HEEEEELP!\n");
+#endif
+
+				for( loop=0; loop<RIO_PORTS; loop++ ) {
+#if 0
+					p->RIOPortp[loop]->TtyP = &p->channel[loop];
+#endif
+					
+					p->RIOPortp[loop]->portSem = SPIN_LOCK_UNLOCKED;
+					p->RIOPortp[loop]->InUse = NOT_INUSE;
+				}
+
+				p->RIOSystemUp = 0;
+				return retval;
+
+			case RIO_DOWNLOAD:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD\n"));
+				if ( !su ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Not super user\n"));
+					 p->RIOError.Error = NOT_SUPER_USER;
+					 return EPERM;
+				}
+				if ( copyin((int)arg, (caddr_t)&DownLoad, 
+							sizeof(DownLoad) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL,  ("Copied in download code for product code 0x%x\n",
+				    DownLoad.ProductCode ) );
+
+				/*
+				** It is important that the product code is an unsigned object!
+				*/
+				if ( DownLoad.ProductCode > MAX_PRODUCT ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Bad product code %d passed\n",
+							DownLoad.ProductCode));
+					 p->RIOError.Error = NO_SUCH_PRODUCT;
+					 return ENXIO;
+				}
+				/*
+				** do something!
+				*/
+				retval = (*(RIOBootTable[DownLoad.ProductCode]))(p, &DownLoad);
+										/* <-- Panic */
+				p->RIOHalted = 0;
+				/*
+				** and go back, content with a job well completed.
+				*/
+				return retval;
+
+			case RIO_PARMS:
+				{
+					uint host;
+
+					if (copyin((int)arg, (caddr_t)&host, 
+							sizeof(host) ) == COPYFAIL ) {
+						rio_dprint(RIO_DEBUG_CTRL, (
+							"RIO_HOST_REQ: Copy in from user space failed\n"));
+						p->RIOError.Error = COPYIN_FAILED;
+						return EFAULT;
+					}
+					/*
+					** Fetch the parmmap
+					*/
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS\n"));
+					if ( copyout( (caddr_t)p->RIOHosts[host].ParmMapP, 
+								(int)arg, sizeof(PARM_MAP) )==COPYFAIL ) {
+						p->RIOError.Error = COPYOUT_FAILED;
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS: Copy out to user space failed\n"));
+						return EFAULT;
+					}
+				}
+				return retval;
+
+			case RIO_HOST_REQ:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ\n"));
+				if (copyin((int)arg, (caddr_t)&HostReq, 
+							sizeof(HostReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( HostReq.HostNum >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Illegal host number %d\n",
+							HostReq.HostNum));
+					 return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostReq.HostNum));
+
+				if (copyout((caddr_t)&p->RIOHosts[HostReq.HostNum], 
+					(int)HostReq.HostP,sizeof(struct Host) ) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Bad copy to user space\n"));
+					return EFAULT;
+				}
+				return retval;
+
+			 case RIO_HOST_DPRAM:
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for DPRAM\n"));
+				if ( copyin( (int)arg, (caddr_t)&HostDpRam, 
+								sizeof(HostDpRam) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Copy in from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+				if ( HostDpRam.HostNum >= p->RIONumHosts ) {
+					p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Illegal host number %d\n",
+										HostDpRam.HostNum));
+					return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostDpRam.HostNum));
+
+				if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) {
+					 int off;
+					 /* It's hardware like this that really gets on my tits. */
+					 static unsigned char copy[sizeof(struct DpRam)];
+					for ( off=0; off<sizeof(struct DpRam); off++ )
+						copy[off] = p->RIOHosts[HostDpRam.HostNum].Caddr[off];
+					if ( copyout( (caddr_t)copy, (int)HostDpRam.DpRamP, 
+							sizeof(struct DpRam) ) == COPYFAIL ) {
+						p->RIOError.Error = COPYOUT_FAILED;
+						rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n"));
+						return EFAULT;
+					}
+				}
+				else if (copyout((caddr_t)p->RIOHosts[HostDpRam.HostNum].Caddr,
+					(int)HostDpRam.DpRamP, 
+						sizeof(struct DpRam) ) == COPYFAIL ) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n"));
+					 return EFAULT;
+				}
+				return retval;
+
+			 case RIO_SET_BUSY:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY\n"));
+				if ( (int)arg < 0 || (int)arg > 511 ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY: Bad port number %d\n",(int)arg));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				p->RIOPortp[(int)arg]->State |= RIO_BUSY;
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			 case RIO_HOST_PORT:
+				/*
+				** The daemon want port information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT\n"));
+				if ( copyin((int)arg, (caddr_t)&PortReq, 
+					sizeof(PortReq) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Copy in from user space failed\n"));
+					p->RIOError.Error = COPYIN_FAILED;
+					return EFAULT;
+				}
+
+				if (PortReq.SysPort >= RIO_PORTS) { /* SysPort is unsigned */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Illegal port number %d\n",
+											PortReq.SysPort));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for port %d\n", PortReq.SysPort));
+				if (copyout((caddr_t)p->RIOPortp[PortReq.SysPort], 
+							 (int)PortReq.PortP,
+								sizeof(struct Port) ) == COPYFAIL) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Bad copy to user space\n"));
+					 return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_RUP:
+				/*
+				** The daemon want rup information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP\n"));
+				if (copyin((int)arg, (caddr_t)&RupReq, 
+						sizeof(RupReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Copy in from user space failed\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (RupReq.HostNum >= p->RIONumHosts) { /* host is unsigned */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal host number %d\n",
+								RupReq.HostNum));
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+				if ( RupReq.RupNum >= MAX_RUP+LINKS_PER_UNIT ) { /* eek! */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal rup number %d\n",
+							RupReq.RupNum));
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				HostP = &p->RIOHosts[RupReq.HostNum];
+
+				if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Host %d not running\n",
+							RupReq.HostNum));
+					 p->RIOError.Error = HOST_NOT_RUNNING;
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for rup %d from host %d\n",
+						RupReq.RupNum,RupReq.HostNum));
+
+				if (copyout((caddr_t)HostP->UnixRups[RupReq.RupNum].RupP,
+					(int)RupReq.RupP,sizeof(struct RUP) ) == COPYFAIL) {
+					p->RIOError.Error = COPYOUT_FAILED;
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Bad copy to user space\n"));
+					return EFAULT;
+				}
+				return retval;
+
+			case RIO_HOST_LPB:
+				/*
+				** The daemon want lpb information
+				** (probably for debug reasons)
+				*/
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB\n"));
+				if (copyin((int)arg, (caddr_t)&LpbReq, 
+					sizeof(LpbReq) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy from user space\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if (LpbReq.Host >= p->RIONumHosts) { /* host is unsigned */
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal host number %d\n",
+							LpbReq.Host));
+					p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					return ENXIO;
+				}
+				if ( LpbReq.Link >= LINKS_PER_UNIT ) { /* eek! */
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal link number %d\n",
+							LpbReq.Link));
+					 p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				HostP = &p->RIOHosts[LpbReq.Host];
+
+				if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Host %d not running\n",
+						LpbReq.Host));
+					 p->RIOError.Error = HOST_NOT_RUNNING;
+					 return EIO;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Request for lpb %d from host %d\n",
+					LpbReq.Link, LpbReq.Host));
+
+				if (copyout((caddr_t)&HostP->LinkStrP[LpbReq.Link],
+					(int)LpbReq.LpbP,sizeof(struct LPB) ) == COPYFAIL) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy to user space\n"));
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return retval;
+
+				/*
+				** Here 3 IOCTL's that allow us to change the way in which
+				** rio logs errors. send them just to syslog or send them
+				** to both syslog and console or send them to just the console.
+				**
+				** See RioStrBuf() in util.c for the other half.
+				*/
+			case RIO_SYSLOG_ONLY:
+				p->RIOPrintLogState = PRINT_TO_LOG;	/* Just syslog */
+				return 0;
+
+			case RIO_SYSLOG_CONS:
+				p->RIOPrintLogState = PRINT_TO_LOG_CONS;/* syslog and console */
+				return 0;
+
+			case RIO_CONS_ONLY:
+				p->RIOPrintLogState = PRINT_TO_CONS;	/* Just console */
+				return 0;
+
+			case RIO_SIGNALS_ON:
+				if ( p->RIOSignalProcess ) {
+					 p->RIOError.Error = SIGNALS_ALREADY_SET;
+					 return EBUSY;
+				}
+				p->RIOSignalProcess = getpid();
+				p->RIOPrintDisabled = DONT_PRINT;
+				return retval;
+
+			case RIO_SIGNALS_OFF:
+				if ( p->RIOSignalProcess != getpid() ) {
+					 p->RIOError.Error = NOT_RECEIVING_PROCESS;
+					 return EPERM;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("Clear signal process to zero\n"));
+				p->RIOSignalProcess = 0;
+				return retval;
+
+			case RIO_SET_BYTE_MODE:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode &= ~WORD_OPERATION;
+				return retval;
+
+			case RIO_SET_WORD_MODE:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode |= WORD_OPERATION;
+				return retval;
+
+			case RIO_SET_FAST_BUS:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode |= FAST_AT_BUS;
+				return retval;
+
+			case RIO_SET_SLOW_BUS:
+				for ( Host=0; Host<p->RIONumHosts; Host++ )
+					 if ( p->RIOHosts[Host].Type == RIO_AT )
+						 p->RIOHosts[Host].Mode &= ~FAST_AT_BUS;
+				return retval;
+
+			case RIO_MAP_B50_TO_50:
+			case RIO_MAP_B50_TO_57600:
+			case RIO_MAP_B110_TO_110:
+			case RIO_MAP_B110_TO_115200:
+				rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping\n"));
+				port = (uint) arg;
+				if ( port < 0 || port > 511 ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", port));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				switch( cmd )
+				{
+					case RIO_MAP_B50_TO_50 :
+						p->RIOPortp[port]->Config |= RIO_MAP_50_TO_50;
+						break;
+					case RIO_MAP_B50_TO_57600 :
+						p->RIOPortp[port]->Config &= ~RIO_MAP_50_TO_50;
+						break;
+					case RIO_MAP_B110_TO_110 :
+						p->RIOPortp[port]->Config |= RIO_MAP_110_TO_110;
+						break;
+					case RIO_MAP_B110_TO_115200 :
+						p->RIOPortp[port]->Config &= ~RIO_MAP_110_TO_110;
+						break;
+				}
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_STREAM_INFO:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_STREAM_INFO\n"));
+				return EINVAL;
+
+			case RIO_SEND_PACKET:
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET\n"));
+				if ( copyin( (int)arg, (caddr_t)&SendPack,
+									sizeof(SendPack) )==COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET: Bad copy from user space\n"));
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				if ( SendPack.PortNum >= 128 ) {
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return ENXIO;
+				}
+
+				PortP = p->RIOPortp[SendPack.PortNum];
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if ( !can_add_transmit(&PacketP,PortP) ) {
+					 p->RIOError.Error = UNIT_IS_IN_USE;
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return ENOSPC;
+				}
+
+				for ( loop=0; loop<(ushort)(SendPack.Len & 127); loop++ )
+					 WBYTE(PacketP->data[loop], SendPack.Data[loop] );
+
+				WBYTE(PacketP->len, SendPack.Len);
+
+				add_transmit( PortP );
+				/*
+				** Count characters transmitted for port statistics reporting
+				*/
+				if (PortP->statsGather)
+					 PortP->txchars += (SendPack.Len & 127);
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				return retval;
+
+			case RIO_NO_MESG:
+				if ( su )
+					 p->RIONoMessage = 1;
+				return su ? 0 : EPERM;
+
+			case RIO_MESG:
+				if ( su )
+					p->RIONoMessage = 0;
+				return su ? 0 : EPERM;
+
+			case RIO_WHAT_MESG:
+				if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, 
+					sizeof(p->RIONoMessage) )==COPYFAIL ) {
+					rio_dprint(RIO_DEBUG_CTRL, ("RIO_WHAT_MESG: Bad copy to user space\n"));
+					p->RIOError.Error = COPYOUT_FAILED;
+					return EFAULT;
+				}
+				return 0;
+
+			case RIO_MEM_DUMP :
+				if (copyin((int)arg, (caddr_t)&SubCmd, 
+						sizeof(struct SubCmdStruct)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP host %d rup %d addr %x\n", 
+						SubCmd.Host, SubCmd.Rup, SubCmd.Addr));
+
+				if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) {
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Host >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				port = p->RIOHosts[SubCmd.Host].
+								UnixRups[SubCmd.Rup].BaseSysPort;
+
+				PortP = p->RIOPortp[port];
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if ( RIOPreemptiveCmd(p,  PortP, MEMDUMP ) == RIO_FAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP failed\n"));
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return EBUSY;
+				}
+				else
+					 PortP->State |= RIO_BUSY;
+
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				if ( copyout( (caddr_t)p->RIOMemDump, (int)arg, 
+							MEMDUMP_SIZE) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP copy failed\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+
+			case RIO_TICK:
+				if ((int)arg < 0 || (int)arg >= p->RIONumHosts)
+					 return EINVAL;
+				rio_dprint(RIO_DEBUG_CTRL, ("Set interrupt for host %d\n", (int)arg ));
+				WBYTE(p->RIOHosts[(int)arg].SetInt , 0xff);
+				return 0;
+
+			case RIO_TOCK:
+				if ((int)arg < 0 || (int)arg >= p->RIONumHosts)
+					 return EINVAL;
+				rio_dprint(RIO_DEBUG_CTRL, ("Clear interrupt for host %d\n", (int)arg ));
+				WBYTE((p->RIOHosts[(int)arg].ResetInt) , 0xff);
+				return 0;
+
+			case RIO_READ_CHECK:
+				/* Check reads for pkts with data[0] the same */
+				p->RIOReadCheck = !p->RIOReadCheck;
+				if (copyout((caddr_t)&p->RIOReadCheck,(int)arg,
+							sizeof(uint))== COPYFAIL) {
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+
+			case RIO_READ_REGISTER :
+				if (copyin((int)arg, (caddr_t)&SubCmd, 
+							sizeof(struct SubCmdStruct)) == COPYFAIL) {
+					 p->RIOError.Error = COPYIN_FAILED;
+					 return EFAULT;
+				}
+				rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER host %d rup %d port %d reg %x\n", 
+						SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr));
+
+				if (SubCmd.Port > 511) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", 
+								SubCmd.Port));
+					 p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) {
+					 p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				if (SubCmd.Host >= p->RIONumHosts ) {
+					 p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+					 return EINVAL;
+				}
+
+				port = p->RIOHosts[SubCmd.Host].
+						UnixRups[SubCmd.Rup].BaseSysPort + SubCmd.Port;
+				PortP = p->RIOPortp[port];
+
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER failed\n"));
+					 rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+					 return EBUSY;
+				}
+				else
+					 PortP->State |= RIO_BUSY;
+
+				rio_spin_unlock_irqrestore( &PortP->portSem , flags);
+				if (copyout((caddr_t)&p->CdRegister, (int)arg, 
+							sizeof(uint)) == COPYFAIL ) {
+					 rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER copy failed\n"));
+					 p->RIOError.Error = COPYOUT_FAILED;
+					 return EFAULT;
+				}
+				return 0;
+				/*
+				** rio_make_dev: given port number (0-511) ORed with port type
+				** (RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT) return dev_t
+				** value to pass to mknod to create the correct device node.
+				*/
+			case RIO_MAKE_DEV:
+				{
+					uint port = (uint)arg & RIO_MODEM_MASK;
+
+					switch ( (uint)arg & RIO_DEV_MASK ) {
+						case RIO_DEV_DIRECT:
+							arg = (caddr_t)drv_makedev(major(dev), port);
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev direct 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+					 	case RIO_DEV_MODEM:
+							arg =  (caddr_t)drv_makedev(major(dev), (port|RIO_MODEM_BIT) );
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev modem 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+						case RIO_DEV_XPRINT:
+							arg = (caddr_t)drv_makedev(major(dev), port);
+							rio_dprint(RIO_DEBUG_CTRL, ("Makedev printer 0x%x is 0x%x\n",port, (int)arg ));
+							return (int)arg;
+					}
+					rio_dprint(RIO_DEBUG_CTRL, ("MAKE Device is called\n"));
+					return EINVAL;
+				}
+				/*
+				** rio_minor: given a dev_t from a stat() call, return
+				** the port number (0-511) ORed with the port type
+				** ( RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT )
+				*/
+			case RIO_MINOR:
+				{
+					dev_t dv;
+					int mino;
+
+					dv = (dev_t)((int)arg);
+					mino = RIO_UNMODEM(dv);
+
+					if ( RIO_ISMODEM(dv) ) {
+						rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: modem %d\n", dv, mino));
+						arg = (caddr_t)(mino | RIO_DEV_MODEM);
+					}
+					else {
+						rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: direct %d\n", dv, mino));
+						arg = (caddr_t)(mino | RIO_DEV_DIRECT);
+					}
+					return (int)arg;
+				}
+	}
+	rio_dprint(RIO_DEBUG_CTRL, ("INVALID DAEMON IOCTL 0x%x\n",cmd));
+	p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+	return EINVAL;
+}
+
+/*
+** Pre-emptive commands go on RUPs and are only one byte long.
+*/
+int
+RIOPreemptiveCmd(p, PortP, Cmd)
+struct rio_info *	p;
+struct Port *PortP;
+uchar Cmd;
+{
+	struct CmdBlk *CmdBlkP;
+	struct PktCmd_M *PktCmdP;
+	int Ret;
+	ushort rup;
+	int port;
+
+#ifdef CHECK
+	CheckPortP( PortP );
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_CTRL, ("Preemptive command to deleted RTA ignored\n"));
+		return RIO_FAIL;
+	}
+
+	if (((int)((char)PortP->InUse) == -1) || ! (CmdBlkP = RIOGetCmdBlk()) ) {
+		rio_dprint(RIO_DEBUG_CTRL, ("Cannot allocate command block for command %d on port %d\n",
+		       Cmd, PortP->PortNum));
+		return RIO_FAIL;
+	}
+
+	rio_dprint(RIO_DEBUG_CTRL, ("Command blk 0x%x - InUse now %d\n", 
+	       (int)CmdBlkP,PortP->InUse));
+
+	PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0];
+
+	CmdBlkP->Packet.src_unit  = 0;
+	if (PortP->SecondBlock)
+		rup = PortP->ID2;
+	else
+		rup = PortP->RupNum;
+	CmdBlkP->Packet.dest_unit = rup;
+	CmdBlkP->Packet.src_port  = COMMAND_RUP;
+	CmdBlkP->Packet.dest_port = COMMAND_RUP;
+	CmdBlkP->Packet.len	  = PKT_CMD_BIT | 2;
+	CmdBlkP->PostFuncP	= RIOUnUse;
+	CmdBlkP->PostArg	= (int)PortP;
+	PktCmdP->Command	= Cmd;
+	port				= PortP->HostPort % (ushort)PORTS_PER_RTA;
+	/*
+	** Index ports 8-15 for 2nd block of 16 port RTA.
+	*/
+	if (PortP->SecondBlock)
+		port += (ushort) PORTS_PER_RTA;
+	PktCmdP->PhbNum	   = port;
+
+	switch ( Cmd ) {
+		case MEMDUMP:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MEMDUMP command blk 0x%x (addr 0x%x)\n",
+			       (int)CmdBlkP, (int)SubCmd.Addr));
+			PktCmdP->SubCommand		= MEMDUMP;
+			PktCmdP->SubAddr		= SubCmd.Addr;
+			break;
+		case FCLOSE:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP));
+			break;
+		case READ_REGISTER:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue READ_REGISTER (0x%x) command blk 0x%x\n",
+		 		(int)SubCmd.Addr, (int)CmdBlkP));
+			PktCmdP->SubCommand		= READ_REGISTER;
+			PktCmdP->SubAddr		= SubCmd.Addr;
+			break;
+		case RESUME:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue RESUME command blk 0x%x\n",(int)CmdBlkP));
+			break;
+		case RFLUSH:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP));
+			CmdBlkP->PostFuncP = RIORFlushEnable;
+			break;
+		case SUSPEND:
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP));
+			break;
+
+		case MGET :
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MGET command blk 0x%x\n", (int)CmdBlkP));
+			break;
+
+		case MSET :
+		case MBIC :
+		case MBIS :
+			CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
+			rio_dprint(RIO_DEBUG_CTRL, ("Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP));
+			break;
+
+		case WFLUSH:
+			/*
+			** If we have queued up the maximum number of Write flushes
+			** allowed then we should not bother sending any more to the
+			** RTA.
+			*/
+			if ((int)((char)PortP->WflushFlag) == (int)-1) {
+				rio_dprint(RIO_DEBUG_CTRL, ("Trashed WFLUSH, WflushFlag about to wrap!"));
+				RIOFreeCmdBlk(CmdBlkP);
+				return(RIO_FAIL);
+			} else {
+				rio_dprint(RIO_DEBUG_CTRL, ("Queue WFLUSH command blk 0x%x\n",
+				       (int)CmdBlkP));
+				CmdBlkP->PostFuncP = RIOWFlushMark;
+			}
+			break;
+	}
+
+	PortP->InUse++;
+
+	Ret = RIOQueueCmdBlk( PortP->HostP, rup, CmdBlkP );
+
+	return Ret;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riodrvr.h linux/drivers/char/rio/riodrvr.h
--- v2.3.99-pre6/linux/drivers/char/rio/riodrvr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riodrvr.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riodrvr.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 09:22:46
+**	Retrieved	: 11/6/98 09:22:46
+**
+**  ident @(#)riodrvr.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __riodrvr_h
+#define __riodrvr_h
+
+#ifdef SCCS_LABELS
+static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h	1.3";
+#endif
+
+#define MEMDUMP_SIZE	32
+#define HZ				100
+#define	MOD_DISABLE	(RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
+
+
+struct rio_info {
+	int			mode;			/* Intr or polled, word/byte */
+	spinlock_t		RIOIntrSem;		/* Interrupt thread sem */
+	int			current_chan;		/* current channel */
+	int			RIOFailed;		/* Not initialised ? */
+	int			RIOInstallAttempts;	/* no. of rio-install() calls */
+	int			RIOLastPCISearch;	/* status of last search */
+	int			RIONumHosts;		/* Number of RIO Hosts */
+	struct Host		* RIOHosts;		/* RIO Host values */
+	struct Port		**RIOPortp;		/* RIO port values */
+/*
+** 02.03.1999 ARG - ESIL 0820 fix
+** We no longer use RIOBootMode
+**
+	int			RIOBootMode;		* RIO boot mode *
+**
+*/
+	int			RIOPrintDisabled;	/* RIO printing disabled ? */
+	int			RIOPrintLogState;	/* RIO printing state ? */
+	int			RIOPolling;		/* Polling ? */
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** The 'RIO_QUICK_CHECK' ioctl was using RIOHalted.
+** The fix for this ESIL introduces another member (RIORtaDisCons) here to be
+** updated in RIOConCon() - to keep track of RTA connections/disconnections.
+** 'RIO_QUICK_CHECK' now returns the value of RIORtaDisCons.
+*/
+	int			RIOHalted;		/* halted ? */
+	int			RIORtaDisCons;		/* RTA connections/disconnections */
+	uint			RIOReadCheck;		/* Rio read check */
+	uint			RIONoMessage;		/* To display message or not */
+	uint			RIONumBootPkts;		/* how many packets for an RTA */
+	uint			RIOBootCount; 		/* size of RTA code */
+	uint			RIOBooting;		/* count of outstanding boots */
+	uint			RIOSystemUp;		/* Booted ?? */
+	uint			RIOCounting;		/* for counting interrupts */
+	uint			RIOIntCount;		/* # of intr since last check */
+	uint			RIOTxCount;		/* number of xmit intrs  */
+	uint			RIORxCount;		/* number of rx intrs */
+	uint			RIORupCount;		/* number of rup intrs */
+	int			RIXTimer; 
+	int			RIOBufferSize;		/* Buffersize */
+	int			RIOBufferMask;		/* Buffersize */
+
+	int			RIOFirstMajor;		/* First host card's major no */
+
+	uint			RIOLastPortsMapped;	/* highest port number known */
+	uint			RIOFirstPortsMapped;	/* lowest port number known */
+
+	uint			RIOLastPortsBooted;	/* highest port number running */
+	uint			RIOFirstPortsBooted;	/* lowest port number running */
+
+	uint			RIOLastPortsOpened;	/* highest port number running */
+	uint			RIOFirstPortsOpened;	/* lowest port number running */
+
+	/* Flag to say that the topology information has been changed. */
+	uint			RIOQuickCheck; 
+	uint			CdRegister;		/* ??? */
+	int			RIOSignalProcess;	/* Signalling process */
+	int			rio_debug;		/* To debug ... */
+	int			RIODebugWait;		/* For what ??? */
+	int			tpri;			/* Thread prio */
+	int			tid;			/* Thread id */
+	uint			_RIO_Polled;		/* Counter for polling */
+	uint			_RIO_Interrupted;	/* Counter for interrupt */
+	int			intr_tid;		/* iointset return value */
+	int			TxEnSem;		/* TxEnable Semaphore */
+
+
+	struct Error		RIOError;		/* to Identify what went wrong */ 
+	struct Conf		RIOConf;		/* Configuration ??? */
+	struct ttystatics	channel[RIO_PORTS];	/* channel information */
+	char			RIOBootPackets[1+(SIXTY_FOUR_K/RTA_BOOT_DATA_SIZE)]
+								[RTA_BOOT_DATA_SIZE];
+	struct Map		RIOConnectTable[TOTAL_MAP_ENTRIES];
+	struct Map		RIOSavedTable[TOTAL_MAP_ENTRIES];
+
+	/* RTA to host binding table for master/slave operation */
+	ulong			RIOBindTab[MAX_RTA_BINDINGS];
+	/* RTA memory dump variable */
+	uchar			RIOMemDump[MEMDUMP_SIZE]; 
+	struct ModuleInfo 	RIOModuleTypes[MAX_MODULE_TYPES];
+
+};
+
+
+#ifdef linux
+#define debug(x)        printk x
+#else
+#define debug(x)	kkprintf x
+#endif
+
+
+
+#define RIO_RESET_INT	0x7d80
+#define WRBYTE(x,y)		*(volatile unsigned char *)((x)) = \
+					(unsigned char)(y)
+
+#endif	/* __riodrvr.h */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioinfo.h linux/drivers/char/rio/rioinfo.h
--- v2.3.99-pre6/linux/drivers/char/rio/rioinfo.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioinfo.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,96 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioinfo.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 14:07:49
+**	Retrieved	: 11/6/98 14:07:50
+**
+**  ident @(#)rioinfo.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rioinfo_h
+#define __rioinfo_h
+
+#ifdef SCCS_LABELS
+static char *_rioinfo_h_sccs_ = "@(#)rioinfo.h	1.2";
+#endif
+
+/*
+** Host card data structure
+*/
+struct RioHostInfo {
+	long	location;	/* RIO Card Base I/O address */
+	long	vector;		/* RIO Card IRQ vector */
+	int	bus;		/* ISA/EISA/MCA/PCI */
+	int	mode;		/* pointer to host mode - INTERUPT / POLLED */
+	struct old_sgttyb
+		* Sg;		/* pointer to default term characteristics */
+};
+
+
+/* Mode in rio device info */
+#define INTERRUPTED_MODE	0x01		/* Interrupt is generated */
+#define POLLED_MODE		0x02		/* No interrupt */
+#define AUTO_MODE		0x03		/* Auto mode */
+
+#define WORD_ACCESS_MODE	0x10		/* Word Access Mode */
+#define BYTE_ACCESS_MODE	0x20		/* Byte Access Mode */
+
+
+/* Bus type that RIO supports */
+#define ISA_BUS			0x01		/* The card is ISA */
+#define EISA_BUS		0x02		/* The card is EISA */
+#define MCA_BUS			0x04		/* The card is MCA */
+#define PCI_BUS			0x08		/* The card is PCI */
+
+/*
+** 11.11.1998 ARG - ESIL ???? part fix
+** Moved definition for 'CHAN' here from rioinfo.c (it is now
+** called 'DEF_TERM_CHARACTERISTICS').
+*/
+
+#define DEF_TERM_CHARACTERISTICS \
+{ \
+	B19200, B19200,				/* input and output speed */ \
+	'H' - '@',				/* erase char */ \
+	-1,					/* 2nd erase char */ \
+	'U' - '@',				/* kill char */ \
+	ECHO | CRMOD,				/* mode */ \
+	'C' - '@',				/* interrupt character */ \
+	'\\' - '@',				/* quit char */ \
+	'Q' - '@',				/* start char */ \
+	'S' - '@',				/* stop char */ \
+	'D' - '@',				/* EOF */ \
+	-1,					/* brk */ \
+	(LCRTBS | LCRTERA | LCRTKIL | LCTLECH),	/* local mode word */ \
+	'Z' - '@',				/* process stop */ \
+	'Y' - '@',				/* delayed stop */ \
+	'R' - '@',				/* reprint line */ \
+	'O' - '@',				/* flush output */ \
+	'W' - '@',				/* word erase */ \
+	'V' - '@'				/* literal next char */ \
+}
+
+#endif /* __rioinfo_h */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c
--- v2.3.99-pre6/linux/drivers/char/rio/rioinit.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioinit.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1652 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioinit.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:43
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioinit.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioinit_c_sccs_ = "@(#)rioinit.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+#undef bcopy
+#define bcopy rio_pcicopy
+
+int
+RIOPCIinit(struct rio_info *p, int Mode);
+
+
+#if 0
+extern int	rio_intr();
+
+/*
+**	Init time code.
+*/
+void
+rioinit( p, info )
+struct rio_info		* p;
+struct RioHostInfo	* info;
+{
+	/*
+	** Multi-Host card support - taking the easy way out - sorry !
+	** We allocate and set up the Host and Port structs when the
+	** driver is called to 'install' the first host.
+	** We check for this first 'call' by testing the RIOPortp pointer.
+	*/
+	if ( !p->RIOPortp )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("Allocating and setting up driver data structures\n") );
+
+		RIOAllocDataStructs(p);		/* allocate host/port structs */
+		RIOSetupDataStructs(p);		/* setup topology structs */
+	}
+
+	RIOInitHosts( p, info );	/* hunt down the hardware */
+
+	RIOAllocateInterrupts(p);	/* allocate interrupts */
+	RIOReport(p);			/* show what we found */
+}
+
+/*
+** Initialise the Cards 
+*/ 
+void
+RIOInitHosts(p, info)
+struct rio_info		* p;
+struct RioHostInfo	* info;
+{
+/*
+** 15.10.1998 ARG - ESIL 0762 part fix
+** If there is no ISA card definition - we always look for PCI cards.
+** As we currently only support one host card this lets an ISA card
+** definition take precedence over PLUG and PLAY.
+** No ISA card - we are PLUG and PLAY with PCI.
+*/
+
+	/*
+	** Note - for PCI both these will be zero, that's okay because
+	** RIOPCIInit() fills them in if a card is found.
+	*/
+	p->RIOHosts[p->RIONumHosts].Ivec	= info->vector;
+	p->RIOHosts[p->RIONumHosts].PaddrP	= info->location;
+
+	/*
+	** Check that we are able to accomodate another host
+	*/
+	if ( p->RIONumHosts >= RIO_HOSTS )
+	{
+		p->RIOFailed++;
+		return;
+	}
+
+	if ( info->bus & ISA_BUS )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("initialising card %d (ISA)\n", p->RIONumHosts) );
+		RIOISAinit(p, p->mode);
+	}
+	else
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("initialising card %d (PCI)\n", p->RIONumHosts) );
+		RIOPCIinit(p, RIO_PCI_DEFAULT_MODE);
+	}
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Total hosts initialised so far : %d\n", p->RIONumHosts) );
+
+
+#ifdef FUTURE_RELEASE
+	if (p->bus & EISA_BUS)
+		/* EISA card */
+		RIOEISAinit(p, RIO_EISA_DEFAULT_MODE);
+
+	if (p->bus & MCA_BUS)
+		/* MCA card */
+		RIOMCAinit(p, RIO_MCA_DEFAULT_MODE);
+#endif
+}
+
+/*
+** go through memory for an AT host that we pass in the device info
+** structure and initialise
+*/
+void
+RIOISAinit(p, mode)
+struct rio_info *	p;
+int					mode;
+{
+
+  /* XXX Need to implement this. */
+#if 0
+	p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec,
+					(int (*)())rio_intr, (char*)p->RIONumHosts);
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ) );
+
+	if (RIODoAT(p, p->RIOHosts[p->RIONumHosts].PaddrP, mode)) {
+		return;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_INIT, ("RIODoAT failed\n"));
+		p->RIOFailed++;
+	}
+#endif
+
+}
+
+/*
+** RIODoAT :
+**
+** Map in a boards physical address, check that the board is there,
+** test the board and if everything is okay assign the board an entry
+** in the Rio Hosts structure.
+*/
+int
+RIODoAT(p, Base, mode)
+struct rio_info *	p;
+int		Base;
+int		mode;
+{
+#define	FOUND		1
+#define NOT_FOUND	0
+
+	caddr_t		cardAddr;
+
+	/*
+	** Check to see if we actually have a board at this physical address.
+	*/
+	if ((cardAddr = RIOCheckForATCard(Base)) != 0) {
+		/*
+		** Now test the board to see if it is working.
+		*/
+		if (RIOBoardTest(Base, cardAddr, RIO_AT, 0) == RIO_SUCCESS) {
+			/*
+			** Fill out a slot in the Rio host structure.
+			*/
+			if (RIOAssignAT(p, Base, cardAddr, mode)) {
+				return(FOUND);
+			}
+		}
+		RIOMapout(Base, RIO_AT_MEM_SIZE, cardAddr);
+	}
+	return(NOT_FOUND);
+}
+
+caddr_t
+RIOCheckForATCard(Base)
+int		Base;
+{
+	int				off;
+	struct DpRam	*cardp;		/* (Points at the host) */
+	caddr_t			virtAddr;
+	unsigned char			RIOSigTab[24];
+/*
+** Table of values to search for as prom signature of a host card
+*/
+	strcpy(RIOSigTab, "JBJGPGGHINSMJPJR");
+
+	/*
+	** Hey! Yes, You reading this code! Yo, grab a load a this:
+	**
+	** IF the card is using WORD MODE rather than BYTE MODE
+	** then it will occupy 128K of PHYSICAL memory area. So,
+	** you might think that the following Mapin is wrong. Well,
+	** it isn't, because the SECOND 64K of occupied space is an
+	** EXACT COPY of the FIRST 64K. (good?), so, we need only
+	** map it in in one 64K block.
+	*/
+	if (RIOMapin(Base, RIO_AT_MEM_SIZE, &virtAddr) == -1) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't map the board in!\n"));
+		return((caddr_t)0);
+	}
+
+	/*
+	** virtAddr points to the DP ram of the system.
+	** We now cast this to a pointer to a RIO Host,
+	** and have a rummage about in the PROM.
+	*/
+	cardp = (struct DpRam *)virtAddr;
+
+	for (off=0; RIOSigTab[off]; off++) {
+		if ((RBYTE(cardp->DpSignature[off]) & 0xFF) != RIOSigTab[off]) {
+			/*
+			** Signature mismatch - card not at this address
+			*/
+			RIOMapout(Base, RIO_AT_MEM_SIZE, virtAddr);
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't match the signature 0x%x 0x%x!\n",
+						(int)cardp, off));
+			return((caddr_t)0);
+		}
+	}
+
+	/*
+	** If we get here then we must have found a valid board so return
+	** its virtual address.
+	*/
+	return(virtAddr);
+}
+#endif
+
+/**
+** RIOAssignAT :
+**
+** Fill out the fields in the p->RIOHosts structure now we know we know
+** we have a board present.
+**
+** bits < 0 indicates 8 bit operation requested,
+** bits > 0 indicates 16 bit operation.
+*/
+int
+RIOAssignAT(p, Base, virtAddr, mode)
+struct rio_info *	p;
+int		Base;
+caddr_t	virtAddr;
+int		mode;
+{
+	int		bits;
+	struct DpRam *cardp = (struct DpRam *)virtAddr;
+
+	if ((Base < ONE_MEG) || (mode & BYTE_ACCESS_MODE))
+		bits = BYTE_OPERATION;
+	else
+		bits = WORD_OPERATION;
+
+	/*
+	** Board has passed its scrub test. Fill in all the
+	** transient stuff.
+	*/
+	p->RIOHosts[p->RIONumHosts].Caddr	= virtAddr;
+	p->RIOHosts[p->RIONumHosts].CardP	= (struct DpRam *)virtAddr;
+
+	/*
+	** Revision 01 AT host cards don't support WORD operations,
+	*/
+	if ( RBYTE(cardp->DpRevision) == 01 )
+		bits = BYTE_OPERATION;
+
+	p->RIOHosts[p->RIONumHosts].Type = RIO_AT;
+	p->RIOHosts[p->RIONumHosts].Copy = bcopy;
+											/* set this later */
+	p->RIOHosts[p->RIONumHosts].Slot = -1;
+	p->RIOHosts[p->RIONumHosts].Mode = SLOW_LINKS | SLOW_AT_BUS | bits;
+	WBYTE(p->RIOHosts[p->RIONumHosts].Control, 
+			BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+			p->RIOHosts[p->RIONumHosts].Mode | 
+			INTERRUPT_DISABLE );
+	WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+	WBYTE(p->RIOHosts[p->RIONumHosts].Control,
+			BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+			p->RIOHosts[p->RIONumHosts].Mode |
+			INTERRUPT_DISABLE );
+	WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+	p->RIOHosts[p->RIONumHosts].UniqueNum =
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+		((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum));
+
+	p->RIONumHosts++;
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Tests Passed at 0x%x\n", Base));
+	return(1);
+}
+#if 0
+#ifdef FUTURE_RELEASE
+int RIOMCAinit(int Mode)
+{
+	uchar SlotNumber;
+	caddr_t Caddr;
+	uint	Paddr;
+	uint	Ivec;
+	int	 Handle;
+	int	 ret = 0;
+
+	/*
+	** Valid mode information for MCA cards
+	** is only FAST LINKS
+	*/
+	Mode = (Mode & FAST_LINKS) ? McaTpFastLinks : McaTpSlowLinks;
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOMCAinit(%d)\n",Mode);
+
+
+	/*
+	** Check out each of the slots
+	*/
+	for (SlotNumber = 0; SlotNumber < McaMaxSlots; SlotNumber++) {
+	/*
+	** Enable the slot we want to talk to
+	*/
+	outb( McaSlotSelect, SlotNumber | McaSlotEnable );
+
+	/*
+	** Read the ID word from the slot
+	*/
+	if (((inb(McaIdHigh)<< 8)|inb(McaIdLow)) == McaRIOId)
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Potential MCA card in slot %d\n",SlotNumber);
+
+		/*
+		** Card appears to be a RIO MCA card!
+		*/
+		RIOMachineType |= (1<<RIO_MCA);
+
+		/*
+		** Just check we haven't found too many wonderful objects
+		*/
+		if ( RIONumHosts >= RIO_HOSTS )
+		{
+		Rprintf(RIOMesgTooManyCards);
+		return(ret);
+		}
+
+		/*
+		** McaIrqEnable contains the interrupt vector, and a card
+		** enable bit.
+		*/
+		Ivec = inb(McaIrqEnable);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Ivec is %x\n",Ivec);
+
+		switch ( Ivec & McaIrqMask )
+		{
+		case McaIrq9:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ9\n");
+		break;
+		case McaIrq3:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ3\n");
+		break;
+		case McaIrq4:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ4\n");
+		break;
+		case McaIrq7:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ7\n");
+		break;
+		case McaIrq10:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ10\n");
+		break;
+		case McaIrq11:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ11\n");
+		break;
+		case McaIrq12:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ12\n");
+		break;
+		case McaIrq15:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ15\n");
+		break;
+		}
+
+		/*
+		** If the card enable bit isn't set, then set it!
+		*/
+		if ((Ivec & McaCardEnable) != McaCardEnable )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable not set - setting!\n");
+		outb(McaIrqEnable,Ivec|McaCardEnable);
+		}
+		else
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable already set\n");
+		}
+
+		/*
+		** Convert the IRQ enable mask into something useful
+		*/
+		Ivec = RIOMcaToIvec[Ivec & McaIrqMask];
+
+		/*
+		** Find the physical address
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"inb(McaMemory) is %x\n",inb(McaMemory));
+		Paddr = McaAddress(inb(McaMemory));
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"MCA card has Ivec %d Addr %x\n",Ivec,Paddr);
+
+		if ( Paddr != 0 )
+		{
+
+		/*
+		** Tell the memory mapper that we want to talk to it
+		*/
+		Handle = RIOMapin( Paddr, RIO_MCA_MEM_SIZE, &Caddr );
+
+		if ( Handle == -1 ) {
+			rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE,Paddr);
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr);
+
+		/*
+		** And check that it is actually there!
+		*/
+		if ( RIOBoardTest( Paddr,Caddr,RIO_MCA,SlotNumber ) == RIO_SUCCESS )
+		{
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board has passed test\n");
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,
+	"Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n",
+			SlotNumber,RIO_MCA,Paddr,Caddr,Mode);
+
+			/*
+			** Board has passed its scrub test. Fill in all the
+			** transient stuff.
+			*/
+			p->RIOHosts[RIONumHosts].Slot	 = SlotNumber;
+			p->RIOHosts[RIONumHosts].Ivec	 = Ivec;
+			p->RIOHosts[RIONumHosts].Type	 = RIO_MCA;
+			p->RIOHosts[RIONumHosts].Copy	 = bcopy;
+			p->RIOHosts[RIONumHosts].PaddrP   = Paddr;
+			p->RIOHosts[RIONumHosts].Caddr	= Caddr;
+			p->RIOHosts[RIONumHosts].CardP	= (struct DpRam *)Caddr;
+			p->RIOHosts[RIONumHosts].Mode	 = Mode;
+			WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt , 0xff);
+			p->RIOHosts[RIONumHosts].UniqueNum =
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)|
+						((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24);
+			RIONumHosts++;
+			ret++;
+		}
+		else
+		{
+			/*
+			** It failed the test, so ignore it.
+			*/
+			rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n");
+			RIOMapout(Paddr, RIO_MCA_MEM_SIZE, Caddr );
+		}
+		}
+		else
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d - Paddr zero!\n",SlotNumber);
+		}
+	}
+	else
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber);
+	}
+	}
+	/*
+	** Now we have checked all the slots, turn off the MCA slot selector
+	*/
+	outb(McaSlotSelect,0);
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber);
+	return ret;
+}
+
+int RIOEISAinit( int Mode )
+{
+	static int EISADone = 0;
+	uint Paddr;
+	int PollIntMixMsgDone = 0;
+	caddr_t Caddr;
+	ushort Ident;
+	uchar EisaSlot;
+	uchar Ivec;
+	int ret = 0;
+
+	/*
+	** The only valid mode information for EISA hosts is fast or slow
+	** links.
+	*/
+	Mode = (Mode & FAST_LINKS) ? EISA_TP_FAST_LINKS : EISA_TP_SLOW_LINKS;
+
+	if ( EISADone )
+	{
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit() - already done, return.\n");
+		return(0);
+	}
+
+	EISADone++;
+
+	rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit()\n");
+
+
+	/*
+	** First check all cards to see if ANY are set for polled mode operation.
+	** If so, set ALL to polled.
+	*/
+
+	for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ )
+	{
+	Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) |
+		 INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO);
+
+	/* rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, "Check EISA slot %d, ID=%x\n",EisaSlot,Ident); */
+
+	if ( Ident == RIO_EISA_IDENT )
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Found Specialix product\n");
+
+		if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Not Specialix RIO - Product number %x\n",
+						INBZ(EisaSlot,EISA_PRODUCT_NUMBER));
+		continue;  /* next slot */
+		}
+		/*
+		** Its a Specialix RIO!
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIO Revision %d\n",
+					INBZ(EisaSlot,EISA_REVISION_NUMBER));
+		
+		RIOMachineType |= (1<<RIO_EISA);
+
+		/*
+		** Just check we haven't found too many wonderful objects
+		*/
+		if ( RIONumHosts >= RIO_HOSTS )
+		{
+		Rprintf(RIOMesgTooManyCards);
+		return 0;
+		}
+
+		/*
+		** Ensure that the enable bit is set!
+		*/
+		OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT );
+
+		/*
+		** EISA_INTERRUPT_VEC contains the interrupt vector.
+		*/
+		Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC);
+
+#ifdef RIODEBUG
+		switch ( Ivec & EISA_INTERRUPT_MASK )
+		{
+		case EISA_IRQ_3:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 3\n");
+		break;
+		case EISA_IRQ_4:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 4\n");
+		break;
+		case EISA_IRQ_5:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 5\n");
+		break;
+		case EISA_IRQ_6:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 6\n");
+		break;
+		case EISA_IRQ_7:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 7\n");
+		break;
+		case EISA_IRQ_9:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 9\n");
+		break;
+		case EISA_IRQ_10:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 10\n");
+		break;
+		case EISA_IRQ_11:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 11\n");
+		break;
+		case EISA_IRQ_12:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 12\n");
+		break;
+		case EISA_IRQ_14:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 14\n");
+		break;
+		case EISA_IRQ_15:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 15\n");
+		break;
+		case EISA_POLLED:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA POLLED\n");
+		break;
+		default:
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT|DBG_FAIL,"Shagged interrupt number!\n");
+		Ivec &= EISA_CONTROL_MASK;
+		}
+#endif
+
+		if ( (Ivec & EISA_INTERRUPT_MASK) ==
+		 EISA_POLLED )
+		{
+		RIOWillPoll = 1;
+		break;		/* From EisaSlot loop */
+		}
+	}
+	}
+
+	/*
+	** Do it all again now we know whether to change all cards to polled
+	** mode or not
+	*/
+
+	for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ )
+	{
+	Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) |
+		 INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO);
+
+	if ( Ident == RIO_EISA_IDENT )
+	{
+		if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE )
+		continue;  /* next slot */
+
+		/*
+		** Its a Specialix RIO!
+		*/
+		
+		/*
+		** Ensure that the enable bit is set!
+		*/
+		OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT );
+
+		/*
+		** EISA_INTERRUPT_VEC contains the interrupt vector.
+		*/
+		Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC);
+
+		if ( RIOWillPoll )
+		{
+			/*
+			** If we are going to operate in polled mode, but this
+			** board is configured to be interrupt driven, display
+			** the message explaining the situation to the punter,
+			** assuming we haven't already done so.
+			*/
+
+			if ( !PollIntMixMsgDone &&
+			 (Ivec & EISA_INTERRUPT_MASK) != EISA_POLLED )
+			{
+			Rprintf(RIOMesgAllPolled);
+			PollIntMixMsgDone = 1;
+			}
+
+			/*
+			** Ungraciously ignore whatever the board reports as its
+			** interrupt vector...
+			*/
+
+			Ivec &= ~EISA_INTERRUPT_MASK;
+
+			/*
+			** ...and force it to dance to the poll tune.
+			*/
+
+			Ivec |= EISA_POLLED;
+		}
+
+		/*
+		** Convert the IRQ enable mask into something useful (0-15)
+		*/
+		Ivec = RIOEisaToIvec(Ivec);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT, "EISA host in slot %d has Ivec 0x%x\n",
+		 EisaSlot, Ivec);
+
+		/*
+		** Find the physical address
+		*/
+		Paddr = (INBZ(EisaSlot,EISA_MEMORY_BASE_HI)<<24) |
+				(INBZ(EisaSlot,EISA_MEMORY_BASE_LO)<<16);
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"EISA card has Ivec %d Addr %x\n",Ivec,Paddr);
+
+		if ( Paddr == 0 )
+		{
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT | DBG_FAIL,
+		 "Board in slot %d configured for address zero!\n", EisaSlot);
+		continue;
+		}
+
+		/*
+		** Tell the memory mapper that we want to talk to it
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"About to map EISA card \n");
+
+		if (RIOMapin( Paddr, RIO_EISA_MEM_SIZE, &Caddr) == -1) {
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"Couldn't map %d bytes at %x\n",
+							RIO_EISA_MEM_SIZE,Paddr);
+		continue;
+		}
+
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr);
+
+		/*
+		** And check that it is actually there!
+		*/
+		if ( RIOBoardTest( Paddr,Caddr,RIO_EISA,EisaSlot) == RIO_SUCCESS )
+			{
+		rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board has passed test\n");
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,
+		"Slot %d. Ivec %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n",
+			EisaSlot,Ivec,RIO_EISA,Paddr,Caddr,Mode);
+
+		/*
+		** Board has passed its scrub test. Fill in all the
+		** transient stuff.
+		*/
+		p->RIOHosts[RIONumHosts].Slot	 = EisaSlot;
+		p->RIOHosts[RIONumHosts].Ivec	 = Ivec;
+		p->RIOHosts[RIONumHosts].Type	 = RIO_EISA;
+		p->RIOHosts[RIONumHosts].Copy	 = bcopy;
+				p->RIOHosts[RIONumHosts].PaddrP   = Paddr;
+				p->RIOHosts[RIONumHosts].Caddr	= Caddr;
+		p->RIOHosts[RIONumHosts].CardP	= (struct DpRam *)Caddr;
+				p->RIOHosts[RIONumHosts].Mode	 = Mode;
+		/*
+		** because the EISA prom is mapped into IO space, we
+		** need to copy the unqiue number into the memory area
+		** that it would have occupied, so that the download
+		** code can determine its ID and card type.
+		*/
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[0],INBZ(EisaSlot,EISA_UNIQUE_NUM_0));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[1],INBZ(EisaSlot,EISA_UNIQUE_NUM_1));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[2],INBZ(EisaSlot,EISA_UNIQUE_NUM_2));
+	 WBYTE(p->RIOHosts[RIONumHosts].Unique[3],INBZ(EisaSlot,EISA_UNIQUE_NUM_3));
+		p->RIOHosts[RIONumHosts].UniqueNum =
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)|
+						((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)|
+			((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24);
+		INBZ(EisaSlot,EISA_INTERRUPT_RESET);
+				RIONumHosts++;
+		ret++;
+			}
+		else
+		{
+		/*
+		** It failed the test, so ignore it.
+		*/
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n");
+
+		RIOMapout(Paddr, RIO_EISA_MEM_SIZE, Caddr );
+		}
+	}
+	}
+	if (RIOMachineType & RIO_EISA)
+	return ret+1;
+	return ret;
+}
+#endif
+
+
+#ifndef linux
+
+#define CONFIG_ADDRESS	0xcf8
+#define CONFIG_DATA		0xcfc
+#define FORWARD_REG		0xcfa
+
+
+static int
+read_config(int bus_number, int device_num, int r_number) 
+{
+	unsigned int cav;
+	unsigned int val;
+
+/*
+   Build config_address_value:
+
+      31        24 23        16 15      11 10  8 7        0 
+      ------------------------------------------------------
+      |1| 0000000 | bus_number | device # | 000 | register |
+      ------------------------------------------------------
+*/
+
+	cav = r_number & 0xff;
+	cav |= ((device_num & 0x1f) << 11);
+	cav |= ((bus_number & 0xff) << 16);
+	cav |= 0x80000000; /* Enable bit */
+	outpd(CONFIG_ADDRESS,cav);
+	val = inpd(CONFIG_DATA);
+	outpd(CONFIG_ADDRESS,0);
+	return val;
+}
+
+static
+write_config(bus_number,device_num,r_number,val) 
+{
+	unsigned int cav;
+
+/*
+   Build config_address_value:
+
+      31        24 23        16 15      11 10  8 7        0 
+      ------------------------------------------------------
+      |1| 0000000 | bus_number | device # | 000 | register |
+      ------------------------------------------------------
+*/
+
+	cav = r_number & 0xff;
+	cav |= ((device_num & 0x1f) << 11);
+	cav |= ((bus_number & 0xff) << 16);
+	cav |= 0x80000000; /* Enable bit */
+	outpd(CONFIG_ADDRESS, cav);
+	outpd(CONFIG_DATA, val);
+	outpd(CONFIG_ADDRESS, 0);
+	return val;
+}
+#else
+/* XXX Implement these... */
+static int
+read_config(int bus_number, int device_num, int r_number) 
+{
+  return 0;
+}
+
+static int
+write_config(int bus_number, int device_num, int r_number) 
+{
+  return 0;
+}
+
+#endif
+
+int
+RIOPCIinit(p, Mode)
+struct rio_info	*p;
+int 		Mode;
+{
+	#define MAX_PCI_SLOT		32
+	#define RIO_PCI_JET_CARD	0x200011CB
+
+	static int	slot;	/* count of machine's PCI slots searched so far */
+	caddr_t		Caddr;	/* Virtual address of the current PCI host card. */
+	unsigned char	Ivec;	/* interrupt vector for the current PCI host */
+	unsigned long	Paddr;	/* Physical address for the current PCI host */
+	int		Handle;	/* Handle to Virtual memory allocated for current PCI host */
+
+
+	rio_dprint(RIO_DEBUG_INIT,  ("Search for a RIO PCI card - start at slot %d\n", slot ) );
+
+	/*
+	** Initialise the search status
+	*/
+	p->RIOLastPCISearch	= RIO_FAIL;
+
+	while ( (slot < MAX_PCI_SLOT) & (p->RIOLastPCISearch != RIO_SUCCESS) )
+	{
+		rio_dprint(RIO_DEBUG_INIT,  ("Currently testing slot %d\n", slot ) );
+
+		if (read_config(0,slot,0) == RIO_PCI_JET_CARD) {
+			p->RIOHosts[p->RIONumHosts].Ivec = 0;
+			Paddr = read_config(0,slot,0x18);
+			Paddr = Paddr - (Paddr & 0x1); /* Mask off the io bit */
+
+			if ( (Paddr == 0) || ((Paddr & 0xffff0000) == 0xffff0000) ) {
+				rio_dprint(RIO_DEBUG_INIT,  ("Goofed up slot\n") );	/* what! */
+				slot++;
+				continue;
+			}
+
+			p->RIOHosts[p->RIONumHosts].PaddrP = Paddr;
+			Ivec = (read_config(0,slot,0x3c) & 0xff);
+
+			rio_dprint(RIO_DEBUG_INIT,  ("PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec ) );
+
+			Handle = RIOMapin( Paddr, RIO_PCI_MEM_SIZE, &Caddr );
+			if (Handle == -1) {
+				rio_dprint(RIO_DEBUG_INIT,  ("Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr ) );
+				slot++;
+				continue;
+			}
+			p->RIOHosts[p->RIONumHosts].Ivec = Ivec + 32;
+			p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec,
+						(int (*)())rio_intr, (char *)p->RIONumHosts);
+			if (RIOBoardTest( Paddr, Caddr, RIO_PCI, 0 ) == RIO_SUCCESS) {
+				rio_dprint(RIO_DEBUG_INIT, ("Board has passed test\n"));
+				rio_dprint(RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, 
+																Mode));
+
+				/*
+				** Board has passed its scrub test. Fill in all the
+				** transient stuff.
+				*/
+				p->RIOHosts[p->RIONumHosts].Slot	   = 0;
+				p->RIOHosts[p->RIONumHosts].Ivec	   = Ivec + 32;
+				p->RIOHosts[p->RIONumHosts].Type	   = RIO_PCI;
+				p->RIOHosts[p->RIONumHosts].Copy	   = rio_pcicopy; 
+				p->RIOHosts[p->RIONumHosts].PaddrP	   = Paddr;
+				p->RIOHosts[p->RIONumHosts].Caddr	   = Caddr;
+				p->RIOHosts[p->RIONumHosts].CardP	   = (struct DpRam *)Caddr;
+				p->RIOHosts[p->RIONumHosts].Mode	   = Mode;
+
+#if 0
+				WBYTE(p->RIOHosts[p->RIONumHosts].Control, 
+						BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+						p->RIOHosts[p->RIONumHosts].Mode | 
+						INTERRUPT_DISABLE );
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+				WBYTE(p->RIOHosts[p->RIONumHosts].Control,
+						BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+						p->RIOHosts[p->RIONumHosts].Mode |
+						INTERRUPT_DISABLE );
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff);
+#else
+				WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff);
+#endif
+				p->RIOHosts[p->RIONumHosts].UniqueNum  =
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+					((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+
+				rio_dprint(RIO_DEBUG_INIT,  ("Unique no 0x%x.\n", 
+				    p->RIOHosts[p->RIONumHosts].UniqueNum ) );
+
+				p->RIOLastPCISearch = RIO_SUCCESS;
+				p->RIONumHosts++;
+			}
+		}
+		slot++;
+	}
+
+	if ( slot >= MAX_PCI_SLOT ) {
+		rio_dprint(RIO_DEBUG_INIT,  ("All %d PCI slots have tested for RIO cards !!!\n",
+		    MAX_PCI_SLOT ) );
+	}
+
+
+	/*
+	** I don't think we want to do this anymore
+	**
+
+	if (!p->RIOLastPCISearch == RIO_FAIL ) {
+		p->RIOFailed++;
+	}
+
+	**
+	*/
+}
+
+#ifdef FUTURE_RELEASE
+void riohalt( void )
+{
+	int host;
+	for ( host=0; host<p->RIONumHosts; host++ )
+	{
+		rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Stop host %d\n",host);
+		(void)RIOBoardTest( p->RIOHosts[host].PaddrP, p->RIOHosts[host].Caddr, p->RIOHosts[host].Type,p->RIOHosts[host].Slot );
+	}
+}
+#endif
+#endif
+
+static	uchar	val[] = {
+#ifdef VERY_LONG_TEST
+	  0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+	  0xa5, 0xff, 0x5a, 0x00, 0xff, 0xc9, 0x36, 
+#endif
+	  0xff, 0x00, 0x00 };
+
+#define	TEST_END sizeof(val)
+
+/*
+** RAM test a board. 
+** Nothing too complicated, just enough to check it out.
+*/
+int
+RIOBoardTest(paddr, caddr, type, slot)
+paddr_t	paddr;
+caddr_t	caddr;
+uchar	type;
+int		slot;
+{
+	struct DpRam *DpRam = (struct DpRam *)caddr;
+	char *ram[4];
+	int  size[4];
+	int  op, bank;
+	int  nbanks;
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n",
+			type,(int)DpRam,slot));
+
+	RIOHostReset(type, DpRam, slot);
+
+	/*
+	** Scrub the memory. This comes in several banks:
+	** DPsram1	- 7000h bytes
+	** DPsram2	- 200h  bytes
+	** DPsram3	- 7000h bytes
+	** scratch	- 1000h bytes
+	*/
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Setup ram/size arrays\n"));
+
+	size[0] = DP_SRAM1_SIZE;
+	size[1] = DP_SRAM2_SIZE;
+	size[2] = DP_SRAM3_SIZE;
+	size[3] = DP_SCRATCH_SIZE;
+
+	ram[0] = (char *)&DpRam->DpSram1[0];
+	ram[1] = (char *)&DpRam->DpSram2[0];
+	ram[2] = (char *)&DpRam->DpSram3[0];
+	nbanks = (type == RIO_PCI) ? 3 : 4;
+	if (nbanks == 4)
+		ram[3] = (char *)&DpRam->DpScratch[0];
+
+
+	if (nbanks == 3) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n",
+				(int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2]));
+	} else {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n",
+			(int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2], (int)ram[3], 
+					size[3]));
+	}
+
+	/*
+	** This scrub operation will test for crosstalk between
+	** banks. TEST_END is a magic number, and relates to the offset
+	** within the 'val' array used by Scrub.
+	*/
+	for (op=0; op<TEST_END; op++) {
+		for (bank=0; bank<nbanks; bank++) {
+			if (RIOScrub(op, (BYTE *)ram[bank], size[bank]) == RIO_FAIL) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: RIOScrub band %d, op %d failed\n", 
+							bank, op));
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	rio_dprint(RIO_DEBUG_INIT, ("Test completed\n"));
+	return RIO_SUCCESS;
+}
+
+
+/*
+** Scrub an area of RAM.
+** Define PRETEST and POSTTEST for a more thorough checking of the
+** state of the memory.
+** Call with op set to an index into the above 'val' array to determine
+** which value will be written into memory.
+** Call with op set to zero means that the RAM will not be read and checked
+** before it is written.
+** Call with op not zero, and the RAM will be read and compated with val[op-1]
+** to check that the data from the previous phase was retained.
+*/
+int
+RIOScrub(op, ram, size)
+int		op;
+BYTE *	ram;
+int		size; 
+{
+	int				off;
+	unsigned char	oldbyte;
+	unsigned char	newbyte;
+	unsigned char	invbyte;
+	unsigned short	oldword;
+	unsigned short	newword;
+	unsigned short	invword;
+	unsigned short	swapword;
+
+	if (op) {
+		oldbyte = val[op-1];
+		oldword = oldbyte | (oldbyte<<8);
+	} else
+	  oldbyte = oldword = 0; /* Tell the compiler we've initilalized them. */
+	newbyte = val[op];
+	newword = newbyte | (newbyte<<8);
+	invbyte = ~newbyte;
+	invword = invbyte | (invbyte<<8);
+
+	/*
+	** Check that the RAM contains the value that should have been left there
+	** by the previous test (not applicable for pass zero)
+	*/
+	if (op) {
+		for (off=0; off<size; off++) {
+			if (RBYTE(ram[off]) != oldbyte) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, RBYTE(ram[off])));
+				return RIO_FAIL;
+			}
+		}
+		for (off=0; off<size; off+=2) {
+			if (*(ushort *)&ram[off] != oldword) {
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword,*(ushort *)&ram[off]));
+				rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	/*
+	** Now write the INVERSE of the test data into every location, using
+	** BYTE write operations, first checking before each byte is written
+	** that the location contains the old value still, and checking after
+	** the write that the location contains the data specified - this is
+	** the BYTE read/write test.
+	*/
+	for (off=0; off<size; off++) {
+		if (op && (RBYTE(ram[off]) != oldbyte)) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,oldbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+		WBYTE(ram[off],invbyte);
+		if (RBYTE(ram[off]) != invbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,invbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now, use WORD operations to write the test value into every location,
+	** check as before that the location contains the previous test value
+	** before overwriting, and that it contains the data value written
+	** afterwards.
+	** This is the WORD operation test.
+	*/
+	for (off=0; off<size; off+=2) {
+		if (*(ushort *)&ram[off] != invword) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,invword,*(ushort *)&ram[off]));
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+
+		*(ushort *)&ram[off] = newword;
+		if ( *(ushort *)&ram[off] != newword ) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off]));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now run through the block of memory again, first in byte mode
+	** then in word mode, and check that all the locations contain the
+	** required test data.
+	*/
+	for (off=0; off<size; off++) {
+		if (RBYTE(ram[off]) != newbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+	}
+
+	for (off=0; off<size; off+=2) {
+		if ( *(ushort *)&ram[off] != newword ) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off]));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** time to check out byte swapping errors
+	*/
+	swapword = invbyte | (newbyte << 8);
+
+	for (off=0; off<size; off+=2) {
+		WBYTE(ram[off],invbyte);
+		WBYTE(ram[off+1],newbyte);
+	}
+
+	for ( off=0; off<size; off+=2 ) {
+		if (*(ushort *)&ram[off] != swapword) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,swapword,*((ushort *)&ram[off])));
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+		*((ushort *)&ram[off]) = ~swapword;
+	}
+
+	for (off=0; off<size; off+=2) {
+		if (RBYTE(ram[off]) != newbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off])));
+			return RIO_FAIL;
+		}
+		if (RBYTE(ram[off+1]) != invbyte) {
+			rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off+1,invbyte,RBYTE(ram[off+1])));
+			return RIO_FAIL;
+		}
+		*((ushort *)&ram[off]) = newword;
+	}
+	return RIO_SUCCESS;
+}
+
+/*
+** try to ensure that every host is either in polled mode
+** or is in interrupt mode. Only allow interrupt mode if
+** all hosts can interrupt (why?)
+** and force into polled mode if told to. Patch up the
+** interrupt vector & salute The Queen when you've done.
+*/
+void
+RIOAllocateInterrupts(p)
+struct rio_info *	p;
+{
+	int Host;
+
+	/*
+	** Easy case - if we have been told to poll, then we poll.
+	*/
+	if (p->mode & POLLED_MODE) {
+		RIOStopInterrupts(p, 0, 0);
+		return;
+	}
+
+	/*
+	** check - if any host has been set to polled mode, then all must be.
+	*/
+	for (Host=0; Host<p->RIONumHosts; Host++) {
+		if ( (p->RIOHosts[Host].Type != RIO_AT) &&
+				(p->RIOHosts[Host].Ivec == POLLED) ) {
+			RIOStopInterrupts(p, 1, Host );
+			return;
+		}
+	}
+	for (Host=0; Host<p->RIONumHosts; Host++) {
+		if (p->RIOHosts[Host].Type == RIO_AT) {
+			if ( (p->RIOHosts[Host].Ivec - 32) == 0) {
+				RIOStopInterrupts(p, 2, Host );
+				return;
+			}
+		}
+	}
+}
+
+/*
+** something has decided that we can't be doing with these
+** new-fangled interrupt thingies. Set everything up to just
+** poll.
+*/
+void
+RIOStopInterrupts(p, Reason, Host)
+struct rio_info *	p;
+int	Reason;
+int	Host; 
+{
+#ifdef FUTURE_RELEASE
+	switch (Reason) {
+		case 0:	/* forced into polling by rio_polled */
+			break;
+		case 1:	/* SCU has set 'Host' into polled mode */
+			break;
+		case 2:	/* there aren't enough interrupt vectors for 'Host' */
+			break;
+	}
+#endif
+
+	for (Host=0; Host<p->RIONumHosts; Host++ ) {
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		switch (HostP->Type) {
+			case RIO_AT:
+				/*
+				** The AT host has it's interrupts disabled by clearing the
+				** int_enable bit.
+				*/
+				HostP->Mode &= ~INTERRUPT_ENABLE;
+				HostP->Ivec = POLLED;
+				break;
+#ifdef FUTURE_RELEASE
+			case RIO_EISA:
+				/*
+				** The EISA host has it's interrupts disabled by setting the
+				** Ivec to zero
+				*/
+				HostP->Ivec = POLLED;
+				break;
+#endif
+			case RIO_PCI:
+				/*
+				** The PCI host has it's interrupts disabled by clearing the
+				** int_enable bit, like a regular host card.
+				*/
+				HostP->Mode &= ~RIO_PCI_INT_ENABLE;
+				HostP->Ivec = POLLED;
+				break;
+#ifdef FUTURE_RELEASE
+			case RIO_MCA:
+				/*
+				** There's always one, isn't there?
+				** The MCA host card cannot have it's interrupts disabled.
+				*/
+				RIOPatchVec(HostP);
+				break;
+#endif
+		}
+	}
+}
+
+#if 0
+/*
+** This function is called at init time to setup the data structures.
+*/
+void
+RIOAllocDataStructs(p)
+struct rio_info *	p;
+{
+	int	port,
+		host,
+		tm;
+
+	p->RIOPortp = (struct Port *)sysbrk(RIO_PORTS * sizeof(struct Port));
+	if (!p->RIOPortp) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for port structures\n"));
+		p->RIOFailed++;
+		return;
+	} 
+	bzero( p->RIOPortp, sizeof(struct Port) * RIO_PORTS );
+	rio_dprint(RIO_DEBUG_INIT,  ("RIO-init: allocated and cleared memory for port structs\n") );
+	rio_dprint(RIO_DEBUG_INIT,  ("First RIO port struct @0x%x, size=0x%x bytes\n",
+	    (int)p->RIOPortp, sizeof(struct Port) ) );
+
+	for( port=0; port<RIO_PORTS; port++ ) {
+		p->RIOPortp[port].PortNum = port;
+		p->RIOPortp[port].TtyP = &p->channel[port];
+		sreset (p->RIOPortp[port].InUse);	/* Let the first guy uses it */
+		p->RIOPortp[port].portSem = -1;	/* Let the first guy takes it */
+		p->RIOPortp[port].ParamSem = -1;	/* Let the first guy takes it */
+		p->RIOPortp[port].timeout_id = 0;	/* Let the first guy takes it */
+	}
+
+	p->RIOHosts = (struct Host *)sysbrk(RIO_HOSTS * sizeof(struct Host));
+	if (!p->RIOHosts) {
+		rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for host structures\n"));
+		p->RIOFailed++;
+		return;
+	}
+	bzero(p->RIOHosts, sizeof(struct Host)*RIO_HOSTS);
+	rio_dprint(RIO_DEBUG_INIT,  ("RIO-init: allocated and cleared memory for host structs\n"));
+	rio_dprint(RIO_DEBUG_INIT,  ("First RIO host struct @0x%x, size=0x%x bytes\n",
+	    (int)p->RIOHosts, sizeof(struct Host) ) );
+
+	for( host=0; host<RIO_HOSTS; host++ ) {
+		p->RIOHosts[host].HostLock = SPIN_LOCK_UNLOCKED; /* Let the first guy takes it */
+		p->RIOHosts[host].timeout_id = 0; /* Let the first guy takes it */
+	}
+	/*
+	** check that the buffer size is valid, round down to the next power of
+	** two if necessary; if the result is zero, then, hey, no double buffers.
+	*/
+	for ( tm = 1; tm && tm <= p->RIOConf.BufferSize; tm <<= 1 )
+		;
+	tm >>= 1;
+	p->RIOBufferSize = tm;
+	p->RIOBufferMask = tm ? tm - 1 : 0;
+}
+
+/*
+** this function gets called whenever the data structures need to be
+** re-setup, for example, after a riohalt (why did I ever invent it?)
+*/
+void
+RIOSetupDataStructs(p)
+struct rio_info	* p;
+{
+	int host, entry, rup;
+
+	for ( host=0; host<RIO_HOSTS; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+		for ( entry=0; entry<LINKS_PER_UNIT; entry++ ) {
+			HostP->Topology[entry].Unit = ROUTE_DISCONNECT;
+			HostP->Topology[entry].Link = NO_LINK;
+		}
+		bcopy("HOST X", HostP->Name, 7);
+		HostP->Name[5] = '1'+host;
+		for (rup=0; rup<(MAX_RUP + LINKS_PER_UNIT); rup++) {
+			if (rup < MAX_RUP) {
+				for (entry=0; entry<LINKS_PER_UNIT; entry++ ) {
+					HostP->Mapping[rup].Topology[entry].Unit = ROUTE_DISCONNECT;
+					HostP->Mapping[rup].Topology[entry].Link = NO_LINK;
+				}
+				RIODefaultName(p, HostP, rup);
+			}
+			HostP->UnixRups[rup].RupLock = -1;
+		}
+	}
+}
+#endif
+
+int
+RIODefaultName(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *	HostP;
+uint			UnitId;
+{
+#ifdef CHECK
+	CheckHost( Host );
+	CheckUnitId( UnitId );
+#endif
+	bcopy("UNKNOWN RTA X-XX",HostP->Mapping[UnitId].Name,17);
+	HostP->Mapping[UnitId].Name[12]='1'+(HostP-p->RIOHosts);
+	if ((UnitId+1) > 9) {
+		HostP->Mapping[UnitId].Name[14]='0'+((UnitId+1)/10);
+		HostP->Mapping[UnitId].Name[15]='0'+((UnitId+1)%10);
+	}
+	else {
+		HostP->Mapping[UnitId].Name[14]='1'+UnitId;
+		HostP->Mapping[UnitId].Name[15]=0;
+	}
+	return 0;
+}
+
+#define RIO_RELEASE	"Linux"
+#define RELEASE_ID	"1.0"
+
+int
+RIOReport(p)
+struct rio_info *	p;
+{
+	char *	RIORelease = RIO_RELEASE;
+	char *	RIORelID = RELEASE_ID;
+	int		host;
+
+	rio_dprint(RIO_DEBUG_INIT, ("RIO : Release: %s ID: %s\n", RIORelease, RIORelID));
+
+	if ( p->RIONumHosts==0 ) {
+		rio_dprint(RIO_DEBUG_INIT, ("\nNo Hosts configured\n"));
+		return(0);
+	}
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+		switch ( HostP->Type ) {
+			case RIO_AT:
+				rio_dprint(RIO_DEBUG_INIT, ("AT BUS : found the card at 0x%x\n", HostP->PaddrP));
+		}
+	}
+	return 0;
+}
+
+/*
+** This function returns release/version information as used by ioctl() calls
+** It returns a MAX_VERSION_LEN byte string, null terminated.
+*/
+char *
+OLD_RIOVersid( void )
+{
+	static char	Info[MAX_VERSION_LEN];
+	char *	RIORelease = RIO_RELEASE;
+	char *	cp;
+	int		ct = 0;
+
+	for ( ct=0; RIORelease[ct] && ct<MAX_VERSION_LEN; ct++ )
+		Info[ct] = RIORelease[ct];
+	if ( ct>=MAX_VERSION_LEN ) {
+		Info[MAX_VERSION_LEN-1] = '\0';
+		return Info;
+	}
+	Info[ct++]=' ';
+	if ( ct>=MAX_VERSION_LEN ) {
+		Info[MAX_VERSION_LEN-1] = '\0';
+		return Info;
+	}
+
+	cp="";	/* Fill the RCS Id here */
+
+	while ( *cp && ct<MAX_VERSION_LEN )
+		Info[ct++] = *cp++;
+	if ( ct<MAX_VERSION_LEN-1 )
+		Info[ct] = '\0';
+	Info[MAX_VERSION_LEN-1] = '\0';
+	return Info;
+}
+
+
+static struct rioVersion	stVersion;
+
+struct rioVersion *
+RIOVersid(void)
+{
+    strncpy(stVersion.version, "RIO driver for linux V1.0", 255);
+    strncpy(stVersion.buildDate, __DATE__, 255);
+
+    return &stVersion;
+}
+
+#if 0
+int
+RIOMapin(paddr, size, vaddr)
+paddr_t		paddr;
+int			size;
+caddr_t *	vaddr;
+{
+	*vaddr = (caddr_t)permap( (long)paddr, size);
+	return ((int)*vaddr);
+}
+
+void
+RIOMapout(paddr, size, vaddr)
+paddr_t		paddr;
+long		size;
+caddr_t 	vaddr;
+{
+}
+#endif
+
+
+void
+RIOHostReset(Type, DpRamP, Slot)
+uint Type;
+volatile struct DpRam *DpRamP;
+uint Slot; 
+{
+	/*
+	** Reset the Tpu
+	*/
+	rio_dprint(RIO_DEBUG_INIT,  ("RIOHostReset: type 0x%x", Type ) );
+	switch ( Type ) {
+		case RIO_AT:
+			rio_dprint(RIO_DEBUG_INIT, (" (RIO_AT)\n"));
+			WBYTE(DpRamP->DpControl,  BOOT_FROM_RAM | EXTERNAL_BUS_OFF | 
+					  INTERRUPT_DISABLE | BYTE_OPERATION |
+					  SLOW_LINKS | SLOW_AT_BUS);
+			WBYTE(DpRamP->DpResetTpu, 0xFF);
+			rio_udelay (3);
+
+			rio_dprint(RIO_DEBUG_INIT,  ("RIOHostReset: Don't know if it worked. Try reset again\n") );
+			WBYTE(DpRamP->DpControl,  BOOT_FROM_RAM | EXTERNAL_BUS_OFF |
+					  INTERRUPT_DISABLE | BYTE_OPERATION |
+					  SLOW_LINKS | SLOW_AT_BUS);
+			WBYTE(DpRamP->DpResetTpu, 0xFF);
+			rio_udelay (3);
+			break;
+#ifdef FUTURE_RELEASE
+	case RIO_EISA:
+	/*
+	** Bet this doesn't work!
+	*/
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RUN		| EISA_TP_BUS_DISABLE   |
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RESET	  | EISA_TP_BUS_DISABLE   | 
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	suspend( 3 );
+	OUTBZ( Slot, EISA_CONTROL_PORT,
+		EISA_TP_RUN		| EISA_TP_BUS_DISABLE   | 
+		EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM );
+	break;
+	case RIO_MCA:
+	WBYTE(DpRamP->DpControl  , McaTpBootFromRam | McaTpBusDisable );
+	WBYTE(DpRamP->DpResetTpu , 0xFF );
+	suspend( 3 );
+	WBYTE(DpRamP->DpControl  , McaTpBootFromRam | McaTpBusDisable );
+	WBYTE(DpRamP->DpResetTpu , 0xFF );
+	suspend( 3 );
+		break;
+#endif
+	case RIO_PCI:
+		rio_dprint(RIO_DEBUG_INIT,  (" (RIO_PCI)\n") );
+		DpRamP->DpControl  = RIO_PCI_BOOT_FROM_RAM;
+		DpRamP->DpResetInt = 0xFF;
+		DpRamP->DpResetTpu = 0xFF;
+		rio_udelay (100);
+		/* for (i=0; i<6000; i++);  */
+		/* suspend( 3 ); */
+		break;
+#ifdef FUTURE_RELEASE
+	default:
+	Rprintf(RIOMesgNoSupport,Type,DpRamP,Slot);
+	return;
+#endif
+
+	default:
+		rio_dprint(RIO_DEBUG_INIT,  (" (UNKNOWN)\n") );
+		break;
+	}
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riointr.c linux/drivers/char/rio/riointr.c
--- v2.3.99-pre6/linux/drivers/char/rio/riointr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riointr.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1112 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riointr.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:44
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riointr.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riointr_c_sccs_ = "@(#)riointr.c	1.2";
+#endif
+
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+#include <linux/delay.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+
+
+/*
+** riopoll is called every clock tick. Once the /dev/rio device has been
+** opened, and polldistributed( ) has been called, this routine is called
+** every clock tick *by every cpu*. The 'interesting' piece of code that
+** manipulates 'RIONumCpus' and 'RIOCpuCountdown' is used to fair-share
+** the work between the CPUs. If there are 'N' cpus, then each poll time
+** we increment a counter, modulo 'N-1'. When this counter is 0, we call
+** the interrupt handler. This has the effect that polls are serviced
+** by processor 'N', 'N-1', 'N-2', ... '0', round and round. Neat.
+*/
+void
+riopoll(p)
+struct rio_info *	p;
+{
+	int   host;
+
+	/*
+	** Here's the deal. We try to fair share as much as possible amongst
+	** all the processors that are available. Since each processor 
+	** should generate HZ ticks per second and since we only need HZ ticks
+	** in total for proper operation we simply attempt to cycle round each
+	** processor in turn, using RIOCpuCountdown to decide whether to call
+	** the interrupt routine. ( In fact the count zeroes when it reaches
+	** one less than the total number of processors - so e.g. on a two
+	** processor system RIOService will get called 2*HZ times per second. )
+	** this_cpu (cur_cpu()) tells us the number of the current processor
+	** as follows:
+	**
+	**		0 - default CPU
+	**		1 - first extra CPU
+	**		2 - second extra CPU
+	**		etc.
+	*/
+
+	/*
+	** okay, we've got a cpu that hasn't had a go recently 
+	** - lets check to see what needs doing.
+	*/
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+
+		rio_spin_lock( &HostP->HostLock );
+
+		if ( ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) ||
+		     HostP->InIntr ) {
+			rio_spin_unlock (&HostP->HostLock); 
+			continue;
+		}
+
+		if ( RWORD( HostP->ParmMapP->rup_intr ) ||
+			 RWORD( HostP->ParmMapP->rx_intr  ) ||
+			 RWORD( HostP->ParmMapP->tx_intr  ) ) {
+			HostP->InIntr = 1;
+
+#ifdef FUTURE_RELEASE
+			if( HostP->Type == RIO_EISA )
+				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );
+			else
+#endif
+				WBYTE( HostP->ResetInt , 0xff );
+
+			rio_spin_lock(&HostP->HostLock); 
+
+			p->_RIO_Polled++;
+			RIOServiceHost(p, HostP, 'p' );
+			rio_spin_lock( &HostP->HostLock); 
+			HostP->InIntr = 0;
+			rio_spin_unlock (&HostP->HostLock);
+		}
+	}
+	rio_spin_unlock (&p->RIOIntrSem); 
+}
+
+
+char *firstchars (char *p, int nch)
+{
+  static char buf[2][128];
+  static int t=0;
+  t = ! t;
+  memcpy (buf[t], p, nch);
+  buf[t][nch] = 0;
+  return buf[t];
+}
+
+
+#define	INCR( P, I )	((P) = (((P)+(I)) & p->RIOBufferMask))
+/* Enable and start the transmission of packets */
+void
+RIOTxEnable(en)
+char *		en;
+{
+  struct Port *	PortP;
+  struct rio_info *p;
+  struct tty_struct* tty;
+  int c;
+  struct PKT *	PacketP;
+  unsigned long flags;
+
+  PortP = (struct Port *)en; 
+  p = (struct rio_info *)PortP->p;
+  tty = PortP->gs.tty;
+
+
+  rio_dprint (RIO_DEBUG_INTR, ("tx port %d: %d chars queued.\n", 
+	      PortP->PortNum, PortP->gs.xmit_cnt));
+
+  if (!PortP->gs.xmit_cnt) return;
+  
+
+  /* This routine is an order of magnitude simpler than the specialix
+     version. One of the disadvantages is that this version will send
+     an incomplete packet (usually 64 bytes instead of 72) once for
+     every 4k worth of data. Let's just say that this won't influence
+     performance significantly..... */
+
+  rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+  while (can_add_transmit( &PacketP, PortP )) {
+    c = PortP->gs.xmit_cnt;
+    if (c > PKT_MAX_DATA_LEN) c = PKT_MAX_DATA_LEN;
+
+    /* Don't copy past the end of the source buffer */
+    if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail) 
+      c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;
+
+    { int t;
+    t = (c > 10)?10:c;
+    
+    rio_dprint (RIO_DEBUG_INTR, ("tx port %d: copying %d chars: %s - %s\n", 
+				 PortP->PortNum, c, 
+	 firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail      , t),
+	 firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t)));
+    }
+    /* If for one reason or another, we can't copy more data, 
+       we're done! */
+    if (c == 0) break;
+
+    rio_memcpy_toio (PortP->HostP->Caddr, (caddr_t)PacketP->data, 
+		 PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
+    /*    udelay (1); */
+
+    writeb (c, &(PacketP->len));
+    if (!( PortP->State & RIO_DELETED ) ) {
+      add_transmit ( PortP );
+      /*
+      ** Count chars tx'd for port statistics reporting
+      */
+      if ( PortP->statsGather )
+	PortP->txchars += c;
+    }
+    PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+    PortP->gs.xmit_cnt -= c;
+  }
+
+  rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+  if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2*PKT_MAX_DATA_LEN)) {
+    rio_dprint (RIO_DEBUG_INTR, ("Waking up.... ldisc:%d (%d/%d)....",
+		 (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)),
+		 PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); 
+    if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	PortP->gs.tty->ldisc.write_wakeup)
+      (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty);
+    rio_dprint (RIO_DEBUG_INTR, ("(%d/%d)\n",
+		PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); 
+    wake_up_interruptible(&PortP->gs.tty->write_wait);
+  }
+
+}
+
+
+/*
+** When a real-life interrupt comes in here, we try to find out
+** which host card it belongs to, and then service only that host
+** Notice the cunning way that, once we've found a candidate, we
+** continue just in case we are sharing interrupts.
+*/
+void
+riointr(p)
+struct rio_info *	p;
+{
+	int host;
+
+	for ( host=0; host<p->RIONumHosts; host++ ) {
+		struct Host *HostP = &p->RIOHosts[host];
+
+		rio_dprint(RIO_DEBUG_INTR,  ("riointr() doing host %d type %d\n", host, HostP->Type ) );
+
+		switch( HostP->Type ) {
+			case RIO_AT:
+			case RIO_MCA:
+			case RIO_PCI:
+			  	rio_spin_lock(&HostP->HostLock);
+				WBYTE(HostP->ResetInt , 0xff);
+				if ( !HostP->InIntr ) {
+					HostP->InIntr = 1;
+					rio_spin_unlock (&HostP->HostLock);
+					p->_RIO_Interrupted++;
+					RIOServiceHost(p, HostP, 'i');
+					rio_spin_lock(&HostP->HostLock);
+					HostP->InIntr = 0;
+				}
+				rio_spin_unlock(&HostP->HostLock); 
+				break;
+#ifdef FUTURE_RELEASE
+		case RIO_EISA:
+			if ( ivec == HostP->Ivec )
+			{
+				OldSpl = LOCKB( &HostP->HostLock );
+				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );
+				if ( !HostP->InIntr )
+				{
+					HostP->InIntr = 1;
+					UNLOCKB( &HostP->HostLock, OldSpl );
+					if ( this_cpu < RIO_CPU_LIMIT )
+					{
+						int intrSpl = LOCKB( &RIOIntrLock );
+						UNLOCKB( &RIOIntrLock, intrSpl );
+					}
+						p->_RIO_Interrupted++;
+					RIOServiceHost( HostP, 'i' );
+					OldSpl = LOCKB( &HostP->HostLock );
+					HostP->InIntr = 0;
+				}
+				UNLOCKB( &HostP->HostLock, OldSpl );
+				done++;
+			}
+			break;
+#endif
+		}
+
+		HostP->IntSrvDone++;
+	}
+
+#ifdef FUTURE_RELEASE
+	if ( !done )
+	{
+		cmn_err( CE_WARN, "RIO: Interrupt received with vector 0x%x\n", ivec );
+		cmn_err( CE_CONT, "	 Valid vectors are:\n");
+		for ( host=0; host<RIONumHosts; host++ )
+		{
+			switch( RIOHosts[host].Type )
+			{
+				case RIO_AT:
+				case RIO_MCA:
+				case RIO_EISA:
+						cmn_err( CE_CONT, "0x%x ", RIOHosts[host].Ivec );
+						break;
+				case RIO_PCI:
+						cmn_err( CE_CONT, "0x%x ", get_intr_arg( RIOHosts[host].PciDevInfo.busnum, IDIST_PCI_IRQ( RIOHosts[host].PciDevInfo.slotnum, RIOHosts[host].PciDevInfo.funcnum ) ));
+						break;
+			}
+		}
+		cmn_err( CE_CONT, "\n" );
+	}
+#endif
+}
+
+/*
+** RIO Host Service routine. Does all the work traditionally associated with an
+** interrupt.
+*/
+static int	RupIntr;
+static int	RxIntr;
+static int	TxIntr;
+void
+RIOServiceHost(p, HostP, From)
+struct rio_info *	p;
+struct Host *HostP;
+int From; 
+{
+  rio_spin_lock (&HostP->HostLock);
+  if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) { 
+    static int t =0;
+    rio_spin_unlock (&HostP->HostLock); 
+    if ((t++ % 200) == 0)
+      rio_dprint(RIO_DEBUG_INTR, ("Interrupt but host not running. flags=%x.\n", (int)HostP->Flags));
+    return;
+  }
+  rio_spin_unlock (&HostP->HostLock); 
+
+  if ( RWORD( HostP->ParmMapP->rup_intr ) ) {
+    WWORD( HostP->ParmMapP->rup_intr , 0 );
+    p->RIORupCount++;
+    RupIntr++;
+    rio_dprint(RIO_DEBUG_INTR, ("RUP interrupt on host %d\n", HostP-p->RIOHosts ));
+    RIOPollHostCommands(p, HostP );
+  }
+
+  if ( RWORD( HostP->ParmMapP->rx_intr ) ) {
+    int port;
+
+    WWORD( HostP->ParmMapP->rx_intr , 0 );
+    p->RIORxCount++;
+    RxIntr++;
+
+    rio_dprint(RIO_DEBUG_INTR, ("RX interrupt on host %d\n", HostP-p->RIOHosts));
+    /*
+    ** Loop through every port. If the port is mapped into
+    ** the system ( i.e. has /dev/ttyXXXX associated ) then it is
+    ** worth checking. If the port isn't open, grab any packets
+    ** hanging on its receive queue and stuff them on the free
+    ** list; check for commands on the way.
+    */
+    for ( port=p->RIOFirstPortsBooted; 
+	  port<p->RIOLastPortsBooted+PORTS_PER_RTA; port++ ) {
+      struct Port *PortP = p->RIOPortp[port];
+      struct tty_struct *ttyP;
+      struct PKT *PacketP;
+		
+      /*
+      ** not mapped in - most of the RIOPortp[] information
+      ** has not been set up!
+      ** Optimise: ports come in bundles of eight.
+      */
+      if ( !PortP->Mapped ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** If the host board isn't THIS host board, check the next one.
+      ** optimise: ports come in bundles of eight.
+      */
+      if ( PortP->HostP != HostP ) {
+	port += 7;
+	continue;
+      }
+
+      /*
+      ** Let us see - is the port open? If not, then don't service it.
+      */
+      if ( !( PortP->PortState & PORT_ISOPEN ) ) {
+	continue;
+      }
+
+      /*
+      ** find corresponding tty structure. The process of mapping
+      ** the ports puts these here.
+      */
+      ttyP = PortP->gs.tty;
+
+      /*
+      ** Lock the port before we begin working on it.
+      */
+      rio_spin_lock(&PortP->portSem);
+
+      /*
+      ** Process received data if there is any.
+      */
+      if ( can_remove_receive( &PacketP, PortP ) )
+	RIOReceive(p, PortP);
+
+      /*
+      ** If there is no data left to be read from the port, and
+      ** it's handshake bit is set, then we must clear the handshake,
+      ** so that that downstream RTA is re-enabled.
+      */
+      if ( !can_remove_receive( &PacketP, PortP ) && 
+	   ( RWORD( PortP->PhbP->handshake )==PHB_HANDSHAKE_SET ) ) {
+				/*
+				** MAGIC! ( Basically, handshake the RX buffer, so that
+				** the RTAs upstream can be re-enabled. )
+				*/
+	rio_dprint(RIO_DEBUG_INTR, ("Set RX handshake bit\n" ));
+	WWORD( PortP->PhbP->handshake, 
+	       PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET );
+      }
+      rio_spin_unlock(&PortP->portSem);
+    }
+  }
+
+  if ( RWORD( HostP->ParmMapP->tx_intr ) ) {
+    int port;
+
+    WWORD( HostP->ParmMapP->tx_intr , 0);
+
+    p->RIOTxCount++;
+    TxIntr++;
+    rio_dprint(RIO_DEBUG_INTR, ("TX interrupt on host %d\n", HostP-p->RIOHosts));
+
+    /*
+    ** Loop through every port.
+    ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX
+    ** associated ) then it is worth checking.
+    */
+    for ( port=p->RIOFirstPortsBooted; 
+	  port<p->RIOLastPortsBooted+PORTS_PER_RTA; port++ ) {
+      struct Port *PortP = p->RIOPortp[port];
+      struct tty_struct *ttyP;
+      struct PKT *PacketP;
+
+      /*
+      ** not mapped in - most of the RIOPortp[] information
+      ** has not been set up!
+      */
+      if ( !PortP->Mapped ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** If the host board isn't running, then its data structures
+      ** are no use to us - continue quietly.
+      */
+      if ( PortP->HostP != HostP ) {
+	port += 7;
+	continue; /* with the next port */
+      }
+
+      /*
+      ** Let us see - is the port open? If not, then don't service it.
+      */
+      if ( !( PortP->PortState & PORT_ISOPEN ) ) {
+	continue;
+      }
+
+      rio_dprint (RIO_DEBUG_INTR, ("Looking into port %d.\n", port));
+      /*
+      ** Lock the port before we begin working on it.
+      */
+      rio_spin_lock(&PortP->portSem);
+
+      /*
+      ** If we can't add anything to the transmit queue, then
+      ** we need do none of this processing.
+      */
+      if ( !can_add_transmit( &PacketP, PortP ) ) {
+	rio_dprint (RIO_DEBUG_INTR, ("Can't add to port, so skipping.\n"));
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+
+      /*
+      ** find corresponding tty structure. The process of mapping
+      ** the ports puts these here.
+      */
+      ttyP = PortP->gs.tty;
+      /* If ttyP is NULL, the port is getting closed. Forget about it. */
+      if (!ttyP) {
+	rio_dprint (RIO_DEBUG_INTR, ("no tty, so skipping.\n"));
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+      /*
+      ** If there is more room available we start up the transmit
+      ** data process again. This can be direct I/O, if the cookmode
+      ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the
+      ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch
+      ** characters via the line discipline. We must always call
+      ** the line discipline,
+      ** so that user input characters can be echoed correctly.
+      **
+      ** ++++ Update +++++
+      ** With the advent of double buffering, we now see if
+      ** TxBufferOut-In is non-zero. If so, then we copy a packet
+      ** to the output place, and set it going. If this empties
+      ** the buffer, then we must issue a wakeup( ) on OUT.
+      ** If it frees space in the buffer then we must issue
+      ** a wakeup( ) on IN.
+      **
+      ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we
+      ** have to send a WFLUSH command down the PHB, to mark the
+      ** end point of a WFLUSH. We also need to clear out any
+      ** data from the double buffer! ( note that WflushFlag is a
+      ** *count* of the number of WFLUSH commands outstanding! )
+      **
+      ** ++++ And there's more!
+      ** If an RTA is powered off, then on again, and rebooted,
+      ** whilst it has ports open, then we need to re-open the ports.
+      ** ( reasonable enough ). We can't do this when we spot the
+      ** re-boot, in interrupt time, because the queue is probably
+      ** full. So, when we come in here, we need to test if any
+      ** ports are in this condition, and re-open the port before
+      ** we try to send any more data to it. Now, the re-booted
+      ** RTA will be discarding packets from the PHB until it
+      ** receives this open packet, but don't worry tooo much
+      ** about that. The one thing that is interesting is the
+      ** combination of this effect and the WFLUSH effect!
+      */
+      /* For now don't handle RTA reboots. -- REW. 
+	 Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */
+      if ( PortP->MagicFlags ) {
+#if 1
+	if ( PortP->MagicFlags & MAGIC_REBOOT ) {
+	  /*
+	  ** well, the RTA has been rebooted, and there is room
+	  ** on its queue to add the open packet that is required.
+	  **
+	  ** The messy part of this line is trying to decide if
+	  ** we need to call the Param function as a tty or as
+	  ** a modem.
+	  ** DONT USE CLOCAL AS A TEST FOR THIS!
+	  **
+	  ** If we can't param the port, then move on to the
+	  ** next port.
+	  */
+	  PortP->InUse = NOT_INUSE;
+
+	  rio_spin_unlock(&PortP->portSem);
+	  if ( RIOParam(PortP, OPEN, ((PortP->Cor2Copy & 
+				       (COR2_RTSFLOW|COR2_CTSFLOW ) )== 
+				      (COR2_RTSFLOW|COR2_CTSFLOW ) ) ? 
+			TRUE : FALSE, DONT_SLEEP ) == RIO_FAIL ) {
+	    continue; /* with next port */
+	  }
+	  rio_spin_lock(&PortP->portSem);
+	  PortP->MagicFlags &= ~MAGIC_REBOOT;
+	}
+#endif
+
+	/*
+	** As mentioned above, this is a tacky hack to cope
+	** with WFLUSH
+	*/
+	if ( PortP->WflushFlag ) {
+	  rio_dprint(RIO_DEBUG_INTR, ("Want to WFLUSH mark this port\n"));
+
+	  if ( PortP->InUse )
+	    rio_dprint(RIO_DEBUG_INTR, ("FAILS - PORT IS IN USE\n"));
+	}
+				
+	while ( PortP->WflushFlag &&
+		can_add_transmit( &PacketP, PortP ) && 
+		( PortP->InUse == NOT_INUSE ) ) {
+	  int p;
+	  struct PktCmd *PktCmdP;
+
+	  rio_dprint(RIO_DEBUG_INTR, ("Add WFLUSH marker to data queue\n"));
+	  /*
+	  ** make it look just like a WFLUSH command
+	  */
+	  PktCmdP = ( struct PktCmd * )&PacketP->data[0];
+
+	  WBYTE( PktCmdP->Command , WFLUSH );
+
+	  p =  PortP->HostPort % ( ushort )PORTS_PER_RTA;
+
+	  /*
+	  ** If second block of ports for 16 port RTA, add 8
+	  ** to index 8-15.
+	  */
+	  if ( PortP->SecondBlock )
+	    p += PORTS_PER_RTA;
+
+	  WBYTE( PktCmdP->PhbNum, p );
+
+	  /*
+	  ** to make debuggery easier
+	  */
+	  WBYTE( PacketP->data[ 2], 'W'  );
+	  WBYTE( PacketP->data[ 3], 'F'  );
+	  WBYTE( PacketP->data[ 4], 'L'  );
+	  WBYTE( PacketP->data[ 5], 'U'  );
+	  WBYTE( PacketP->data[ 6], 'S'  );
+	  WBYTE( PacketP->data[ 7], 'H'  );
+	  WBYTE( PacketP->data[ 8], ' '  );
+	  WBYTE( PacketP->data[ 9], '0'+PortP->WflushFlag );
+	  WBYTE( PacketP->data[10], ' '  );
+	  WBYTE( PacketP->data[11], ' '  );
+	  WBYTE( PacketP->data[12], '\0' );
+
+	  /*
+	  ** its two bytes long!
+	  */
+	  WBYTE( PacketP->len , PKT_CMD_BIT | 2 );
+
+	  /*
+	  ** queue it!
+	  */
+	  if ( !( PortP->State & RIO_DELETED ) ) {
+	    add_transmit( PortP );
+	    /*
+	    ** Count chars tx'd for port statistics reporting
+	    */
+	    if ( PortP->statsGather )
+	      PortP->txchars += 2;
+	  }
+
+	  if ( --( PortP->WflushFlag ) == 0 ) {
+	    PortP->MagicFlags &= ~MAGIC_FLUSH;
+	  }
+
+	  rio_dprint(RIO_DEBUG_INTR, ("Wflush count now stands at %d\n", 
+		 PortP->WflushFlag));
+	}
+	if ( PortP->MagicFlags & MORE_OUTPUT_EYGOR ) {
+	  if ( PortP->MagicFlags & MAGIC_FLUSH ) {
+	    PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+	  }
+	  else {
+	    if ( !can_add_transmit( &PacketP, PortP ) ) {
+	      rio_spin_unlock(&PortP->portSem);
+	      continue;
+	    }
+	    rio_spin_unlock(&PortP->portSem);
+	    RIOTxEnable((char *)PortP);
+	    rio_spin_lock(&PortP->portSem);
+	    PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+	  }
+	}
+      }
+
+
+      /*
+      ** If we can't add anything to the transmit queue, then
+      ** we need do none of the remaining processing.
+      */
+      if (!can_add_transmit( &PacketP, PortP ) ) {
+	rio_spin_unlock(&PortP->portSem);
+	continue;
+      }
+
+      rio_spin_unlock(&PortP->portSem);
+      RIOTxEnable((char *)PortP);
+    }
+  }
+}
+
+/*
+** Routine for handling received data for clist drivers.
+** NB: Called with the tty locked. The spl from the lockb( ) is passed.
+** we return the ttySpl level that we re-locked at.
+*/
+void
+RIOReceive(p, PortP)
+struct rio_info *	p;
+struct Port *		PortP;
+{
+  struct tty_struct *TtyP;
+  register ushort transCount;
+  struct PKT *PacketP;
+  register uint	DataCnt;
+  uchar *	ptr;
+  int copied =0;
+
+  static int intCount, RxIntCnt;
+
+  /*
+  ** The receive data process is to remove packets from the
+  ** PHB until there aren't any more or the current cblock
+  ** is full. When this occurs, there will be some left over
+  ** data in the packet, that we must do something with.
+  ** As we haven't unhooked the packet from the read list
+  ** yet, we can just leave the packet there, having first
+  ** made a note of how far we got. This means that we need
+  ** a pointer per port saying where we start taking the
+  ** data from - this will normally be zero, but when we
+  ** run out of space it will be set to the offset of the
+  ** next byte to copy from the packet data area. The packet
+  ** length field is decremented by the number of bytes that
+  ** we succesfully removed from the packet. When this reaches
+  ** zero, we reset the offset pointer to be zero, and free
+  ** the packet from the front of the queue.
+  */
+
+  intCount++;
+
+  TtyP = PortP->gs.tty;
+  if (!TtyP) {
+    rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: tty is null. \n"));
+    return;
+  }
+
+  if (PortP->State & RIO_THROTTLE_RX) {
+    rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: Throttled. Can't handle more input.\n"));
+    return;
+  }
+
+  if ( PortP->State & RIO_DELETED )
+    {
+      while ( can_remove_receive( &PacketP, PortP ) )
+	{
+	  remove_receive( PortP );
+	  put_free_end( PortP->HostP, PacketP );
+	}
+    }
+  else
+    {
+      /*
+      ** loop, just so long as:
+      **   i ) there's some data ( i.e. can_remove_receive )
+      **  ii ) we haven't been blocked
+      ** iii ) there's somewhere to put the data
+      **  iv ) we haven't outstayed our welcome
+      */
+      transCount = 1;
+      while ( can_remove_receive(&PacketP, PortP)
+	      && transCount)
+	{
+#ifdef STATS
+	  PortP->Stat.RxIntCnt++;
+#endif /* STATS */
+	  RxIntCnt++;
+
+	  /*
+	  ** check that it is not a command!
+	  */
+	  if ( PacketP->len & PKT_CMD_BIT ) {
+	    rio_dprint(RIO_DEBUG_INTR, ("RIO: unexpected command packet received on PHB\n"));
+	    /*	    rio_dprint(RIO_DEBUG_INTR, (" sysport   = %d\n", p->RIOPortp->PortNum)); */
+	    rio_dprint(RIO_DEBUG_INTR, (" dest_unit = %d\n", PacketP->dest_unit));
+	    rio_dprint(RIO_DEBUG_INTR, (" dest_port = %d\n", PacketP->dest_port));
+	    rio_dprint(RIO_DEBUG_INTR, (" src_unit  = %d\n", PacketP->src_unit));
+	    rio_dprint(RIO_DEBUG_INTR, (" src_port  = %d\n", PacketP->src_port));
+	    rio_dprint(RIO_DEBUG_INTR, (" len	   = %d\n", PacketP->len));
+	    rio_dprint(RIO_DEBUG_INTR, (" control   = %d\n", PacketP->control));
+	    rio_dprint(RIO_DEBUG_INTR, (" csum	   = %d\n", PacketP->csum));
+	    rio_dprint(RIO_DEBUG_INTR, ("	 data bytes: "));
+	    for ( DataCnt=0; DataCnt<PKT_MAX_DATA_LEN; DataCnt++ )
+	      rio_dprint(RIO_DEBUG_INTR, ("%d\n", PacketP->data[DataCnt]));
+	    remove_receive( PortP );
+	    put_free_end( PortP->HostP, PacketP );
+	    continue; /* with next packet */
+	  }
+
+	  /*
+	  ** How many characters can we move 'upstream' ?
+	  **
+	  ** Determine the minimum of the amount of data
+	  ** available and the amount of space in which to
+	  ** put it.
+	  **
+	  ** 1.	Get the packet length by masking 'len'
+	  **	for only the length bits.
+	  ** 2.	Available space is [buffer size] - [space used]
+	  **
+	  ** Transfer count is the minimum of packet length
+	  ** and available space.
+	  */
+			
+	  transCount = min(PacketP->len & PKT_LEN_MASK,
+			   TTY_FLIPBUF_SIZE - TtyP->flip.count);
+	  rio_dprint(RIO_DEBUG_REC,  ("port %d: Copy %d bytes\n", 
+				      PortP->PortNum, transCount ) );
+	  /*
+	  ** To use the following 'kkprintfs' for debugging - change the '#undef'
+	  ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the
+	  ** driver).
+	  */
+#undef ___DEBUG_IT___
+#ifdef ___DEBUG_IT___
+	  kkprintf("I:%d R:%d P:%d Q:%d C:%d F:%x ",
+		   intCount,
+		   RxIntCnt,
+		   PortP->PortNum,
+		   TtyP->rxqueue.count,
+		   transCount,
+		   TtyP->flags );
+#endif
+	  ptr = (uchar *) PacketP->data + PortP->RxDataStart;
+
+	  rio_memcpy_fromio (TtyP->flip.char_buf_ptr, ptr, transCount);
+	  memset(TtyP->flip.flag_buf_ptr, TTY_NORMAL, transCount);
+
+#ifdef STATS
+	  /*
+	  ** keep a count for statistical purposes
+	  */
+	  PortP->Stat.RxCharCnt	+= transCount;
+#endif
+	  PortP->RxDataStart	+= transCount;
+	  PacketP->len		-= transCount;
+	  copied += transCount;
+	  TtyP->flip.count += transCount;
+	  TtyP->flip.char_buf_ptr += transCount;
+	  TtyP->flip.flag_buf_ptr += transCount;
+
+
+#ifdef ___DEBUG_IT___
+	  kkprintf("T:%d L:%d\n", DataCnt, PacketP->len );
+#endif
+
+	  if ( PacketP->len == 0 )
+	    {
+				/*
+				** If we have emptied the packet, then we can
+				** free it, and reset the start pointer for
+				** the next packet.
+				*/
+	      remove_receive( PortP );
+	      put_free_end( PortP->HostP, PacketP );
+	      PortP->RxDataStart = 0;
+#ifdef STATS
+				/*
+				** more lies ( oops, I mean statistics )
+				*/
+	      PortP->Stat.RxPktCnt++;
+#endif /* STATS */
+	    }
+	}
+    }
+  if (copied) {
+    rio_dprint ( RIO_DEBUG_REC, ("port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum,  copied));
+    tty_flip_buffer_push (TtyP);
+  }
+
+  return;
+}
+
+#ifdef FUTURE_RELEASE
+/*
+** The proc routine called by the line discipline to do the work for it.
+** The proc routine works hand in hand with the interrupt routine.
+*/
+int
+riotproc(p, tp, cmd, port)
+struct rio_info *	p;
+register struct ttystatics *tp;
+int cmd;
+int	port;
+{
+	register struct Port *PortP;
+	int SysPort;
+	struct PKT *PacketP;
+
+	SysPort = port;	/* Believe me, it works. */
+
+	if ( SysPort < 0 || SysPort >= RIO_PORTS ) {
+		rio_dprint(RIO_DEBUG_INTR, ("Illegal port %d derived from TTY in riotproc()\n",SysPort));
+		return 0;
+	}
+	PortP = p->RIOPortp[SysPort];
+
+	if ((uint)PortP->PhbP < (uint)PortP->Caddr || 
+			(uint)PortP->PhbP >= (uint)PortP->Caddr+SIXTY_FOUR_K ) {
+		rio_dprint(RIO_DEBUG_INTR, ("RIO: NULL or BAD PhbP on sys port %d in proc routine\n",
+							SysPort));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP = 0x%x\n",PortP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->PhbP = 0x%x\n",PortP->PhbP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->Caddr = 0x%x\n",PortP->PhbP));
+		rio_dprint(RIO_DEBUG_INTR, ("	 PortP->HostPort = 0x%x\n",PortP->HostPort));
+		return 0;
+	}
+
+	switch(cmd) {
+		case T_WFLUSH:
+			rio_dprint(RIO_DEBUG_INTR, "T_WFLUSH\n");
+			/*
+			** Because of the spooky way the RIO works, we don't need
+			** to issue a flush command on any of the SET*F commands,
+			** as that causes trouble with getty and login, which issue
+			** these commands to incur a READ flush, and rely on the fact
+			** that the line discipline does a wait for drain for them.
+			** As the rio doesn't wait for drain, the write flush would
+			** destroy the Password: prompt. This isn't very friendly, so
+			** here we only issue a WFLUSH command if we are in the interrupt
+			** routine, or we aren't executing a SET*F command.
+			*/
+			if ( PortP->HostP->InIntr || !PortP->FlushCmdBodge ) {
+				/*
+				** form a wflush packet - 1 byte long, no data
+				*/
+				if ( PortP->State & RIO_DELETED ) {
+					rio_dprint(RIO_DEBUG_INTR, ("WFLUSH on deleted RTA\n"));
+				}
+				else {
+					if ( RIOPreemptiveCmd(p, PortP, WFLUSH ) == RIO_FAIL ) {
+						rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command failed\n"));
+					}
+					else
+						rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command\n"));
+				}
+				/*
+				** WFLUSH operation - flush the data!
+				*/
+				PortP->TxBufferIn = PortP->TxBufferOut = 0;
+			}
+			else {
+				rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command ignored\n"));
+			}
+			/*
+			** sort out the line discipline
+			*/
+			if (PortP->CookMode == COOK_WELL)
+				goto start;
+			break;
+	
+		case T_RESUME:
+			rio_dprint(RIO_DEBUG_INTR, ("T_RESUME\n"));
+			/*
+			** send pre-emptive resume packet
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("RESUME on deleted RTA\n"));
+			}
+			else {
+				if ( RIOPreemptiveCmd(p, PortP, RESUME ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_RESUME Command failed\n"));
+				}
+			}
+			/*
+			** and re-start the sender software!
+			*/
+			if (PortP->CookMode == COOK_WELL)
+				goto start;
+			break;
+	
+		case T_TIME:
+			rio_dprint(RIO_DEBUG_INTR, ("T_TIME\n"));
+			/*
+			** T_TIME is called when xDLY is set in oflags and
+			** the line discipline timeout has expired. It's
+			** function in life is to clear the TIMEOUT flag
+			** and to re-start output to the port.
+			*/
+			/*
+			** Fall through and re-start output
+			*/
+		case T_OUTPUT:
+start:
+			if ( PortP->MagicFlags & MAGIC_FLUSH ) {
+				PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+				return 0;
+			}
+			RIOTxEnable((char *)PortP);
+			PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+			/*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"T_OUTPUT finished\n");*/
+			break;
+	
+		case T_SUSPEND:
+			rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND\n"));
+			/*
+			** send a suspend pre-emptive packet.
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("SUSPEND deleted RTA\n"));
+			}
+			else {
+				if ( RIOPreemptiveCmd(p, PortP, SUSPEND ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND Command failed\n"));
+				}
+			}
+			/*
+			** done!
+			*/
+			break;
+	
+		case T_BLOCK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_BLOCK\n"));
+			break;
+	
+		case T_RFLUSH:
+			rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH\n"));
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("RFLUSH on deleted RTA\n"));
+				PortP->RxDataStart = 0;
+			}
+			else {
+				if ( RIOPreemptiveCmd( p, PortP, RFLUSH ) == RIO_FAIL ) {
+					rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH Command failed\n"));
+					return 0;
+				}
+				PortP->RxDataStart = 0;
+				while ( can_remove_receive(&PacketP, PortP) ) {
+					remove_receive(PortP);
+					ShowPacket(DBG_PROC, PacketP );
+					put_free_end(PortP->HostP, PacketP );
+				}
+				if ( PortP->PhbP->handshake == PHB_HANDSHAKE_SET ) {
+					/*
+					** MAGIC!
+					*/
+					rio_dprint(RIO_DEBUG_INTR, ("Set receive handshake bit\n"));
+					PortP->PhbP->handshake |= PHB_HANDSHAKE_RESET;
+				}
+			}
+			break;
+			/* FALLTHROUGH */
+		case T_UNBLOCK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_UNBLOCK\n"));
+			/*
+			** If there is any data to receive set a timeout to service it.
+			*/
+			RIOReceive(p, PortP);
+			break;
+	
+		case T_BREAK:
+			rio_dprint(RIO_DEBUG_INTR, ("T_BREAK\n"));
+			/*
+			** Send a break command. For Sys V
+			** this is a timed break, so we
+			** send a SBREAK[time] packet
+			*/
+			/*
+			** Build a BREAK command
+			*/
+			if ( PortP->State & RIO_DELETED ) {
+				rio_dprint(RIO_DEBUG_INTR, ("BREAK on deleted RTA\n"));
+			}
+			else {
+				if (RIOShortCommand(PortP,SBREAK,2,
+								p->RIOConf.BreakInterval)==RIO_FAIL) {
+			   		rio_dprint(RIO_DEBUG_INTR, ("SBREAK RIOShortCommand failed\n"));
+				}
+			}
+	
+			/*
+			** done!
+			*/
+			break;
+	
+		case T_INPUT:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_INPUT called - I don't know what to do!\n"));
+			break;
+		case T_PARM:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_PARM called - I don't know what to do!\n"));
+			break;
+	
+		case T_SWTCH:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc T_SWTCH called - I don't know what to do!\n"));
+			break;
+	
+		default:
+			rio_dprint(RIO_DEBUG_INTR, ("Proc UNKNOWN command %d\n",cmd));
+	}
+	/*
+	** T_OUTPUT returns without passing through this point!
+	*/
+	/*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"riotproc done\n");*/
+	return(0);
+}
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioioctl.h linux/drivers/char/rio/rioioctl.h
--- v2.3.99-pre6/linux/drivers/char/rio/rioioctl.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioioctl.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,103 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioioctl.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rioioctl.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rioioctl_h__
+#define	__rioioctl_h__
+
+#ifdef SCCS_LABELS
+static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h	1.2";
+#endif
+
+/*
+** RIO device driver - user ioctls and associated structures.
+*/
+
+struct portStats {
+	int	port;
+	int	gather;
+	ulong	txchars;
+	ulong	rxchars;
+	ulong	opens;
+	ulong	closes;
+	ulong	ioctls;
+}; 
+
+
+#define rIOC	('r'<<8)
+#define	TCRIOSTATE	(rIOC | 1)
+#define	TCRIOXPON	(rIOC | 2)
+#define	TCRIOXPOFF	(rIOC | 3)
+#define	TCRIOXPCPS	(rIOC | 4)
+#define	TCRIOXPRINT	(rIOC | 5)
+#define TCRIOIXANYON	(rIOC | 6)
+#define	TCRIOIXANYOFF	(rIOC | 7)
+#define TCRIOIXONON	(rIOC | 8)
+#define	TCRIOIXONOFF	(rIOC | 9)
+#define	TCRIOMBIS	(rIOC | 10)
+#define	TCRIOMBIC	(rIOC | 11)
+#define	TCRIOTRIAD	(rIOC | 12)
+#define TCRIOTSTATE	(rIOC | 13)
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS
+** appears to not support hardware flow control).
+*/
+#define TCRIOCTSFLOWEN	(rIOC | 14)	/* enable CTS flow control */
+#define TCRIOCTSFLOWDIS	(rIOC | 15)	/* disable CTS flow control */
+#define TCRIORTSFLOWEN	(rIOC | 16)	/* enable RTS flow control */
+#define TCRIORTSFLOWDIS	(rIOC | 17)	/* disable RTS flow control */
+
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in daemon.h, so we'd better do a
+** #ifndef here first.
+** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now
+** allowed to be used by customers.
+**
+** 05.02.1999 ARG -
+** This is what I've decied to do with ioctls etc., which are intended to be
+** invoked from users applications :
+** Anything that needs to be defined here will be removed from daemon.h, that
+** way it won't end up having to be defined/maintained in two places. The only
+** consequence of this is that this file should now be #include'd by daemon.h
+**
+** 'stats' ioctls now #define'd here as they are to be used by customers.
+*/
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+
+#define	RIO_QUICK_CHECK	  	(RIOC | 105)
+#define RIO_GATHER_PORT_STATS	(RIOC | 193)
+#define RIO_RESET_PORT_STATS	(RIOC | 194)
+#define RIO_GET_PORT_STATS	(RIOC | 195)
+
+#endif	/* __rioioctl_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riolocks.h linux/drivers/char/rio/riolocks.h
--- v2.3.99-pre6/linux/drivers/char/rio/riolocks.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riolocks.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,43 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riolocks.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riolocks.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_riolocks_h__
+#define	__rio_riolocks_h__
+
+#ifdef SCCS_LABELS
+static char *_riolocks_h_sccs_ = "@(#)riolocks.h	1.2";
+#endif
+
+#define LOCKB(lk)		lockb(lk);
+#define UNLOCKB(lk, oldspl)	unlockb(lk, oldspl);
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioparam.c linux/drivers/char/rio/rioparam.c
--- v2.3.99-pre6/linux/drivers/char/rio/rioparam.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioparam.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,727 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioparam.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:45
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioparam.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifdef SCCS_LABELS
+static char *_rioparam_c_sccs_ = "@(#)rioparam.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+
+
+/*
+** The Scam, based on email from jeremyr@bugs.specialix.co.uk....
+**
+** To send a command on a particular port, you put a packet with the
+** command bit set onto the port. The command bit is in the len field,
+** and gets ORed in with the actual byte count.
+**
+** When you send a packet with the command bit set, then the first
+** data byte ( data[0] ) is interpretted as the command to execute.
+** It also governs what data structure overlay should accompany the packet.
+** Commands are defined in cirrus/cirrus.h
+**
+** If you want the command to pre-emt data already on the queue for the
+** port, set the pre-emptive bit in conjunction with the command bit.
+** It is not defined what will happen if you set the preemptive bit
+** on a packet that is NOT a command.
+**
+** Pre-emptive commands should be queued at the head of the queue using
+** add_start(), whereas normal commands and data are enqueued using
+** add_end().
+**
+** Most commands do not use the remaining bytes in the data array. The
+** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and
+** OPEN are currently analagous). With these three commands the following
+** 11 data bytes are all used to pass config information such as baud rate etc.
+** The fields are also defined in cirrus.h. Some contain straightforward
+** information such as the transmit XON character. Two contain the transmit and
+** receive baud rates respectively. For most baud rates there is a direct
+** mapping between the rates defined in <sys/termio.h> and the byte in the
+** packet. There are additional (non UNIX-standard) rates defined in
+** /u/dos/rio/cirrus/h/brates.h.
+**
+** The rest of the data fields contain approximations to the Cirrus registers
+** that are used to program number of bits etc. Each registers bit fields is
+** defined in cirrus.h.
+** 
+** NB. Only use those bits that are defined as being driver specific
+** or common to the RTA and the driver.
+** 
+** All commands going from RTA->Host will be dealt with by the Host code - you
+** will never see them. As with the SI there will be three fields to look out
+** for in each phb (not yet defined - needs defining a.s.a.p).
+** 
+** modem_status	- current state of handshake pins.
+**
+** port_status	 - current port status - equivalent to hi_stat for SI, indicates
+** if port is IDLE_OPEN, IDLE_CLOSED etc.
+**
+** break_status	- bit X set if break has been received.
+** 
+** Happy hacking.
+** 
+*/
+
+/* 
+** RIOParam is used to open or configure a port. You pass it a PortP,
+** which will have a tty struct attached to it. You also pass a command,
+** either OPEN or CONFIG. The port's setup is taken from the t_ fields
+** of the tty struct inside the PortP, and the port is either opened
+** or re-configured. You must also tell RIOParam if the device is a modem
+** device or not (i.e. top bit of minor number set or clear - take special
+** care when deciding on this!).
+** RIOParam neither flushes nor waits for drain, and is NOT preemptive.
+**
+** RIOParam assumes it will be called at splrio(), and also assumes
+** that CookMode is set correctly in the port structure.
+**
+** NB. for MPX
+**	tty lock must NOT have been previously acquired.
+*/
+int
+RIOParam(PortP, cmd, Modem, SleepFlag)
+struct Port *PortP;
+int cmd;
+int Modem;
+int SleepFlag; 
+{
+	register struct tty_struct *TtyP;
+	int	retval;
+	register struct phb_param *phb_param_ptr;
+	PKT *PacketP;
+	int res;
+	uchar Cor1=0, Cor2=0, Cor4=0, Cor5=0;
+	uchar TxXon=0, TxXoff=0, RxXon=0, RxXoff=0;
+	uchar LNext=0, TxBaud=0, RxBaud=0;
+	int		retries = 0xff;
+	unsigned long flags;
+
+	TtyP = PortP->gs.tty;
+
+	rio_dprint(RIO_DEBUG_PARAM, ("RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n",
+	    PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP) );
+
+	if (!TtyP) {
+	  rio_dprint (RIO_DEBUG_PARAM, ("Can't call rioparam with null tty.\n"));
+	  return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags );
+
+	if (cmd == OPEN) {
+		/*
+		** If the port is set to store or lock the parameters, and it is
+		** paramed with OPEN, we want to restore the saved port termio, but
+		** only if StoredTermio has been saved, i.e. NOT 1st open after reboot.
+		*/
+#if 0
+		if (PortP->FirstOpen) {
+			PortP->StoredTty.iflag = TtyP->tm.c_iflag;
+			PortP->StoredTty.oflag = TtyP->tm.c_oflag;
+			PortP->StoredTty.cflag = TtyP->tm.c_cflag;
+			PortP->StoredTty.lflag = TtyP->tm.c_lflag;
+			PortP->StoredTty.line = TtyP->tm.c_line;
+			for (i = 0; i < NCC + 5; i++)
+				PortP->StoredTty.cc[i] = TtyP->tm.c_cc[i];
+			PortP->FirstOpen = 0;
+		}
+		else if (PortP->Store || PortP->Lock) {
+			rio_dprint(RIO_DEBUG_PARAM, ("OPEN: Restoring stored/locked params\n"));
+			TtyP->tm.c_iflag = PortP->StoredTty.iflag;
+			TtyP->tm.c_oflag = PortP->StoredTty.oflag;
+			TtyP->tm.c_cflag = PortP->StoredTty.cflag;
+			TtyP->tm.c_lflag = PortP->StoredTty.lflag;
+			TtyP->tm.c_line = PortP->StoredTty.line;
+			for (i = 0; i < NCC + 5; i++)
+				TtyP->tm.c_cc[i] = PortP->StoredTty.cc[i];
+		}
+#endif
+	}
+
+	/*
+	** wait for space
+	*/
+	while ( !(res=can_add_transmit(&PacketP,PortP)) || 
+			(PortP->InUse != NOT_INUSE) ) {
+		if (retries -- <= 0) {
+			break;
+		}
+		if ( PortP->InUse != NOT_INUSE ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Port IN_USE for pre-emptive command\n"));
+		}
+
+		if ( !res ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Port has no space on transmit queue\n"));
+		}
+
+		if ( SleepFlag != OK_TO_SLEEP ) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			return RIO_FAIL;
+		}
+
+		rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit\n"));
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		retval = RIODelay(PortP, HUNDRED_MS);
+		rio_spin_lock_irqsave( &PortP->portSem, flags);
+		if (retval == RIO_FAIL) {
+			rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit broken by signal\n"));
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			pseterr(EINTR);
+			return RIO_FAIL;
+		}
+		if ( PortP->State & RIO_DELETED ) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			return RIO_SUCCESS;
+		}
+	}
+
+	if (!res) {
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	rio_dprint(RIO_DEBUG_PARAM, ("can_add_transmit() returns %x\n",res));
+	rio_dprint(RIO_DEBUG_PARAM, ("Packet is 0x%x\n",(int) PacketP));
+
+	phb_param_ptr = (struct phb_param *)PacketP->data;
+
+
+#if 0
+	/*
+	** COR 1
+	*/
+	if ( TtyP->tm.c_iflag & INPCK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Parity checking on input enabled\n"));
+		Cor1 |= COR1_INPCK;
+	}
+#endif
+
+	switch ( TtyP->termios->c_cflag & CSIZE ) {
+		case CS5:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("5 bit data\n"));
+			Cor1 |= COR1_5BITS;
+			break;
+		}
+		case CS6:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("6 bit data\n"));
+			Cor1 |= COR1_6BITS;
+			break;
+		}
+		case CS7:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("7 bit data\n"));
+			Cor1 |= COR1_7BITS;
+			break;
+		}
+		case CS8:
+		{
+			rio_dprint(RIO_DEBUG_PARAM, ("8 bit data\n"));
+			Cor1 |= COR1_8BITS;
+			break;
+		}
+	}
+
+	if ( TtyP->termios->c_cflag & CSTOPB ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("2 stop bits\n"));
+		Cor1 |= COR1_2STOP;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("1 stop bit\n"));
+		Cor1 |= COR1_1STOP;
+	}
+
+	if ( TtyP->termios->c_cflag & PARENB ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable parity\n"));
+		Cor1 |= COR1_NORMAL;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Disable parity\n"));
+		Cor1 |= COR1_NOP;
+	}
+	if ( TtyP->termios->c_cflag & PARODD ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Odd parity\n"));
+		Cor1 |= COR1_ODD;
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Even parity\n"));
+		Cor1 |= COR1_EVEN; 
+	}
+
+	/*
+	** COR 2
+	*/
+	if ( TtyP->termios->c_iflag & IXON ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop output control\n"));
+		Cor2 |= COR2_IXON;
+	}
+	else {
+		if ( PortP->Config & RIO_IXON ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Force enable start/stop output control\n"));
+			Cor2 |= COR2_IXON;
+		}
+		else
+			rio_dprint(RIO_DEBUG_PARAM, ("IXON has been disabled.\n"));
+	}
+
+	if (TtyP->termios->c_iflag & IXANY) {
+		if ( PortP->Config & RIO_IXANY ) {
+			rio_dprint(RIO_DEBUG_PARAM, ("Enable any key to restart output\n"));
+			Cor2 |= COR2_IXANY;
+		}
+		else
+			rio_dprint(RIO_DEBUG_PARAM, ("IXANY has been disabled due to sanity reasons.\n"));
+	}
+
+	if ( TtyP->termios->c_iflag & IXOFF ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop input control 2\n"));
+		Cor2 |= COR2_IXOFF;
+	}
+
+	if ( TtyP->termios->c_cflag & HUPCL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Hangup on last close\n"));
+		Cor2 |= COR2_HUPCL;
+	}
+
+	if ( C_CRTSCTS (TtyP)) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control enabled\n"));
+		Cor2 |= COR2_CTSFLOW;
+		Cor2 |= COR2_RTSFLOW;
+	} else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control disabled\n"));
+		Cor2 &= ~COR2_CTSFLOW;
+		Cor2 &= ~COR2_RTSFLOW;
+	}
+
+
+	if ( TtyP->termios->c_cflag & CLOCAL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Local line\n"));
+	}
+	else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Possible Modem line\n"));
+	}
+
+	/*
+	** COR 4 (there is no COR 3)
+	*/
+	if ( TtyP->termios->c_iflag & IGNBRK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore break condition\n"));
+		Cor4 |= COR4_IGNBRK;
+	}
+	if ( !(TtyP->termios->c_iflag & BRKINT) ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Break generates NULL condition\n"));
+		Cor4 |= COR4_NBRKINT;
+	} else {
+		rio_dprint(RIO_DEBUG_PARAM, ("Interrupt on	break condition\n"));
+	}
+
+	if ( TtyP->termios->c_iflag & INLCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage return on input\n"));
+		Cor4 |= COR4_INLCR;
+	}
+
+	if ( TtyP->termios->c_iflag & IGNCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore carriage return on input\n"));
+		Cor4 |= COR4_IGNCR;
+	}
+
+	if ( TtyP->termios->c_iflag & ICRNL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on input\n"));
+		Cor4 |= COR4_ICRNL;
+	}
+	if ( TtyP->termios->c_iflag & IGNPAR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Ignore characters with parity errors\n"));
+		Cor4 |= COR4_IGNPAR;
+	}
+	if ( TtyP->termios->c_iflag & PARMRK ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Mark parity errors\n"));
+		Cor4 |= COR4_PARMRK;
+	}
+
+	/*
+	** Set the RAISEMOD flag to ensure that the modem lines are raised
+	** on reception of a config packet.
+	** The download code handles the zero baud condition.
+	*/
+	Cor4 |= COR4_RAISEMOD;
+
+	/*
+	** COR 5
+	*/
+
+	Cor5 = COR5_CMOE;
+
+	/*
+	** Set to monitor tbusy/tstop (or not).
+	*/
+
+	if (PortP->MonitorTstate)
+		Cor5 |= COR5_TSTATE_ON;
+	else
+		Cor5 |= COR5_TSTATE_OFF;
+
+	/*
+	** Could set LNE here if you wanted LNext processing. SVR4 will use it.
+	*/
+	if ( TtyP->termios->c_iflag & ISTRIP ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Strip input characters\n"));
+		if (! (PortP->State & RIO_TRIAD_MODE)) {
+			Cor5 |= COR5_ISTRIP;
+		}
+	}
+
+	if ( TtyP->termios->c_oflag & ONLCR ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage-return, newline on output\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_ONLCR;
+	}
+	if ( TtyP->termios->c_oflag & OCRNL ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on output\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_OCRNL;
+	}
+	if ( ( TtyP->termios->c_oflag & TABDLY) == TAB3 ) {
+		rio_dprint(RIO_DEBUG_PARAM, ("Tab delay 3 set\n"));
+		if ( PortP->CookMode == COOK_MEDIUM )
+			Cor5 |= COR5_TAB3;
+	}
+
+	/*
+	** Flow control bytes.
+	*/
+	TxXon = TtyP->termios->c_cc[VSTART];
+	TxXoff = TtyP->termios->c_cc[VSTOP];
+	RxXon = TtyP->termios->c_cc[VSTART];
+	RxXoff = TtyP->termios->c_cc[VSTOP];
+	/*
+	** LNEXT byte
+	*/
+	LNext = 0;
+
+	/*
+	** Baud rate bytes
+	*/
+	rio_dprint(RIO_DEBUG_PARAM, ("Mapping of rx/tx baud %x (%x)\n", 
+				     TtyP->termios->c_cflag, CBAUD));
+
+	switch (TtyP->termios->c_cflag & CBAUD) {
+#define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break
+	  e(50);e(75);e(110);e(134);e(150);e(200);e(300);e(600);e(1200);
+	  e(1800);e(2400);e(4800);e(9600);e(19200);e(38400);e(57600);
+	  e(115200); /* e(230400);e(460800); e(921600);  */
+	}
+
+	/* XXX MIssing conversion table. XXX */
+	/* 	 (TtyP->termios->c_cflag & V_CBAUD); */
+
+	rio_dprint(RIO_DEBUG_PARAM, ("tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud));
+
+
+	/*
+	** Leftovers
+	*/
+	if ( TtyP->termios->c_cflag & CREAD )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable receiver\n"));
+#ifdef RCV1EN
+	if ( TtyP->termios->c_cflag & RCV1EN )
+		rio_dprint(RIO_DEBUG_PARAM, ("RCV1EN (?)\n"));
+#endif
+#ifdef XMT1EN
+	if ( TtyP->termios->c_cflag & XMT1EN )
+		rio_dprint(RIO_DEBUG_PARAM, ("XMT1EN (?)\n"));
+#endif
+#if 0
+	if ( TtyP->termios->c_cflag & LOBLK )
+		rio_dprint(RIO_DEBUG_PARAM, ("LOBLK - JCL output blocks when not current\n"));
+#endif
+	if ( TtyP->termios->c_lflag & ISIG )
+		rio_dprint(RIO_DEBUG_PARAM, ("Input character signal generating enabled\n"));
+	if ( TtyP->termios->c_lflag & ICANON )
+		rio_dprint(RIO_DEBUG_PARAM, ("Canonical input: erase and kill enabled\n"));
+	if ( TtyP->termios->c_lflag & XCASE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Canonical upper/lower presentation\n"));
+	if ( TtyP->termios->c_lflag & ECHO )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable input echo\n"));
+	if ( TtyP->termios->c_lflag & ECHOE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo erase\n"));
+	if ( TtyP->termios->c_lflag & ECHOK )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo kill\n"));
+	if ( TtyP->termios->c_lflag & ECHONL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable echo newline\n"));
+	if ( TtyP->termios->c_lflag & NOFLSH )
+		rio_dprint(RIO_DEBUG_PARAM, ("Disable flush after interrupt or quit\n"));
+#ifdef TOSTOP
+	if ( TtyP->termios->c_lflag & TOSTOP )
+		rio_dprint(RIO_DEBUG_PARAM, ("Send SIGTTOU for background output\n"));
+#endif
+#ifdef XCLUDE
+	if ( TtyP->termios->c_lflag & XCLUDE )
+		rio_dprint(RIO_DEBUG_PARAM, ("Exclusive use of this line\n"));
+#endif
+	if ( TtyP->termios->c_iflag & IUCLC )
+		rio_dprint(RIO_DEBUG_PARAM, ("Map uppercase to lowercase on input\n"));
+	if ( TtyP->termios->c_oflag & OPOST )
+		rio_dprint(RIO_DEBUG_PARAM, ("Enable output post-processing\n"));
+	if ( TtyP->termios->c_oflag & OLCUC )
+		rio_dprint(RIO_DEBUG_PARAM, ("Map lowercase to uppercase on output\n"));
+	if ( TtyP->termios->c_oflag & ONOCR )
+		rio_dprint(RIO_DEBUG_PARAM, ("No carriage return output at column 0\n"));
+	if ( TtyP->termios->c_oflag & ONLRET )
+		rio_dprint(RIO_DEBUG_PARAM, ("Newline performs carriage return function\n"));
+	if ( TtyP->termios->c_oflag & OFILL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Use fill characters for delay\n"));
+	if ( TtyP->termios->c_oflag & OFDEL )
+		rio_dprint(RIO_DEBUG_PARAM, ("Fill character is DEL\n"));
+	if ( TtyP->termios->c_oflag & NLDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Newline delay set\n"));
+	if ( TtyP->termios->c_oflag & CRDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Carriage return delay set\n"));
+	if ( TtyP->termios->c_oflag & TABDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Tab delay set\n"));
+#if 0
+	if ( TtyP->termios->c_oflag & BSDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Back-space delay set\n"));
+	if ( TtyP->termios->c_oflag & VTDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Vertical tab delay set\n"));
+	if ( TtyP->termios->c_oflag & FFDLY )
+		rio_dprint(RIO_DEBUG_PARAM, ("Form-feed delay set\n"));
+#endif
+	/*
+	** These things are kind of useful in a later life!
+	*/
+	PortP->Cor2Copy = Cor2;
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	/*
+	** Actually write the info into the packet to be sent
+	*/
+	WBYTE(phb_param_ptr->Cmd,	cmd);
+	WBYTE(phb_param_ptr->Cor1,	 Cor1);
+	WBYTE(phb_param_ptr->Cor2,	 Cor2);
+	WBYTE(phb_param_ptr->Cor4,	 Cor4);
+	WBYTE(phb_param_ptr->Cor5,	 Cor5);
+	WBYTE(phb_param_ptr->TxXon,	TxXon);
+	WBYTE(phb_param_ptr->RxXon,	RxXon);
+	WBYTE(phb_param_ptr->TxXoff, TxXoff);
+	WBYTE(phb_param_ptr->RxXoff, RxXoff);
+	WBYTE(phb_param_ptr->LNext,	LNext);
+	WBYTE(phb_param_ptr->TxBaud, TxBaud);
+	WBYTE(phb_param_ptr->RxBaud, RxBaud);
+
+	/*
+	** Set the length/command field
+	*/
+	WBYTE(PacketP->len , 12 | PKT_CMD_BIT);
+
+	/*
+	** The packet is formed - now, whack it off
+	** to its final destination:
+	*/
+	add_transmit(PortP);
+	/*
+	** Count characters transmitted for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->txchars += 12;
+
+	rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+
+	rio_dprint(RIO_DEBUG_PARAM, ("add_transmit returned.\n"));
+	/*
+	** job done.
+	*/
+	return RIO_SUCCESS;
+}
+
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+int
+can_add_transmit(PktP, PortP)
+PKT **PktP;
+struct Port *PortP; 
+{
+	register PKT *tp;
+
+	*PktP = tp = (PKT *)RIO_PTR(PortP->Caddr,RWORD(*PortP->TxAdd));
+
+	return !((uint)tp & PKT_IN_USE);
+}
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+void
+add_transmit(PortP)
+struct Port *PortP; 
+{
+  if (RWORD(*PortP->TxAdd) & PKT_IN_USE) {
+    rio_dprint (RIO_DEBUG_PARAM, ("add_transmit: Packet has been stolen!"));
+  }
+	WWORD( *(ushort *)PortP->TxAdd, RWORD(*PortP->TxAdd) | PKT_IN_USE);
+	PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : 
+					PortP->TxAdd + 1;
+	WWORD( PortP->PhbP->tx_add , RIO_OFF(PortP->Caddr,PortP->TxAdd) );
+}
+
+/****************************************
+ * Put a packet onto the end of the
+ * free list
+ ****************************************/
+void
+put_free_end(HostP, PktP)
+struct Host *HostP;
+PKT *PktP;
+{
+	FREE_LIST *tmp_pointer;
+	ushort old_end, new_end;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+	 /*************************************************
+	* Put a packet back onto the back of the free list
+	*
+	************************************************/
+
+	rio_dprint(RIO_DEBUG_PFE, ("put_free_end(PktP=%x)\n",(int)PktP));
+
+	if ((old_end=RWORD(HostP->ParmMapP->free_list_end)) != TPNULL) {
+		new_end = RIO_OFF(HostP->Caddr,PktP);
+		tmp_pointer = (FREE_LIST *)RIO_PTR(HostP->Caddr,old_end);
+		WWORD(tmp_pointer->next , new_end );
+		WWORD(((FREE_LIST *)PktP)->prev , old_end);
+		WWORD(((FREE_LIST *)PktP)->next , TPNULL);
+		WWORD(HostP->ParmMapP->free_list_end, new_end);
+	}
+	else {	/* First packet on the free list this should never happen! */
+		rio_dprint(RIO_DEBUG_PFE, ("put_free_end(): This should never happen\n"));
+		WWORD(HostP->ParmMapP->free_list_end , RIO_OFF(HostP->Caddr,PktP));
+		tmp_pointer = (FREE_LIST *)PktP;
+		WWORD(tmp_pointer->prev , TPNULL);
+		WWORD(tmp_pointer->next , TPNULL);
+	}
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+}
+
+/*
+** can_remove_receive(PktP,P) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PktP to point to the
+** relevent packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+int
+can_remove_receive(PktP, PortP)
+PKT **PktP;
+struct Port *PortP;
+{
+	if ( RWORD(*PortP->RxRemove) & PKT_IN_USE) {
+		*PktP = (PKT *)RIO_PTR(PortP->Caddr,
+					RWORD(*PortP->RxRemove) & ~PKT_IN_USE);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+** To remove a packet from the receive queue you clear its PKT_IN_USE bit,
+** and then bump the pointers. Once the pointers get to the end, they must
+** be wrapped back to the start.
+*/
+void
+remove_receive(PortP)
+struct Port *PortP; 
+{
+	WWORD( *PortP->RxRemove, RWORD(*PortP->RxRemove) & ~PKT_IN_USE );
+	PortP->RxRemove = (PortP->RxRemove == PortP->RxEnd) ? PortP->RxStart : 
+								PortP->RxRemove + 1;
+	WWORD( PortP->PhbP->rx_remove , RIO_OFF(PortP->Caddr, PortP->RxRemove) );
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riopcicopy.c linux/drivers/char/rio/riopcicopy.c
--- v2.3.99-pre6/linux/drivers/char/rio/riopcicopy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riopcicopy.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,8 @@
+
+/* Yeah. We have copyright on this one. Sure. */
+
+void rio_pcicopy( char *from, char *to, int amount)
+{
+  while ( amount-- )
+    *to++ = *from++;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rioroute.c linux/drivers/char/rio/rioroute.c
--- v2.3.99-pre6/linux/drivers/char/rio/rioroute.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rioroute.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1233 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: rioroute.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:46
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioroute.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_rioroute_c_sccs_ = "@(#)rioroute.c	1.3";
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+/*
+** Incoming on the ROUTE_RUP
+** I wrote this while I was tired. Forgive me.
+*/
+int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP )
+{
+  struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data;
+  struct PktCmd_M *PktReplyP;
+  struct CmdBlk *CmdBlkP;
+  struct Port *PortP;
+  struct Map *MapP;
+  struct Top *TopP;
+  int ThisLink, ThisLinkMin, ThisLinkMax;
+  int port;
+  int Mod, Mod1, Mod2;
+  ushort RtaType;
+  uint RtaUniq;
+  uint ThisUnit, ThisUnit2;	/* 2 ids to accommodate 16 port RTA */
+  uint OldUnit, NewUnit, OldLink, NewLink;
+  char *MyType, *MyName;
+  int Lies;
+  unsigned long flags;
+
+#ifdef STACK
+    RIOStackCheck("RIORouteRup");
+#endif
+#ifdef CHECK
+    CheckPacketP(PacketP);
+    CheckHostP(HostP);
+    CheckRup(Rup);
+    CheckHost(Host);
+#endif
+  /*
+  ** Is this unit telling us it's current link topology?
+  */
+  if ( RBYTE(PktCmdP->Command) == ROUTE_TOPOLOGY )
+  {
+    MapP = HostP->Mapping;
+
+    /*
+    ** The packet can be sent either by the host or by an RTA.
+    ** If it comes from the host, then we need to fill in the
+    ** Topology array in the host structure. If it came in
+    ** from an RTA then we need to fill in the Mapping structure's
+    ** Topology array for the unit.
+    */
+    if ( Rup >= (ushort)MAX_RUP )
+    {
+      ThisUnit = HOST_ID;
+      TopP = HostP->Topology;
+      MyType = "Host";
+      MyName = HostP->Name;
+      ThisLinkMin = ThisLinkMax = Rup - MAX_RUP;
+    }
+    else
+    {
+      ThisUnit = Rup+1;
+      TopP = HostP->Mapping[Rup].Topology;
+      MyType = "RTA";
+      MyName = HostP->Mapping[Rup].Name;
+      ThisLinkMin = 0;
+      ThisLinkMax = LINKS_PER_UNIT - 1;
+    }
+
+    /*
+    ** Lies will not be tolerated.
+    ** If any pair of links claim to be connected to the same
+    ** place, then ignore this packet completely.
+    */
+    Lies = 0;
+    for ( ThisLink=ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++)
+    {
+      /*
+      ** it won't lie about network interconnect, total disconnects
+      ** and no-IDs. (or at least, it doesn't *matter* if it does)
+      */
+      if ( RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) > (ushort)MAX_RUP )
+	  continue;
+
+      for ( NewLink=ThisLinkMin; NewLink < ThisLink; NewLink++ )
+      {
+        if ( (RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) ==
+              RBYTE(PktCmdP->RouteTopology[NewLink].Unit)) &&
+	     (RBYTE(PktCmdP->RouteTopology[ThisLink].Link) ==
+              RBYTE(PktCmdP->RouteTopology[NewLink].Link)) )
+	{
+          Lies++;
+	}
+      }
+    }
+
+    if ( Lies )
+    {
+      rio_dprint(RIO_DEBUG_ROUTE, ("LIES! DAMN LIES! %d LIES!\n",Lies));
+      rio_dprint(RIO_DEBUG_ROUTE, ("%d:%c %d:%c %d:%c %d:%c\n",
+          RBYTE(PktCmdP->RouteTopology[0].Unit), 
+	  'A'+RBYTE(PktCmdP->RouteTopology[0].Link),
+          RBYTE(PktCmdP->RouteTopology[1].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[1].Link),
+          RBYTE(PktCmdP->RouteTopology[2].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[2].Link),
+          RBYTE(PktCmdP->RouteTopology[3].Unit),
+	  'A'+RBYTE(PktCmdP->RouteTopology[3].Link)));
+      return TRUE;
+    }
+
+    /*
+    ** now, process each link.
+    */
+    for ( ThisLink=ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++)
+    {
+      /*
+      ** this is what it was connected to
+      */
+      OldUnit = TopP[ThisLink].Unit;
+      OldLink = TopP[ThisLink].Link;
+
+      /*
+      ** this is what it is now connected to
+      */
+      NewUnit = RBYTE(PktCmdP->RouteTopology[ThisLink].Unit);
+      NewLink = RBYTE(PktCmdP->RouteTopology[ThisLink].Link);
+
+      if ( OldUnit != NewUnit || OldLink != NewLink )
+      {
+	/*
+	** something has changed!
+	*/
+
+        if ( NewUnit > MAX_RUP &&
+	     NewUnit != ROUTE_DISCONNECT &&
+	     NewUnit != ROUTE_NO_ID &&
+	     NewUnit != ROUTE_INTERCONNECT )
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("I have a link from %s %s to unit %d:%d - I don't like it.\n",
+		  MyType,
+		  MyName,
+		  NewUnit,
+		  NewLink));
+	}
+	else
+	{
+	  /*
+	  ** put the new values in
+	  */
+	  TopP[ThisLink].Unit = NewUnit;
+	  TopP[ThisLink].Link = NewLink;
+
+	  RIOSetChange(p);
+
+	  if ( OldUnit <= MAX_RUP )
+	  {
+	    /*
+	    ** If something has become bust, then re-enable them messages
+	    */
+	    if (! p->RIONoMessage)
+		RIOConCon(p,HostP,ThisUnit,ThisLink,OldUnit,OldLink,DISCONNECT);
+	  }
+
+	  if ( ( NewUnit <= MAX_RUP ) && !p->RIONoMessage )
+	    RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT);
+
+	  if ( NewUnit == ROUTE_NO_ID )
+	    rio_dprint(RIO_DEBUG_ROUTE, ("%s %s (%c) is connected to an unconfigured unit.\n",
+		    MyType,MyName,'A'+ThisLink));
+
+	  if ( NewUnit == ROUTE_INTERCONNECT )
+	  {
+	    if (! p->RIONoMessage)
+		cprintf("%s '%s' (%c) is connected to another network.\n", MyType,MyName,'A'+ThisLink);
+	  }
+
+	  /*
+	  ** perform an update for 'the other end', so that these messages
+	  ** only appears once. Only disconnect the other end if it is pointing
+	  ** at us!
+	  */
+	  if ( OldUnit == HOST_ID )
+	  {
+	    if ( HostP->Topology[OldLink].Unit == ThisUnit &&
+		 HostP->Topology[OldLink].Link == ThisLink )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'));
+	      HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT;
+	      HostP->Topology[OldLink].Link = NO_LINK;
+	    }
+	    else
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n",
+		    OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'));
+	    }
+	  }
+	  else if ( OldUnit <= MAX_RUP )
+	  {
+	    if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit &&
+	         HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("SETTING RTA %s (%c) TO DISCONNECTED!\n",
+				   HostP->Mapping[OldUnit-1].Name,OldLink+'A'));
+	      HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT;
+	      HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK;
+	    }
+	    else
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n",
+			    HostP->Mapping[OldUnit-1].Name,OldLink+'A',
+			    HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'));
+	    }
+	  }
+	  if ( NewUnit == HOST_ID )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("MARKING HOST (%c) CONNECTED TO %s (%c)\n",
+				NewLink+'A',MyName,ThisLink+'A'));
+	    HostP->Topology[NewLink].Unit = ThisUnit;
+	    HostP->Topology[NewLink].Link = ThisLink;
+	  }
+	  else if ( NewUnit <= MAX_RUP )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("MARKING RTA %s (%c) CONNECTED TO %s (%c)\n",
+	      HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'));
+	    HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit;
+	    HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink;
+	  }
+	}
+	RIOSetChange(p);
+	RIOCheckIsolated(p, HostP, OldUnit );
+      }
+    }
+    return TRUE;
+  }
+
+  /*
+  ** The only other command we recognise is a route_request command
+  */
+  if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("Unknown command %d received on rup %d host %d ROUTE_RUP\n", 
+	   RBYTE(PktCmdP->Command),Rup,(int)HostP));
+    return TRUE;
+  }
+      
+  RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) +
+	    (RBYTE(PktCmdP->UniqNum[1]) << 8) +
+	    (RBYTE(PktCmdP->UniqNum[2]) << 16) +
+	    (RBYTE(PktCmdP->UniqNum[3]) << 24);
+
+  /*
+  ** Determine if 8 or 16 port RTA
+  */
+  RtaType = GetUnitType(RtaUniq);
+
+  rio_dprint(RIO_DEBUG_ROUTE, ("Received a request for an ID for serial number %x\n", RtaUniq));
+
+  Mod = RBYTE(PktCmdP->ModuleTypes);
+  Mod1 = LONYBLE(Mod);
+  if (RtaType == TYPE_RTA16)
+  {
+    /*
+    ** Only one ident is set for a 16 port RTA. To make compatible
+    ** with 8 port, set 2nd ident in Mod2 to the same as Mod1.
+    */
+    Mod2 = Mod1;
+    rio_dprint(RIO_DEBUG_ROUTE, ("Backplane type is %s (all ports)\n",
+     p->RIOModuleTypes[Mod1].Name ));
+  }
+  else
+  {
+    Mod2 = HINYBLE(Mod);
+    rio_dprint(RIO_DEBUG_ROUTE, ("Module types are %s (ports 0-3) and %s (ports 4-7)\n",
+     p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name ));
+  }
+
+  if ( RtaUniq == 0xffffffff )
+  {
+      ShowPacket( DBG_SPECIAL, PacketP );
+  }
+
+  /*
+  ** try to unhook a command block from the command free list.
+  */
+  if ( !(CmdBlkP = RIOGetCmdBlk()) )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("No command blocks to route RTA! come back later.\n"));
+    return 0;
+  }
+
+  /*
+  ** Fill in the default info on the command block
+  */
+  CmdBlkP->Packet.dest_unit = Rup;
+  CmdBlkP->Packet.dest_port = ROUTE_RUP;
+  CmdBlkP->Packet.src_unit = HOST_ID;
+  CmdBlkP->Packet.src_port = ROUTE_RUP;
+  CmdBlkP->Packet.len = PKT_CMD_BIT | 1;
+  CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+  PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data;
+
+  if (! RIOBootOk(p, HostP, RtaUniq))
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("RTA %x tried to get an ID, but does not belong - FOAD it!\n",
+	  RtaUniq));
+    PktReplyP->Command = ROUTE_FOAD;
+    HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7);
+    RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+    return TRUE;
+  }
+
+  /*
+  ** Check to see if the RTA is configured for this host
+  */
+  for ( ThisUnit=0; ThisUnit<MAX_RUP; ThisUnit++ )
+  {
+    rio_dprint(RIO_DEBUG_ROUTE, ("Entry %d Flags=%s %s UniqueNum=0x%x\n",
+			ThisUnit,
+			HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ?
+					    "Slot-In-Use":"Not In Use",
+			HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? 
+					    "Slot-Tentative":"Not Tentative",
+			HostP->Mapping[ThisUnit].RtaUniqueNum ));
+
+    /*
+    ** We have an entry for it.
+    */
+    if ( (HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) &&
+         (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq) )
+    {
+      if (RtaType == TYPE_RTA16)
+      {
+	  ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1;
+          rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slots %d+%d\n",
+					    RtaUniq,ThisUnit,ThisUnit2));
+      }
+      else
+          rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slot %d\n",
+					    RtaUniq,ThisUnit));
+      /*
+      ** If we have no knowledge of booting it, then the host has
+      ** been re-booted, and so we must kill the RTA, so that it
+      ** will be booted again (potentially with new bins)
+      ** and it will then re-ask for an ID, which we will service.
+      */
+      if ( (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && 
+	  !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED) )
+      {
+	if ( !(HostP->Mapping[ThisUnit].Flags & MSG_DONE) )
+	{
+	    if ( !p->RIONoMessage )
+	        cprintf("RTA '%s' is being updated.\n",HostP->Mapping[ThisUnit].Name);
+	    HostP->Mapping[ThisUnit].Flags |= MSG_DONE;
+	}
+	PktReplyP->Command = ROUTE_FOAD;
+	HostP->Copy("RT_FOAD",PktReplyP->CommandText,7);
+	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+	return TRUE;
+      }
+
+      /*
+      ** Send the ID (entry) to this RTA. The ID number is implicit as
+      ** the offset into the table. It is worth noting at this stage
+      ** that offset zero in the table contains the entries for the
+      ** RTA with ID 1!!!!
+      */
+      PktReplyP->Command = ROUTE_ALLOCATE;
+      PktReplyP->IDNum   = ThisUnit+1;
+      if (RtaType == TYPE_RTA16)
+      {
+        if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)
+	    /*
+	    ** Adjust the phb and tx pkt dest_units for 2nd block of 8
+	    ** only if the RTA has ports associated (SLOT_IN_USE)
+	    */
+	    RIOFixPhbs(p, HostP, ThisUnit2);
+	    PktReplyP->IDNum2  = ThisUnit2+1;
+	    rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated IDs %d+%d\n",
+	          HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2));
+      }
+      else
+      {
+	    PktReplyP->IDNum2 = ROUTE_NO_ID;
+	    rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated ID %d\n",
+	          HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum));
+      }
+      HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10);
+
+      RIOQueueCmdBlk( HostP, Rup, CmdBlkP);
+
+      /*
+      ** If this is a freshly booted RTA, then we need to re-open
+      ** the ports, if any where open, so that data may once more
+      ** flow around the system!
+      */
+      if ( (HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) &&
+	   (HostP->Mapping[ThisUnit].SysPort != NO_PORT) )
+      {
+	/*
+	** look at the ports associated with this beast and
+	** see if any where open. If they was, then re-open
+	** them, using the info from the tty flags.
+	*/
+	for ( port=0; port<PORTS_PER_RTA; port++ )
+	{
+	  PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort];
+	  if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) )
+	  {
+	    rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n"));
+	    rio_spin_lock_irqsave(&PortP->portSem, flags);
+	    PortP->MagicFlags |= MAGIC_REBOOT;
+	    rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	  }
+	}
+	if (RtaType == TYPE_RTA16)
+	{
+	  for ( port=0; port<PORTS_PER_RTA; port++ )
+	  {
+	    PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort];
+	    if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) )
+	    {
+	      rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n"));
+	      rio_spin_lock_irqsave(&PortP->portSem, flags);
+	      PortP->MagicFlags |= MAGIC_REBOOT;
+	      rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	    }
+	  }
+	}
+      }
+
+      /*
+      ** keep a copy of the module types!
+      */
+      HostP->UnixRups[ThisUnit].ModTypes = Mod;
+      if (RtaType == TYPE_RTA16)
+	      HostP->UnixRups[ThisUnit2].ModTypes = Mod;
+
+      /*
+      ** If either of the modules on this unit is read-only or write-only
+      ** or none-xprint, then we need to transfer that info over to the
+      ** relevent ports.
+      */
+      if ( HostP->Mapping[ThisUnit].SysPort != NO_PORT )
+      {
+        for ( port=0; port<PORTS_PER_MODULE; port++ )
+	{
+	  p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+	  p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config |=
+	   p->RIOModuleTypes[Mod1].Flags[port];
+	  p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+	  p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+	}
+	if (RtaType == TYPE_RTA16)
+	{
+          for ( port=0; port<PORTS_PER_MODULE; port++ )
+	  {
+	    p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+	    p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+	    p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+	    p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+          }
+	}
+      }
+
+      /*
+      ** Job done, get on with the interrupts!
+      */
+      return TRUE;
+    }
+  }
+  /*
+  ** There is no table entry for this RTA at all.
+  **
+  ** Lets check to see if we actually booted this unit - if not,
+  ** then we reset it and it will go round the loop of being booted
+  ** we can then worry about trying to fit it into the table.
+  */
+  for ( ThisUnit=0; ThisUnit<HostP->NumExtraBooted; ThisUnit++ )
+    if ( HostP->ExtraUnits[ThisUnit] == RtaUniq )
+      break;
+  if ( ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS )
+  {
+    /*
+    ** if the unit wasn't in the table, and the table wasn't full, then
+    ** we reset the unit, because we didn't boot it.
+    ** However, if the table is full, it could be that we did boot
+    ** this unit, and so we won't reboot it, because it isn't really
+    ** all that disasterous to keep the old bins in most cases. This
+    ** is a rather tacky feature, but we are on the edge of reallity
+    ** here, because the implication is that someone has connected
+    ** 16+MAX_EXTRA_UNITS onto one host.
+    */
+    static int UnknownMesgDone = 0;
+
+    if ( !UnknownMesgDone )
+    {
+	if (! p->RIONoMessage)
+	    cprintf("One or more unknown RTAs are being updated.\n");
+	UnknownMesgDone = 1;
+    }
+
+    PktReplyP->Command = ROUTE_FOAD;
+    HostP->Copy("RT_FOAD",PktReplyP->CommandText,7);
+  }
+  else
+  {
+    /*
+    ** we did boot it (as an extra), and there may now be a table
+    ** slot free (because of a delete), so we will try to make
+    ** a tentative entry for it, so that the configurator can see it
+    ** and fill in the details for us.
+    */
+    if (RtaType == TYPE_RTA16)
+    {
+	if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0)
+	{
+	    RIODefaultName(p, HostP, ThisUnit);
+	    FillSlot(ThisUnit, ThisUnit2, RtaUniq, HostP);
+	}
+    }
+    else
+    {
+	if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0)
+	{
+	    RIODefaultName(p, HostP, ThisUnit);
+	    FillSlot(ThisUnit, 0, RtaUniq, HostP);
+	}
+    }
+    PktReplyP->Command = ROUTE_USED;
+    HostP->Copy("RT_USED",PktReplyP->CommandText,7);
+  }
+  RIOQueueCmdBlk( HostP, Rup, CmdBlkP);
+  return TRUE;
+}
+
+
+void
+RIOFixPhbs(p, HostP, unit)
+struct rio_info *p;
+struct Host *HostP;
+uint unit;
+{
+	ushort			link, port;
+	struct Port		*PortP;
+	unsigned long flags;
+	int PortN = HostP->Mapping[unit].SysPort;
+
+	rio_dprint(RIO_DEBUG_ROUTE, ("RIOFixPhbs unit %d sysport %d\n", unit, PortN));
+
+	if (PortN != -1) {
+		ushort		dest_unit = HostP->Mapping[unit].ID2;
+
+		/*
+		** Get the link number used for the 1st 8 phbs on this unit.
+		*/
+		PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];
+
+		link = RWORD(PortP->PhbP->link);
+
+		for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {
+			ushort		dest_port = port + 8;
+#if 0
+			uint		PktInt;
+#endif
+			WORD		*TxPktP;
+			PKT		*Pkt;
+
+			PortP = p->RIOPortp[PortN];
+
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			/*
+			** If RTA is not powered on, the tx packets will be
+			** unset, so go no further.
+			*/
+			if (PortP->TxStart == 0) {
+					rio_dprint(RIO_DEBUG_ROUTE, ("Tx pkts not set up yet\n"));
+					break;
+			}
+
+			/*
+			** For the second slot of a 16 port RTA, the driver needs to
+			** sort out the phb to port mappings. The dest_unit for this
+			** group of 8 phbs is set to the dest_unit of the accompanying
+			** 8 port block. The dest_port of the second unit is set to
+			** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port
+			** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6
+			** (being the second map ID) will be sent to dest_unit 5, port
+			** 14. When this RTA is deleted, dest_unit for ID 6 will be
+			** restored, and the dest_port will be reduced by 8.
+			** Transmit packets also have a destination field which needs
+			** adjusting in the same manner.
+			** Note that the unit/port bytes in 'dest' are swapped.
+			** We also need to adjust the phb and rup link numbers for the
+			** second block of 8 ttys.
+			*/
+			for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+				/*
+				** *TxPktP is the pointer to the transmit packet on the host
+				** card. This needs to be translated into a 32 bit pointer
+				** so it can be accessed from the driver.
+				*/
+				Pkt = (PKT *) RIO_PTR(HostP->Caddr,RINDW(TxPktP));
+
+				/*
+				** If the packet is used, reset it.
+				*/
+				Pkt = (PKT *)((uint)Pkt & ~PKT_IN_USE);
+				WBYTE(Pkt->dest_unit, dest_unit);
+				WBYTE(Pkt->dest_port, dest_port);
+			}
+			rio_dprint(RIO_DEBUG_ROUTE, ("phb dest: Old %x:%x New %x:%x\n",
+					RWORD(PortP->PhbP->destination) & 0xff,
+					(RWORD(PortP->PhbP->destination) >> 8) & 0xff,
+					dest_unit, dest_port));
+			WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8));
+			WWORD(PortP->PhbP->link, link);
+
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		}
+		/*
+		** Now make sure the range of ports to be serviced includes
+		** the 2nd 8 on this 16 port RTA.
+		*/
+		if (link > 3) return;
+		if (((unit * 8) + 7) > RWORD(HostP->LinkStrP[link].last_port)) {
+			rio_dprint(RIO_DEBUG_ROUTE, ("last port on host link %d: %d\n", link, (unit * 8) + 7));
+			WWORD(HostP->LinkStrP[link].last_port, (unit * 8) + 7);
+		}
+	}
+}
+
+/*
+** Check to see if the new disconnection has isolated this unit.
+** If it has, then invalidate all its link information, and tell
+** the world about it. This is done to ensure that the configurator
+** only gets up-to-date information about what is going on.
+*/
+int
+RIOCheckIsolated(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *HostP;
+uint UnitId;
+{
+	unsigned long flags;
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+	if ( RIOCheck( HostP, UnitId ) ) {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated\n",UnitId));
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+		return(0);
+	}
+
+	RIOIsolate(p, HostP, UnitId );
+	RIOSetChange(p);
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	return 1;
+}
+
+/*
+** Invalidate all the link interconnectivity of this unit, and of
+** all the units attached to it. This will mean that the entire
+** subnet will re-introduce itself.
+*/
+int
+RIOIsolate(p, HostP, UnitId)
+struct rio_info *	p;
+struct Host *		HostP;
+uint UnitId; 
+{
+	uint link, unit;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+	UnitId--;		/* this trick relies on the Unit Id being UNSIGNED! */
+
+	if ( UnitId > MAX_RUP )		/* dontcha just lurv unsigned maths! */
+		return(0);
+
+	if ( HostP->Mapping[UnitId].Flags & BEEN_HERE )
+		return(0);
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	if ( p->RIOPrintDisabled == DO_PRINT )
+		rio_dprint(RIO_DEBUG_ROUTE, ("RIOMesgIsolated %s",HostP->Mapping[UnitId].Name));
+
+	for ( link=0; link<LINKS_PER_UNIT; link++) {
+		unit = HostP->Mapping[UnitId].Topology[link].Unit;
+		HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;
+		HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;
+		RIOIsolate(p, HostP, unit );
+	}
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+	return 1;
+}
+
+int
+RIOCheck(HostP, UnitId)
+struct Host *HostP;
+uint UnitId;
+{
+  unsigned char link;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckUnitId( UnitId );
+#endif
+/* 	rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */
+	rio_dprint(RIO_DEBUG_ROUTE, ("RIOCheck : UnitID = %d\n",UnitId));
+
+	if ( UnitId == HOST_ID ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */
+		return 1;
+	}
+
+	UnitId--;
+
+	if ( UnitId >= MAX_RUP ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */
+		return 0;
+	}
+
+	for ( link=0; link<LINKS_PER_UNIT; link++ ) {
+		if ( HostP->Mapping[UnitId].Topology[link].Unit==HOST_ID ) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n", 
+						UnitId, 'A'+link)); */
+			return 1;
+		}
+	}
+
+	if ( HostP->Mapping[UnitId].Flags & BEEN_HERE ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */
+		return 0;
+	}
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	for ( link=0; link < LINKS_PER_UNIT; link++ ) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */
+		if ( RIOCheck( HostP, HostP->Mapping[UnitId].Topology[link].Unit ) ) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */
+			HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+			return 1;
+		}
+	}
+
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+
+	/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */
+	
+	return 0;
+}
+
+/*
+** Returns the type of unit (host, 16/8 port RTA)
+*/
+
+uint
+GetUnitType(Uniq)
+uint Uniq;
+{
+	switch ( (Uniq >> 28) & 0xf)
+	{
+		case RIO_AT:
+		case RIO_MCA:
+		case RIO_EISA:
+		case RIO_PCI:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Host\n"));
+			return(TYPE_HOST);
+		case RIO_RTA_16:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 16 port RTA\n"));
+			return(TYPE_RTA16);
+		case RIO_RTA:
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 8 port RTA\n"));
+			return(TYPE_RTA8);
+		default :
+			rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Unrecognised\n"));
+			return(99);
+	}
+}
+
+int
+RIOSetChange(p)
+struct rio_info *	p;
+{
+	if ( p->RIOQuickCheck != NOT_CHANGED )
+		return(0);
+	p->RIOQuickCheck = CHANGED;
+	if ( p->RIOSignalProcess ) {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Send SIG-HUP"));
+		/*
+		psignal( RIOSignalProcess, SIGHUP );
+		*/
+	}
+	return(0);
+}
+
+void
+RIOConCon(p, HostP, FromId, FromLink, ToId, ToLink, Change)
+struct rio_info *	p;
+struct Host *HostP;
+uint FromId;
+uint FromLink;
+uint ToId;
+uint ToLink;
+int Change; 
+{
+    char *FromName;
+    char *FromType;
+    char *ToName;
+    char *ToType;
+    unsigned int tp;
+
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+**
+** What's this doing in here anyway ?
+** It was causing the port to be 'unmapped' if opened whilst RTA "disconnected"
+**
+** 09.12.1998 ARG - ESIL 0776 - part fix
+** Okay, We've found out what this was all about now !
+** Someone had botched this to use RIOHalted to indicated the number of RTAs
+** 'disconnected'. The value in RIOHalted was then being used in the
+** 'RIO_QUICK_CHECK' ioctl. A none zero value indicating that a least one RTA
+** is 'disconnected'. The change was put in to satisfy a customer's needs.
+** Having taken this bit of code out 'RIO_QUICK_CHECK' now no longer works for
+** the customer.
+**
+    if (Change == CONNECT) {
+		if (p->RIOHalted) p->RIOHalted --;
+	 }
+	 else {
+		p->RIOHalted ++;
+	 }
+**
+** So - we need to implement it slightly differently - a new member of the
+** rio_info struct - RIORtaDisCons (RIO RTA connections) keeps track of RTA
+** connections and disconnections. 
+*/
+    if (Change == CONNECT) {
+		if (p->RIORtaDisCons) p->RIORtaDisCons--;
+	 }
+	 else {
+		p->RIORtaDisCons++;
+	 }
+
+    if ( p->RIOPrintDisabled == DONT_PRINT )
+		return;
+
+    if ( FromId > ToId ) {
+		tp = FromId;
+		FromId = ToId;
+		ToId = tp;
+		tp = FromLink;
+		FromLink = ToLink;
+		ToLink = tp;
+    }
+
+    FromName = FromId ? HostP->Mapping[FromId-1].Name : HostP->Name;
+    FromType = FromId ? "RTA" : "HOST";
+    ToName = ToId ? HostP->Mapping[ToId-1].Name : HostP->Name;
+    ToType = ToId ? "RTA" : "HOST";
+
+    rio_dprint(RIO_DEBUG_ROUTE, ("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n",
+			    FromType, FromName, 'A'+FromLink,
+			    ToType,   ToName,   'A'+ToLink,
+			    (Change==CONNECT) ? "established" : "disconnected"));
+    cprintf("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n",
+			    FromType, FromName, 'A'+FromLink,
+			    ToType,   ToName,   'A'+ToLink,
+			    (Change==CONNECT) ? "established" : "disconnected");
+}
+
+/*
+** RIORemoveFromSavedTable :
+**
+** Delete and RTA entry from the saved table given to us
+** by the configuration program.
+*/
+int
+RIORemoveFromSavedTable(struct rio_info *p, struct Map *pMap)
+{
+    int		entry;
+
+    /*
+    ** We loop for all entries even after finding an entry and
+    ** zeroing it because we may have two entries to delete if
+    ** its a 16 port RTA.
+    */
+    for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++)
+    {
+	if (p->RIOSavedTable[entry].RtaUniqueNum == pMap->RtaUniqueNum)
+	{
+	    bzero((caddr_t)&p->RIOSavedTable[entry], sizeof(struct Map));
+	}
+    }
+    return 0;
+}
+
+
+/*
+** RIOCheckDisconnected :
+**
+** Scan the unit links to and return zero if the unit is completely
+** disconnected.
+*/
+int
+RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit)
+{
+    int		link;
+
+
+    rio_dprint(RIO_DEBUG_ROUTE, ("RIOFreeDisconnect unit %d\n",unit));
+    /*
+    ** If the slot is tentative and does not belong to the
+    ** second half of a 16 port RTA then scan to see if
+    ** is disconnected.
+    */
+    for (link = 0; link < LINKS_PER_UNIT; link++)
+    {
+	if (HostP->Mapping[unit].Topology[link].Unit != ROUTE_DISCONNECT)
+	    break;
+    }
+
+    /*
+    ** If not all links are disconnected then we can forget about it.
+    */
+    if (link < LINKS_PER_UNIT)
+	    return 1;
+
+#if NEED_TO_FIX_THIS
+    /* Ok so all the links are disconnected. But we may have only just
+    ** made this slot tentative and not yet received a topology update.
+    ** Lets check how long ago we made it tentative.
+    */
+    rio_dprint(RIO_DEBUG_ROUTE, ("Just about to check LBOLT on entry %d\n",unit));
+    if (drv_getparm(LBOLT, (ulong_t *) &current_time))
+        rio_dprint(RIO_DEBUG_ROUTE, ("drv_getparm(LBOLT,....) Failed.\n"));
+
+    elapse_time = current_time - TentTime[unit];
+    rio_dprint(RIO_DEBUG_ROUTE, ("elapse %d = current %d - tent %d (%d usec)\n",
+        elapse_time, current_time, TentTime[unit],drv_hztousec(elapse_time)));
+    if (drv_hztousec(elapse_time) < WAIT_TO_FINISH)
+    {
+        rio_dprint(RIO_DEBUG_ROUTE, ("Skipping slot %d, not timed out yet %d\n"
+            ,unit,drv_hztousec(elapse_time)));
+        return 1;
+    }
+#endif
+
+    /*
+    ** We have found an usable slot.
+    ** If it is half of a 16 port RTA then delete the other half.
+    */
+    if (HostP->Mapping[unit].ID2 != 0)
+    {
+	int nOther = (HostP->Mapping[unit].ID2) -1;
+
+	rio_dprint(RIO_DEBUG_ROUTE, ("RioFreedis second slot %d.\n",nOther));
+	bzero((caddr_t)&HostP->Mapping[nOther], sizeof(struct Map));
+    }
+    RIORemoveFromSavedTable(p, &HostP->Mapping[unit]);
+
+    return 0;
+}
+
+
+/*
+** RIOFindFreeID :
+**
+** This function scans the given host table for either one
+** or two free unit ID's.
+*/
+int
+RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2)
+{
+    int unit,tempID;
+
+    /*
+    ** Initialise the ID's to MAX_RUP.
+    ** We do this to make the loop for setting the ID's as simple as
+    ** possible.
+    */
+    *pID1 = MAX_RUP;
+    if (pID2 != NULL)
+	*pID2 = MAX_RUP;
+
+    /*
+    ** Scan all entries of the host mapping table for free slots.
+    ** We scan for free slots first and then if that is not successful
+    ** we start all over again looking for tentative slots we can re-use.
+    */
+    for (unit = 0; unit < MAX_RUP; unit++)
+    {
+	rio_dprint(RIO_DEBUG_ROUTE, ("Scanning unit %d\n",unit));
+	/*
+	** If the flags are zero then the slot is empty.
+	*/
+	if (HostP->Mapping[unit].Flags == 0)
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("      This slot is empty.\n"));
+	    /*
+	    ** If we haven't allocated the first ID then do it now.
+	    */
+	    if (*pID1 == MAX_RUP)
+	    {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for first unit %d\n", unit));
+		*pID1 = unit;
+
+		/*
+		** If the second ID is not needed then we can return
+		** now.
+		*/
+		if (pID2 == NULL)
+		    return 0;
+	    }
+	    else
+	    {
+		/*
+		** Allocate the second slot and return.
+		*/
+		rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for second unit %d\n", unit));
+		*pID2 = unit;
+		return 0;
+	    }
+	}
+    }
+
+    /*
+    ** If we manage to come out of the free slot loop then we
+    ** need to start all over again looking for tentative slots
+    ** that we can re-use.
+    */
+    rio_dprint(RIO_DEBUG_ROUTE, ("Starting to scan for tentative slots\n"));
+    for (unit = 0; unit < MAX_RUP; unit++)
+    {
+	if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) ||
+	                       (HostP->Mapping[unit].Flags == 0))  && ! 
+	   (HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT ))
+	{
+	    rio_dprint(RIO_DEBUG_ROUTE, ("    Slot %d looks promising.\n",unit));
+
+	    if(unit == *pID1)
+	    {
+	    	rio_dprint(RIO_DEBUG_ROUTE, ("    No it isn't, its the 1st half\n"));
+		continue;
+	    }
+
+	    /*
+	    ** Slot is Tentative or Empty, but not a tentative second 
+	    ** slot of a 16 porter.
+	    ** Attempt to free up this slot (and its parnter if
+	    ** it is a 16 port slot. The second slot will become
+	    ** empty after a call to RIOFreeDisconnected so thats why
+	    ** we look for empty slots above  as well).
+	    */
+	    if (HostP->Mapping[unit].Flags != 0) 
+	    	if (RIOFreeDisconnected(p, HostP, unit) != 0)
+			    continue;
+	    /*
+	    ** If we haven't allocated the first ID then do it now.
+	    */
+	    if (*pID1 == MAX_RUP)
+	    {
+		rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative entry for first unit %d\n", unit));
+		*pID1 = unit;
+
+		/*
+		** Clear out this slot now that we intend to use it.
+		*/
+		bzero(&HostP->Mapping[unit], sizeof(struct Map));
+
+		/*
+		** If the second ID is not needed then we can return
+		** now.
+		*/
+		if (pID2 == NULL)
+		    return 0;
+	    }
+	    else
+	    {
+		/*
+		** Allocate the second slot and return.
+		*/
+		rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative/empty  entry for second unit %d\n",
+		      unit));
+		*pID2 = unit;
+
+		/*
+		** Clear out this slot now that we intend to use it.
+		*/
+		bzero(&HostP->Mapping[unit], sizeof(struct Map));
+
+		/* At this point under the right(wrong?) conditions
+		** we may have a first unit ID being higher than the
+		** second unit ID. This is a bad idea if we are about
+		** to fill the slots with a 16 port RTA.
+		** Better check and swap them over.
+		*/
+
+		if (*pID1 > *pID2)
+		{
+			rio_dprint(RIO_DEBUG_ROUTE, ("Swapping IDS %d %d\n",*pID1,*pID2));
+			tempID = *pID1;
+			*pID1 = *pID2;
+			*pID2 = tempID;
+		}
+		return 0;
+	    }
+	}
+    }
+
+    /*
+    ** If we manage to get to the end of the second loop then we
+    ** can give up and return a failure.
+    */
+    return 1;
+}
+
+
+/*
+** The link switch scenario.
+**
+** Rta Wun (A) is connected to Tuw (A).
+** The tables are all up to date, and the system is OK.
+**
+** If Wun (A) is now moved to Wun (B) before Wun (A) can
+** become disconnected, then the follow happens:
+**
+** Tuw (A) spots the change of unit:link at the other end
+** of its link and Tuw sends a topology packet reflecting
+** the change: Tuw (A) now disconnected from Wun (A), and
+** this is closely followed by a packet indicating that 
+** Tuw (A) is now connected to Wun (B).
+**
+** Wun (B) will spot that it has now become connected, and
+** Wun will send a topology packet, which indicates that
+** both Wun (A) and Wun (B) is connected to Tuw (A).
+**
+** Eventually Wun (A) realises that it is now disconnected
+** and Wun will send out a topology packet indicating that
+** Wun (A) is now disconnected.
+*/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riospace.h linux/drivers/char/rio/riospace.h
--- v2.3.99-pre6/linux/drivers/char/rio/riospace.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riospace.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,161 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riospace.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riospace.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riospace_h__
+#define __rio_riospace_h__
+
+#ifdef SCCS_LABELS
+static char *_riospace_h_sccs_ = "@(#)riospace.h	1.2";
+#endif
+
+#define	RIO_LOCATOR_LEN	16
+#define	MAX_RIO_BOARDS	4
+
+/*
+** DONT change this file. At all. Unless you can rebuild the entire
+** device driver, which you probably can't, then the rest of the
+** driver won't see any changes you make here. So don't make any.
+** In particular, it won't be able to see changes to RIO_SLOTS
+*/
+
+struct Conf
+{
+	char         Locator[24];
+	unsigned int StartupTime;
+	unsigned int SlowCook;
+	unsigned int IntrPollTime;
+	unsigned int BreakInterval;
+	unsigned int Timer;
+	unsigned int RtaLoadBase;
+	unsigned int HostLoadBase;
+	unsigned int XpHz;
+	unsigned int XpCps;
+	char         *XpOn;
+	char         *XpOff;
+	unsigned int MaxXpCps;
+	unsigned int MinXpCps;
+	unsigned int SpinCmds;
+	unsigned int FirstAddr;
+	unsigned int LastAddr;
+	unsigned int BufferSize;
+	unsigned int LowWater;
+	unsigned int LineLength;
+	unsigned int CmdTime;
+};
+
+/*
+**	Board types - these MUST correspond to product codes!
+*/ 
+#define	RIO_EMPTY	0x0
+#define	RIO_EISA	0x3
+#define	RIO_RTA_16	0x9
+#define	RIO_AT		0xA
+#define	RIO_MCA		0xB
+#define	RIO_PCI		0xD
+#define	RIO_RTA		0xE
+
+/*
+**	Board data structure. This is used for configuration info
+*/
+struct	Brd
+{
+    unsigned char Type;	/* RIO_EISA, RIO_MCA, RIO_AT, RIO_EMPTY... */
+    unsigned char Ivec;	/* POLLED or ivec number */
+    unsigned char Mode;	/* Control stuff, see below */
+};
+
+struct	Board
+{
+    char       Locator[RIO_LOCATOR_LEN];
+    int        NumSlots;
+    struct Brd Boards[MAX_RIO_BOARDS];
+};
+
+#define	BOOT_FROM_LINK		0x00
+#define	BOOT_FROM_RAM		0x01
+#define	EXTERNAL_BUS_OFF	0x00
+#define	EXTERNAL_BUS_ON		0x02
+#define	INTERRUPT_DISABLE	0x00
+#define	INTERRUPT_ENABLE	0x04
+#define	BYTE_OPERATION		0x00
+#define	WORD_OPERATION		0x08
+#define	POLLED			INTERRUPT_DISABLE
+#define	IRQ_15			(0x00 | INTERRUPT_ENABLE)
+#define	IRQ_12			(0x10 | INTERRUPT_ENABLE)
+#define	IRQ_11			(0x20 | INTERRUPT_ENABLE)
+#define	IRQ_9			(0x30 | INTERRUPT_ENABLE)
+#define	SLOW_LINKS		0x00
+#define	FAST_LINKS		0x40
+#define	SLOW_AT_BUS		0x00
+#define	FAST_AT_BUS		0x80
+#define	SLOW_PCI_TP		0x00
+#define	FAST_PCI_TP		0x80
+/*
+**	Debug levels
+*/
+#define	DBG_NONE	0x00000000
+
+#define	DBG_INIT	0x00000001
+#define	DBG_OPEN	0x00000002
+#define	DBG_CLOSE	0x00000004
+#define	DBG_IOCTL	0x00000008
+
+#define	DBG_READ	0x00000010
+#define	DBG_WRITE	0x00000020
+#define	DBG_INTR	0x00000040
+#define	DBG_PROC	0x00000080
+
+#define	DBG_PARAM	0x00000100
+#define	DBG_CMD		0x00000200
+#define	DBG_XPRINT	0x00000400
+#define	DBG_POLL	0x00000800
+
+#define	DBG_DAEMON	0x00001000
+#define	DBG_FAIL	0x00002000
+#define DBG_MODEM	0x00004000
+#define	DBG_LIST	0x00008000
+
+#define	DBG_ROUTE	0x00010000
+#define DBG_UTIL        0x00020000
+#define DBG_BOOT	0x00040000
+#define DBG_BUFFER	0x00080000
+
+#define	DBG_MON		0x00100000
+#define DBG_SPECIAL     0x00200000
+#define	DBG_VPIX	0x00400000
+#define	DBG_FLUSH	0x00800000
+
+#define	DBG_QENABLE	0x01000000
+
+#define	DBG_ALWAYS	0x80000000
+
+#endif /* __rio_riospace_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c
--- v2.3.99-pre6/linux/drivers/char/rio/riotable.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotable.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1057 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riotable.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotable.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riotable_c_sccs_ = "@(#)riotable.c	1.2";
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+#include "protsts.h"
+
+/*
+** A configuration table has been loaded. It is now up to us
+** to sort it out and use the information contained therein.
+*/
+int
+RIONewTable(p)
+struct rio_info *	p;
+{
+	int Host, Host1, Host2, NameIsUnique, Entry, SubEnt;
+	struct Map *MapP;
+	struct Map *HostMapP;
+	struct Host *HostP;
+
+	char *cptr;
+
+	/*
+	** We have been sent a new table to install. We need to break
+	** it down into little bits and spread it around a bit to see
+	** what we have got.
+	*/
+	/*
+	** Things to check:
+	** (things marked 'xx' aren't checked any more!)
+	** (1)	That there are no booted Hosts/RTAs out there.
+	** (2)	That the names are properly formed
+	** (3)	That blank entries really are.
+	** xx (4)	That hosts mentioned in the table actually exist. xx
+	** (5)	That the IDs are unique (per host).
+	** (6)	That host IDs are zero
+	** (7)	That port numbers are valid
+	** (8)	That port numbers aren't duplicated
+	** (9)	That names aren't duplicated
+	** xx (10) That hosts that actually exist are mentioned in the table. xx
+	*/
+	rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(1)\n")); 
+	if ( p->RIOSystemUp ) {		/* (1) */
+		p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED;
+		return EBUSY;
+	}
+
+	p->RIOError.Error = NOTHING_WRONG_AT_ALL;
+	p->RIOError.Entry = -1;
+	p->RIOError.Other = -1;
+
+	for ( Entry=0; Entry<TOTAL_MAP_ENTRIES; Entry++ ) {
+		MapP = &p->RIOConnectTable[Entry];
+		if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(2)\n"));
+			cptr = MapP->Name;		/* (2) */
+			cptr[MAX_NAME_LEN-1]='\0';
+			if ( cptr[0]=='\0' ) {
+				bcopy(MapP->RtaUniqueNum?"RTA	NN":"HOST NN",MapP->Name,8);
+				MapP->Name[5] = '0'+Entry/10;
+				MapP->Name[6] = '0'+Entry%10;
+			}
+			while ( *cptr ) {
+				if ( *cptr<' ' || *cptr>'~' ) {
+					p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+					p->RIOError.Entry = Entry;
+					return ENXIO;
+				}
+				cptr++;
+			}
+		}
+
+		/*
+		** If the entry saved was a tentative entry then just forget
+		** about it.
+		*/
+		if ( MapP->Flags & SLOT_TENTATIVE ) {
+			MapP->HostUniqueNum = 0;
+			MapP->RtaUniqueNum = 0;
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(3)\n"));
+		if ( !MapP->RtaUniqueNum && !MapP->HostUniqueNum ) { /* (3) */
+			if ( MapP->ID || MapP->SysPort || MapP->Flags ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("%s pretending to be empty but isn't\n",MapP->Name));
+				p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("!RIO: Daemon: test (3) passes\n"));
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(4)\n"));
+		for ( Host=0; Host<p->RIONumHosts; Host++ ) { /* (4) */
+			if ( p->RIOHosts[Host].UniqueNum==MapP->HostUniqueNum ) {
+				HostP = &p->RIOHosts[Host];
+				/*
+				** having done the lookup, we don't really want to do
+				** it again, so hang the host number in a safe place
+				*/
+				MapP->Topology[0].Unit = Host;
+				break;
+			}
+		}
+
+		if ( Host >= p->RIONumHosts ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has unknown host unique number 0x%x\n",
+									MapP->Name,MapP->HostUniqueNum));
+			MapP->HostUniqueNum = 0;
+			/* MapP->RtaUniqueNum	= 0; */
+			/* MapP->ID			= 0; */
+			/* MapP->Flags		 = 0; */
+			/* MapP->SysPort		 = 0; */
+			/* MapP->Name[0]		 = 0; */
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(5)\n")); 
+		if ( MapP->RtaUniqueNum ) { /* (5) */
+			if ( !MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an ID of zero!\n",
+							MapP->Name));
+				p->RIOError.Error		 = ZERO_RTA_ID;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->ID > MAX_RUP ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an illegal ID %d\n",
+							MapP->Name, MapP->ID));
+				p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( MapP->HostUniqueNum == 
+						p->RIOConnectTable[SubEnt].HostUniqueNum && 
+						MapP->ID == p->RIOConnectTable[SubEnt].ID ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("Dupl. ID number allocated to RTA %s and RTA %s\n",
+							MapP->Name,p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATED_RTA_ID;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+				/*
+				** If the RtaUniqueNum is the same, it may be looking at both
+				** entries for a 16 port RTA, so check the ids
+				*/
+				if ((MapP->RtaUniqueNum == 
+						p->RIOConnectTable[SubEnt].RtaUniqueNum)
+				 		&& (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",MapP->Name));
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",
+										p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7a)\n")); 
+			/* (7a) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort % PORTS_PER_RTA)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d-RTA %s is not a multiple of %d!\n",
+					(int)MapP->SysPort,MapP->Name,PORTS_PER_RTA));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7b)\n")); 
+			/* (7b) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort >= RIO_PORTS)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d for RTA %s is too big\n",
+							(int)MapP->SysPort,MapP->Name));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT )
+						continue;
+				if ( p->RIOConnectTable[SubEnt].RtaUniqueNum ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(8)\n")); 
+					/* (8) */
+					if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort == 
+									p->RIOConnectTable[SubEnt].SysPort) ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA %s:same TTY port # as RTA %s (%d)\n",
+							MapP->Name, p->RIOConnectTable[SubEnt].Name,
+							(int)MapP->SysPort));
+						p->RIOError.Error = TTY_NUMBER_IN_USE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(9)\n")); 
+					if (RIOStrCmp(MapP->Name,
+							p->RIOConnectTable[SubEnt].Name)==0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA name %s used twice\n",MapP->Name));
+						p->RIOError.Error = NAME_USED_TWICE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+				}
+			}
+		}
+		else { /* (6) */
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(6)\n")); 
+			if ( MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO:HOST %s has been allocated ID that isn't zero!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_ID_NOT_ZERO;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->SysPort != NO_PORT ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: HOST %s has been allocated port numbers!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_SYSPORT_BAD;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+		}
+	}
+
+	/*
+	** wow! if we get here then its a goody!
+	*/
+
+	/*
+	** Zero the (old) entries for each host...
+	*/
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			bzero((caddr_t)&p->RIOHosts[Host].Mapping[Entry], 
+											sizeof(struct Map));
+		}
+		bzero((caddr_t)&p->RIOHosts[Host].Name[0],
+								sizeof(p->RIOHosts[Host].Name) );
+	}
+
+	/*
+	** Copy in the new table entries
+	*/
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: Copy table for Host entry %d\n", Entry));
+		MapP = &p->RIOConnectTable[Entry];
+
+		/*
+		** Now, if it is an empty slot ignore it!
+		*/
+		if ( MapP->HostUniqueNum==0 )
+			continue;
+
+		/*
+		** we saved the host number earlier, so grab it back
+		*/
+		HostP = &p->RIOHosts[MapP->Topology[0].Unit];
+
+		/*
+		** If it is a host, then we only need to fill in the name field.
+		*/
+		if ( MapP->ID==0 ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Host entry found. Name %s\n",MapP->Name));
+			bcopy(MapP->Name,HostP->Name,MAX_NAME_LEN);
+			continue;
+		}
+
+		/*
+		** Its an RTA entry, so fill in the host mapping entries for it
+		** and the port mapping entries. Notice that entry zero is for
+		** ID one.
+		*/
+		HostMapP = &HostP->Mapping[MapP->ID-1];
+
+		if (MapP->Flags & SLOT_IN_USE) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Rta entry found. Name %s\n",MapP->Name));
+			/*
+			** structure assign, then sort out the bits we shouldn't have done
+			*/
+			*HostMapP = *MapP;
+
+			HostMapP->Flags = SLOT_IN_USE;
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+			RIOReMapPorts(p, HostP, HostMapP );
+		}
+		else {
+			rio_dprint(RIO_DEBUG_TABLE, ("TENTATIVE Rta entry found. Name %s\n",MapP->Name));
+		}
+	}
+
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		p->RIOSavedTable[Entry] = p->RIOConnectTable[Entry];
+	}
+
+	for ( Host=0; Host<p->RIONumHosts; Host++ ) {
+		for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+			p->RIOHosts[Host].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+			p->RIOHosts[Host].Topology[SubEnt].Link = NO_LINK;
+		}
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Unit = 
+								ROUTE_DISCONNECT;
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Link = 
+								NO_LINK;
+			}
+		}
+		if ( !p->RIOHosts[Host].Name[0] ) {
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host;
+		}
+		/*
+		** Check that default name assigned is unique.
+		*/
+		Host1 = Host;
+		NameIsUnique = 0;
+		while (!NameIsUnique) {
+			NameIsUnique = 1;
+			for ( Host2=0; Host2<p->RIONumHosts; Host2++ ) {
+				if (Host2 == Host)
+					continue;
+				if (RIOStrCmp(p->RIOHosts[Host].Name, p->RIOHosts[Host2].Name)
+									 == 0) {
+					NameIsUnique = 0;
+					Host1++;
+					if (Host1 >= p->RIONumHosts)
+						Host1 = 0;
+					p->RIOHosts[Host].Name[5] = '1' + Host1;
+				}
+			}
+		}
+		/*
+		** Rename host if name already used.
+		*/
+		if (Host1 != Host)
+		{
+			rio_dprint(RIO_DEBUG_TABLE, ("Default name %s already used\n", p->RIOHosts[Host].Name));
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host1;
+		}
+		rio_dprint(RIO_DEBUG_TABLE, ("Assigning default name %s\n", p->RIOHosts[Host].Name));
+	}
+	return 0;
+}
+
+/*
+** User process needs the config table - build it from first
+** principles.
+*/
+int
+RIOApel(p)
+struct rio_info *	p;
+{
+	int Host;
+	int link;
+	int Rup;
+	int Next = 0;
+	struct Map *MapP;
+	struct Host *HostP;
+	int oldspl;
+
+	disable(oldspl);		/* strange but true! */
+ 
+	rio_dprint(RIO_DEBUG_TABLE, ("Generating a table to return to config.rio\n"));
+
+	bzero((caddr_t)&p->RIOConnectTable[0], 
+					sizeof(struct Map) * TOTAL_MAP_ENTRIES );
+
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Processing host %d\n", Host));
+		HostP = &p->RIOHosts[Host];
+		MapP = &p->RIOConnectTable[Next++];
+		MapP->HostUniqueNum = HostP->UniqueNum;
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING )
+			continue;
+		MapP->RtaUniqueNum = 0;
+		MapP->ID = 0;
+		MapP->Flags = SLOT_IN_USE;
+		MapP->SysPort = NO_PORT;
+		for ( link=0; link<LINKS_PER_UNIT; link++ )
+			MapP->Topology[link] = HostP->Topology[link];
+		bcopy(HostP->Name,MapP->Name,MAX_NAME_LEN);
+		for ( Rup=0; Rup<MAX_RUP; Rup++ ) {
+			if ( HostP->Mapping[Rup].Flags & (SLOT_IN_USE|SLOT_TENTATIVE) ) {
+				p->RIOConnectTable[Next] = HostP->Mapping[Rup];
+				if ( HostP->Mapping[Rup].Flags & SLOT_IN_USE)
+					p->RIOConnectTable[Next].Flags |= SLOT_IN_USE;
+				if ( HostP->Mapping[Rup].Flags & SLOT_TENTATIVE)
+					p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE;
+				if ( HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT )
+					p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT;
+				Next++;
+			}
+		}
+	}
+	restore(oldspl);
+	return 0;
+}
+
+/*
+** config.rio has taken a dislike to one of the gross maps entries.
+** if the entry is suitably inactive, then we can gob on it and remove
+** it from the table.
+*/
+int
+RIODeleteRta(p, MapP)
+struct rio_info *p;
+struct Map *MapP;
+{
+	int host, entry, port, link;
+	int SysPort;
+	struct Host *HostP;
+	struct Map *HostMapP;
+	struct Port *PortP;
+	int work_done = 0;
+	unsigned long flags;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Delete entry on host %x, rta %x\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum));
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		HostP = &p->RIOHosts[host];
+
+		rio_spin_lock_irqsave( &HostP->HostLock, flags );
+
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+			rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+			continue;
+		}
+
+		for ( entry=0; entry<MAX_RUP; entry++ ) {
+			if ( MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum ) {
+				HostMapP = &HostP->Mapping[entry];
+				rio_dprint(RIO_DEBUG_TABLE, ("Found entry offset %d on host %s\n", 
+						entry,HostP->Name));
+
+				/*
+				** Check all four links of the unit are disconnected
+				*/
+				for ( link=0; link< LINKS_PER_UNIT; link++ ) {
+					if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("Entry is in use and cannot be deleted!\n"));
+						p->RIOError.Error = UNIT_IS_IN_USE;
+						rio_spin_unlock_irqrestore( &HostP->HostLock, flags);
+						return EBUSY;
+					}
+				}
+				/*
+				** Slot has been allocated, BUT not booted/routed/
+				** connected/selected or anything else-ed
+				*/
+				SysPort = HostMapP->SysPort;
+
+				if ( SysPort != NO_PORT ) {
+					for (port=SysPort; port < SysPort+PORTS_PER_RTA; port++) {
+						PortP = p->RIOPortp[port];
+						rio_dprint(RIO_DEBUG_TABLE, ("Unmap port\n"));
+
+						rio_spin_lock_irqsave( &PortP->portSem, flags );
+
+						PortP->Mapped = 0;
+
+						if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) {
+
+							rio_dprint(RIO_DEBUG_TABLE, ("Gob on port\n"));
+							PortP->TxBufferIn = PortP->TxBufferOut = 0;
+							/* What should I do 
+							wakeup( &PortP->TxBufferIn );
+							wakeup( &PortP->TxBufferOut);
+							*/
+							PortP->InUse = NOT_INUSE;
+							/* What should I do 
+							wakeup( &PortP->InUse );
+							signal(PortP->TtyP->t_pgrp,SIGKILL);
+							ttyflush(PortP->TtyP,(FREAD|FWRITE));
+							*/
+							PortP->State |= RIO_CLOSING | RIO_DELETED;
+						}
+
+						/*
+						** For the second slot of a 16 port RTA, the
+						** driver needs to reset the changes made to
+						** the phb to port mappings in RIORouteRup.
+						*/
+						if (PortP->SecondBlock) {
+							ushort dest_unit = HostMapP->ID;
+							ushort dest_port = port - SysPort;
+							WORD	 *TxPktP;
+							PKT	*Pkt;
+
+							for (TxPktP = PortP->TxStart;
+								TxPktP <= PortP->TxEnd; TxPktP++) {
+								/*
+								** *TxPktP is the pointer to the
+								** transmit packet on the host card.
+								** This needs to be translated into
+								** a 32 bit pointer so it can be
+								** accessed from the driver.
+								*/
+								Pkt = (PKT *) RIO_PTR(HostP->Caddr,
+								 	RWORD(*TxPktP));
+								rio_dprint(RIO_DEBUG_TABLE, (
+						"Tx packet (%x) destination: Old %x:%x New %x:%x\n",
+								 *TxPktP, Pkt->dest_unit,
+								 Pkt->dest_port, dest_unit, dest_port));
+								WWORD(Pkt->dest_unit, dest_unit);
+								WWORD(Pkt->dest_port, dest_port);
+							}
+							rio_dprint(RIO_DEBUG_TABLE, (
+						"Port %d phb destination: Old %x:%x New %x:%x\n",
+							 port, PortP->PhbP->destination & 0xff,
+							 (PortP->PhbP->destination >> 8) & 0xff,
+							 dest_unit, dest_port));
+							WWORD(PortP->PhbP->destination,
+							 dest_unit + (dest_port << 8));
+						}
+						rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					}
+				}
+				rio_dprint(RIO_DEBUG_TABLE, ("Entry nulled.\n"));
+				bzero((char *)HostMapP,sizeof(struct Map));
+				work_done++;
+			}
+		}
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	}
+
+	/* XXXXX lock me up */
+	for ( entry=0; entry< TOTAL_MAP_ENTRIES; entry++ ) {
+		if ( p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOSavedTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+		if ( p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOConnectTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+	}
+	if ( work_done )
+		return 0;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Couldn't find entry to be deleted\n"));
+	p->RIOError.Error = COULDNT_FIND_ENTRY;
+	return ENXIO;
+}
+
+int RIOAssignRta( struct rio_info *p, struct Map *MapP )
+{
+    int host;
+    struct Map *HostMapP;
+    char *sptr;
+    int	link;
+
+
+    rio_dprint(RIO_DEBUG_TABLE, ("Assign entry on host %x, rta %x, ID %d, Sysport %d\n",
+				MapP->HostUniqueNum,MapP->RtaUniqueNum,
+				MapP->ID, (int)MapP->SysPort ));
+
+    if ((MapP->ID != (ushort)-1) &&
+	((int)MapP->ID < (int)1 || (int)MapP->ID > MAX_RUP ))
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+	p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if (MapP->RtaUniqueNum == 0)
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Rta Unique number zero!\n"));
+	p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not valid!\n",(int)MapP->SysPort));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+
+    /*
+    ** Copy the name across to the map entry.
+    */
+    MapP->Name[MAX_NAME_LEN-1] = '\0';
+    sptr = MapP->Name;
+    while ( *sptr )
+    {
+    if ( *sptr<' ' || *sptr>'~' )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+	p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+	return EINVAL;
+    }
+    sptr++;
+    }
+
+    for ( host=0; host < p->RIONumHosts; host++ )
+    {
+	if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum )
+	{
+	    if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING )
+	    {
+		p->RIOError.Error = HOST_NOT_RUNNING;
+		return ENXIO;
+	    }
+
+	    /*
+	    ** Now we have a host we need to allocate an ID
+	    ** if the the entry does not already have one.
+	    */
+	    if (MapP->ID == (ushort)-1)
+	    {
+		int nNewID;
+
+		rio_dprint(RIO_DEBUG_TABLE, ("Attempting to get a new ID for rta \"%s\"\n",
+		      MapP->Name));
+		/*
+		** The idea here is to allow RTA's to be assigned
+		** before they actually appear on the network.
+		** This allows the addition of RTA's without having
+		** to plug them in.
+		** What we do is:
+		**  - Find a free ID and allocate it to the RTA.
+		**  - If this map entry is the second half of a
+		**    16 port entry then find the other half and
+		**    make sure the 2 cross reference each other.
+		*/
+		if (RIOFindFreeID(p, &p->RIOHosts[host], &nNewID, NULL) != 0)
+		{
+		    p->RIOError.Error = COULDNT_FIND_ENTRY;
+		    return EBUSY;
+		}
+		MapP->ID = (ushort)nNewID + 1;
+		rio_dprint(RIO_DEBUG_TABLE, ("Allocated ID %d for this new RTA.\n",MapP->ID));
+		HostMapP = &p->RIOHosts[host].Mapping[nNewID];
+		HostMapP->RtaUniqueNum = MapP->RtaUniqueNum;
+		HostMapP->HostUniqueNum = MapP->HostUniqueNum;
+		HostMapP->ID = MapP->ID;
+		for (link = 0; link < LINKS_PER_UNIT; link++)
+		{
+		    HostMapP->Topology[link].Unit = ROUTE_DISCONNECT;
+		    HostMapP->Topology[link].Link = NO_LINK;
+		}
+		if (MapP->Flags & RTA16_SECOND_SLOT)
+		{
+		    int unit;
+
+		    for (unit = 0; unit < MAX_RUP; unit++)
+			if (p->RIOHosts[host].Mapping[unit].RtaUniqueNum ==
+			    MapP->RtaUniqueNum)
+			    break;
+		    if (unit == MAX_RUP)
+		    {
+			p->RIOError.Error = COULDNT_FIND_ENTRY;
+			return EBUSY;
+		    }
+		    HostMapP->Flags |= RTA16_SECOND_SLOT;
+		    HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID;
+		    p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID;
+		    rio_dprint(RIO_DEBUG_TABLE, ("Cross referenced id %d to ID %d.\n",
+			  MapP->ID,
+			  p->RIOHosts[host].Mapping[unit].ID));
+		}
+	    }
+
+	    HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+	    if ( HostMapP->Flags & SLOT_IN_USE )
+	    {
+		rio_dprint(RIO_DEBUG_TABLE, ("Map table slot for ID %d is already in use.\n",MapP->ID));
+		p->RIOError.Error = ID_ALREADY_IN_USE;
+		return EBUSY;
+	    }
+
+	    /*
+	    ** Assign the sys ports and the name, and mark the slot as
+	    ** being in use.
+	    */
+	    HostMapP->SysPort = MapP->SysPort;
+	    if ((MapP->Flags & RTA16_SECOND_SLOT) == 0)
+	      CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+	    HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED;
+#if NEED_TO_FIX
+	    RIO_SV_BROADCAST(p->RIOHosts[host].svFlags[MapP->ID-1]);
+#endif
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+	    RIOReMapPorts( p, &p->RIOHosts[host], HostMapP );
+	    /*
+	    ** Adjust 2nd block of 8 phbs
+	    */
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		RIOFixPhbs(p, &p->RIOHosts[host], HostMapP->ID - 1);
+
+	    if ( HostMapP->SysPort != NO_PORT )
+	    {
+		if ( HostMapP->SysPort < p->RIOFirstPortsBooted )
+		    p->RIOFirstPortsBooted = HostMapP->SysPort;
+		if ( HostMapP->SysPort > p->RIOLastPortsBooted )
+		    p->RIOLastPortsBooted = HostMapP->SysPort;
+	    }
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+	        rio_dprint(RIO_DEBUG_TABLE, ("Second map of RTA %s added to configuration\n",
+		 p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name));
+	    else
+	        rio_dprint(RIO_DEBUG_TABLE, ("RTA %s added to configuration\n",MapP->Name));
+	    return 0;
+	}
+    }
+    p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+    rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+    return ENXIO;
+}
+
+
+int
+RIOReMapPorts(p, HostP, HostMapP)
+struct rio_info *	p;
+struct Host *HostP;
+struct Map *HostMapP; 
+{
+	register struct Port *PortP;
+	uint SubEnt;
+	uint HostPort;
+	uint SysPort;
+	ushort RtaType;
+	unsigned long flags;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckHostMapP( HostMapP );
+#endif
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d to id %d\n",(int)HostMapP->SysPort, HostMapP->ID));
+
+	/*
+	** We need to tell the UnixRups which sysport the rup corresponds to
+	*/
+	HostP->UnixRups[HostMapP->ID-1].BaseSysPort = HostMapP->SysPort;
+
+	if ( HostMapP->SysPort == NO_PORT )
+		return(0);
+
+	RtaType = GetUnitType(HostMapP->RtaUniqueNum);
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d-%d\n",
+				(int)HostMapP->SysPort,(int)HostMapP->SysPort+PORTS_PER_RTA-1));
+
+	/*
+	** now map each of its eight ports
+	*/
+	for ( SubEnt=0; SubEnt<PORTS_PER_RTA; SubEnt++) {
+	  rio_dprint  (RIO_DEBUG_TABLE, ("subent = %d, HostMapP->SysPort = %d\n", 
+		  SubEnt, (int) HostMapP->SysPort));
+		SysPort = HostMapP->SysPort+SubEnt;		/* portnumber within system */
+					/* portnumber on host */
+		
+		HostPort = (HostMapP->ID-1)*PORTS_PER_RTA+SubEnt; 
+
+		rio_dprint (RIO_DEBUG_TABLE, ("c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp));
+		PortP = p->RIOPortp[SysPort];
+#if 0
+		PortP->TtyP	= &p->channel[SysPort];
+#endif
+		rio_dprint(RIO_DEBUG_TABLE, ("Map port\n"));
+
+		/*
+		** Point at all the real neat data structures
+		*/
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->HostP = HostP;
+		PortP->Caddr = HostP->Caddr;
+
+		/*
+		** The PhbP cannot be filled in yet
+		** unless the host has been booted
+		*/
+		if ((HostP->Flags & RUN_STATE) == RC_RUNNING) {
+			struct PHB *PhbP = PortP->PhbP = &HostP->PhbP[HostPort];
+			PortP->TxAdd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_add));
+			PortP->TxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_start));
+			PortP->TxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_end));
+			PortP->RxRemove=(WORD *)RIO_PTR(HostP->Caddr,
+									RWORD(PhbP->rx_remove));
+			PortP->RxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_start));
+			PortP->RxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_end));
+		}
+		else
+			PortP->PhbP = NULL;
+
+		/*
+		** port related flags
+		*/
+		PortP->HostPort	= HostPort;
+		/*
+		** For each part of a 16 port RTA, RupNum is ID - 1.
+		*/
+		PortP->RupNum = HostMapP->ID - 1;
+		if (HostMapP->Flags & RTA16_SECOND_SLOT) {
+			PortP->ID2			 = HostMapP->ID2 - 1;
+			PortP->SecondBlock	 = TRUE;
+		}
+		else {
+			PortP->ID2			 = 0;
+			PortP->SecondBlock	 = FALSE;
+		}
+		PortP->RtaUniqueNum	= HostMapP->RtaUniqueNum;
+
+		/*
+		** If the port was already mapped then thats all we need to do.
+		*/
+		if (PortP->Mapped) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			continue;
+		}
+		else HostMapP->Flags &= ~RTA_NEWBOOT;
+
+		PortP->State		 = 0;
+		PortP->Config		= 0;
+		/*
+		** Check out the module type - if it is special (read only etc.)
+		** then we need to set flags in the PortP->Config.
+		** Note: For 16 port RTA, all ports are of the same type.
+		*/
+		if (RtaType == TYPE_RTA16) {
+			PortP->Config |= p->RIOModuleTypes[HostP->UnixRups
+				[HostMapP->ID-1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE];
+		} else {
+			if ( SubEnt < PORTS_PER_MODULE )
+				PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+			else
+				PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+		}
+
+		/*
+		** more port related flags
+		*/
+		PortP->PortState	= 0;
+		PortP->ModemLines	= 0;
+		PortP->ModemState	= 0;
+		PortP->CookMode		= COOK_WELL;
+		PortP->ParamSem		= 0;
+		PortP->FlushCmdBodge= 0;
+		PortP->WflushFlag	= 0;
+		PortP->MagicFlags	= 0;
+		PortP->Lock			= 0;
+		PortP->Store		= 0;
+		PortP->FirstOpen	= 1;
+
+		/*
+		** handle the xprint issues
+		*/
+#ifdef XPRINT_SUPPORT
+		PortP->Xprint.XpActive	= 0;
+		PortP->Xprint.XttyP = &riox_tty[SysPort];
+		/*				TO				FROM			MAXLEN */
+		RIOStrNCpy( PortP->Xprint.XpOn,	RIOConf.XpOn,	MAX_XP_CTRL_LEN );
+		RIOStrNCpy( PortP->Xprint.XpOff, RIOConf.XpOff, MAX_XP_CTRL_LEN );
+		PortP->Xprint.XpCps = RIOConf.XpCps;
+		PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+									RIOStrlen(PortP->Xprint.XpOff);
+#endif
+
+		/*
+		** Buffers 'n things
+		*/
+		PortP->RxDataStart	= 0;
+		PortP->Cor2Copy	 = 0;
+		PortP->Name		 = &HostMapP->Name[0];
+#ifdef STATS
+		bzero( (caddr_t)&PortP->Stat, sizeof(struct RIOStats) );
+#endif
+		PortP->statsGather = 0;
+		PortP->txchars = 0;
+		PortP->rxchars = 0;
+		PortP->opens = 0;
+		PortP->closes = 0;
+		PortP->ioctls = 0;
+		if ( PortP->TxRingBuffer )
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		else if ( p->RIOBufferSize ) {
+			PortP->TxRingBuffer = sysbrk(p->RIOBufferSize);
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		}
+		PortP->TxBufferOut	= 0;
+		PortP->TxBufferIn	 = 0;
+		PortP->Debug		= 0;
+		/*
+		** LastRxTgl stores the state of the rx toggle bit for this
+		** port, to be compared with the state of the next pkt received.
+		** If the same, we have received the same rx pkt from the RTA
+		** twice. Initialise to a value not equal to PHB_RX_TGL or 0.
+		*/
+		PortP->LastRxTgl	= ~(uchar)PHB_RX_TGL;
+
+		/*
+		** and mark the port as usable
+		*/
+		PortP->Mapped = 1;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	if ( HostMapP->SysPort < p->RIOFirstPortsMapped )
+		p->RIOFirstPortsMapped = HostMapP->SysPort;
+	if ( HostMapP->SysPort > p->RIOLastPortsMapped )
+		p->RIOLastPortsMapped = HostMapP->SysPort;
+
+	return 0;
+}
+
+int
+RIOChangeName(p, MapP)
+struct rio_info *p;
+struct Map* MapP; 
+{
+	int host;
+	struct Map *HostMapP;
+	char *sptr;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Change name entry on host %x, rta %x, ID %d, Sysport %d\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum,
+								MapP->ID, (int)MapP->SysPort ));
+
+	if ( MapP->ID > MAX_RUP ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+		p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+		return EINVAL;
+	}
+
+	MapP->Name[MAX_NAME_LEN-1] = '\0';
+	sptr = MapP->Name;
+
+	while ( *sptr ) {
+		if ( *sptr<' ' || *sptr>'~' ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+			p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+			return EINVAL;
+		}
+		sptr++;
+	}
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum ) {
+			if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING ) {
+				p->RIOError.Error = HOST_NOT_RUNNING;
+				return ENXIO;
+			}
+			if ( MapP->ID==0 ) {
+				CCOPY( MapP->Name, p->RIOHosts[host].Name, MAX_NAME_LEN );
+				return 0;
+			}
+
+			HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+			if ( HostMapP->RtaUniqueNum != MapP->RtaUniqueNum ) {
+				p->RIOError.Error = RTA_NUMBER_WRONG;
+				return ENXIO;
+			}
+			CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+			return 0;
+		}
+	}
+	p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+	rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+	return ENXIO;
+}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riotime.h linux/drivers/char/rio/riotime.h
--- v2.3.99-pre6/linux/drivers/char/rio/riotime.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotime.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,63 @@
+/****************************************************************************
+ *******                                                              *******
+ *******            T I M E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _riotime_h
+#define _riotime_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_riotime_h_sccs = "@(#)riotime.h	1.1" ;
+#endif
+#endif
+
+#define TWO_POWER_FIFTEEN (ushort)32768
+#define RioTime()    riotime
+#define RioTimeAfter(time1,time2) ((ushort)time1 - (ushort)time2) < TWO_POWER_FIFTEEN
+#define RioTimePlus(time1,time2) ((ushort)time1 + (ushort)time2)
+
+/**************************************
+ * Convert a RIO tick (1/10th second)
+ * into transputer low priority ticks
+ *************************************/ 
+#define RioTimeToLow(time) (time*(100000 / 64))
+#define RioLowToTime(time) ((time*64)/100000)
+
+#define RIOTENTHSECOND (ushort)1
+#define RIOSECOND (ushort)(RIOTENTHSECOND * 10)
+#endif
+
+/*********** end of file ***********/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c
--- v2.3.99-pre6/linux/drivers/char/rio/riotty.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotty.c	Wed May 10 16:56:44 2000
@@ -0,0 +1,1321 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riotty.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotty.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riotty_c_sccs_ = "@(#)riotty.c	1.3";
+#endif
+
+
+#define __EXPLICIT_DEF_H__
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+
+
+#if 0
+static void ttyseth_pv(struct Port *, struct ttystatics *, 
+				struct termios *sg, int);
+#endif
+
+static void RIOClearUp(struct Port *PortP);
+static int RIOShortCommand(struct rio_info *p, struct Port *PortP, 
+			   int command, int len, int arg);
+
+
+extern int	conv_vb[];	/* now defined in ttymgr.c */
+extern int	conv_bv[];	/* now defined in ttymgr.c */
+ 
+/*
+** 16.09.1998 ARG - Fix to build riotty.k.o for Modular Kernel Support
+**
+** ep.def.h is necessary for Modular Kernel Support
+** DO NOT place any kernel 'extern's after this line
+** or this source file will not build riotty.k.o
+*/
+#ifdef uLYNX
+#include <ep.def.h>
+#endif
+
+#ifdef NEED_THIS2
+static struct old_sgttyb 
+default_sg = 
+{ 
+	B19200, B19200,				/* input and output speed */ 
+	'H' - '@',					/* erase char */ 
+	-1,							/* 2nd erase char */ 
+	'U' - '@',					/* kill char */ 
+	ECHO | CRMOD,				/* mode */ 
+	'C' - '@',					/* interrupt character */ 
+	'\\' - '@',					/* quit char */ 
+	'Q' - '@',					/* start char */
+	'S' - '@',					/* stop char */ 
+	'D' - '@',					/* EOF */
+	-1,							/* brk */
+	(LCRTBS | LCRTERA | LCRTKIL | LCTLECH),	/* local mode word */ 
+	'Z' - '@',					/* process stop */
+	'Y' - '@',					/* delayed stop */
+	'R' - '@',					/* reprint line */ 
+	'O' - '@',					/* flush output */
+	'W' - '@',					/* word erase */
+	'V' - '@'					/* literal next char */
+};
+#endif
+
+
+extern struct rio_info *p;
+extern void rio_inc_mod_count (void);
+
+
+int
+riotopen(struct tty_struct * tty, struct file * filp)
+{
+	register uint SysPort;
+	int Modem;
+	int repeat_this = 250;
+	struct Port *PortP;		 /* pointer to the port structure */
+	unsigned long flags;
+	int retval = 0;
+
+	SysPort = rio_minor (tty->device);
+	Modem   = rio_ismodem (tty->device);
+
+	if ( p->RIOFailed ) {
+		rio_dprint(RIO_DEBUG_TTY, ("System initialisation failed\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("port open SysPort %d (%s) (mapped:%d)\n",
+	       SysPort,  Modem ? "Modem" : "tty",
+				   p->RIOPortp[SysPort]->Mapped  ) );
+
+	/*
+	** Validate that we have received a legitimate request.
+	** Currently, just check that we are opening a port on
+	** a host card that actually exists, and that the port
+	** has been mapped onto a host.
+	*/
+	if (SysPort >= RIO_PORTS) {	/* out of range ? */
+		rio_dprint(RIO_DEBUG_TTY, ("Illegal port number %d\n",SysPort));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	/*
+	** Grab pointer to the port stucture
+	*/
+	PortP = p->RIOPortp[SysPort];	/* Get control struc */
+
+	if ( !PortP->Mapped ) {	/* we aren't mapped yet! */
+		/*
+		** The system doesn't know which RTA this port
+		** corresponds to.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("port not mapped into system\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	tty->driver_data = PortP;
+
+	PortP->gs.tty = tty;
+	PortP->gs.count++;
+	rio_dprint(RIO_DEBUG_TTY, ("%d bytes in tx buffer\n",
+				   PortP->gs.xmit_cnt));
+	gs_init_port (&PortP->gs);
+
+	/*
+	** If the host hasn't been booted yet, then 
+	** fail
+	*/
+	if ( (PortP->HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Host not running\n"));
+		pseterr(ENXIO);
+		return 0;
+	}
+
+	/*
+	** If the RTA has not booted yet and the user has choosen to block
+	** until the RTA is present then we must spin here waiting for
+	** the RTA to boot.
+	*/
+#if 0
+	if (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+		if (PortP->WaitUntilBooted) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot\n"));
+			do {
+				if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+					rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n"));
+					return -EINTR;
+				}
+				if (repeat_this -- <= 0) {
+					rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n"));
+					RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+					pseterr(EINTR);
+					return -EIO;
+				}
+			} while(!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED));
+			rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n"));
+		} else {
+			rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n"));
+			pseterr(ENXIO);
+			return 0;
+		}
+	}
+#else
+	/* I find the above code a bit hairy. I find the below code
+           easier to read and shorter. Now, if it works too that would
+	   be great... -- REW 
+	*/
+	rio_dprint(RIO_DEBUG_TTY, ("Checking if RTA has booted... \n"));
+	while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+	  if (!PortP->WaitUntilBooted) {
+	    rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n"));
+	    return -ENXIO;
+	  }
+
+	  /* Under Linux you'd normally use a wait instead of this
+	     busy-waiting. I'll stick with the old implementation for
+	     now. --REW 
+	  */
+	  if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+	    rio_dprint(RIO_DEBUG_TTY, ("RTA_wait_for_boot: EINTR in delay \n"));
+	    return -EINTR;
+	  }
+	  if (repeat_this -- <= 0) {
+	    rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n"));
+	    return -EIO;
+	  }
+	}
+	rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n"));
+#endif
+#if 0
+	tp =  PortP->TtyP;		/* get tty struct */
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+#if 0
+	retval = gs_init_port(&PortP->gs);
+	if (retval)
+	  return retval;
+#endif
+
+	/*
+	** If the port is in the final throws of being closed,
+	** we should wait here (politely), waiting
+	** for it to finish, so that it doesn't close us!
+	*/
+	while ( (PortP->State & RIO_CLOSING) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting for RIO_CLOSING to go away\n"));
+		if (repeat_this -- <= 0) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n"));
+			RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+			rio_spin_lock_irqsave(&PortP->portSem, flags); 
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags); 
+	}
+
+	if ( !PortP->Mapped ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Port unmapped while closing!\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		retval = -ENXIO;
+		return retval;
+	}
+
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,
+** we need to make sure that the flags are clear when the port is opened.
+*/
+	/* Uh? Suppose I turn these on and then another process opens
+	   the port again? The flags get cleared! Not good. -- REW */
+	if ( !(PortP->State & (RIO_LOPEN | RIO_MOPEN)) ) {
+		PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
+	}
+
+	if (!(PortP->firstOpen)) {	/* First time ? */
+		rio_dprint(RIO_DEBUG_TTY, ("First open for this port\n"));
+		rio_inc_mod_count ();
+
+		PortP->firstOpen++;
+		PortP->CookMode = 0; /* XXX RIOCookMode(tp); */
+		PortP->InUse = NOT_INUSE;
+
+		/* Tentative fix for bug PR27. Didn't work. */
+		/* PortP->gs.xmit_cnt = 0; */
+
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+#ifdef NEED_THIS
+		ttyseth(PortP, tp, (struct old_sgttyb *)&default_sg);
+#endif
+
+		/* Someone explain to me why this delay/config is
+                   here. If I read the docs correctly the "open"
+                   command piggybacks the parameters immediately. 
+		   -- REW */
+		RIOParam(PortP,OPEN,Modem,OK_TO_SLEEP);		/* Open the port */
+#if 0
+		/* This delay of 1 second was annoying. I removed it. -- REW */
+		RIODelay(PortP, HUNDRED_MS*10);
+		RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	/* Config the port */
+#endif
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		/*
+		** wait for the port to be not closed.
+		*/
+		while ( !(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted ) {
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState));
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+** Take out the limited wait - now wait for ever or until user
+** bangs us out.
+**
+			if (repeat_this -- <= 0) {
+				rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish timed out.\n"));
+				RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				return -EINTR;
+			}
+**
+*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+				rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish broken by signal\n"));
+				RIOPreemptiveCmd(p, PortP, FCLOSE );
+				return -EINTR;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		}
+
+		if ( p->RIOHalted ) {
+		  retval = -EIO;
+bombout:
+		  /* 			RIOClearUp( PortP ); */
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return retval;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("PORT_ISOPEN found\n"));
+	}
+
+#ifdef MODEM_SUPPORT 
+	if (Modem) {
+		rio_dprint(RIO_DEBUG_TTY, ("Modem - test for carrier\n"));
+		/*
+		** ACTION
+		** insert test for carrier here. -- ???
+		** I already see that test here. What's the deal? -- REW
+		*/
+		if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD))
+		{
+			rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) Modem carr on\n",SysPort));
+			tp->tm.c_state |= CARR_ON;
+			wakeup((caddr_t) &tp->tm.c_canq);
+		}
+		else /* no carrier - wait for DCD */
+		{
+			while (!(tp->tm.c_state&CARR_ON) && 
+			       !(filp->f_flags&O_NONBLOCK) && !p->RIOHalted )
+			{
+				rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) sleeping for carr on\n",SysPort));
+				tp->tm.c_state |= WOPEN;
+				PortP->State |= RIO_WOPEN;
+				if ( sleep((caddr_t)&tp->tm.c_canq, TTIPRI|PCATCH))
+				{
+					/*
+					** ACTION: verify that this is a good thing
+					** to do here. -- ???
+					** I think it's OK. -- REW
+					*/
+					rio_dprint(RIO_DEBUG_TTY, ("open(%d) sleeping for carr broken by signal\n",
+					       SysPort));
+					RIOPreemptiveCmd( p, PortP, FCLOSE );
+					tp->tm.c_state &= ~WOPEN;
+					PortP->State &= ~RIO_WOPEN;
+					rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					return -EINTR;
+				}
+			}
+			PortP->State &= ~RIO_WOPEN;
+		}
+		if ( RIOHalted )
+			goto bombout;
+		PortP->State |= RIO_MOPEN;
+	}
+	else
+#endif
+	{
+		/*
+		** ACTION
+		** Direct line open - force carrier (will probably mean
+		** that sleeping Modem line fubar)
+		*/
+		PortP->State |= RIO_LOPEN;
+	}
+
+	if ( p->RIOHalted ) {
+		goto bombout;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("high level open done\n"));
+
+#ifdef STATS
+	PortP->Stat.OpenCnt++;
+#endif
+	/*
+	** Count opens for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->opens++;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Returning from open\n"));
+	return 0;
+}
+
+/*
+** RIOClose the port.
+** The operating system thinks that this is last close for the device.
+** As there are two interfaces to the port (Modem and tty), we need to
+** check that both are closed before we close the device.
+*/ 
+int
+riotclose(void  *ptr)
+{
+#if 0
+	register uint SysPort = dev;
+	struct ttystatics *tp;		/* pointer to our ttystruct */
+#endif
+	struct Port *PortP =ptr;	/* pointer to the port structure */
+	int deleted = 0;
+	int	try = 25;
+	int	repeat_this = 0xff;
+	struct tty_struct * tty;
+	unsigned long flags;
+	int Modem;
+	int rv =0;
+	
+	rio_dprint(RIO_DEBUG_TTY, ("port close SysPort %d\n",PortP->PortNum));
+
+	/* PortP = p->RIOPortp[SysPort]; */
+	rio_dprint(RIO_DEBUG_TTY, ("Port is at address 0x%x\n",(int)PortP));
+	/* tp = PortP->TtyP;*/			/* Get tty */
+	tty = PortP->gs.tty;
+	rio_dprint(RIO_DEBUG_TTY, ("TTY is at address 0x%x\n",(int)tty));
+	Modem = rio_ismodem(tty->device);
+#if 0
+	/* What F.CKING cache? Even then, a higly idle multiprocessor,
+	   system with large caches this won't work . Better find out when 
+	   this doesn't work asap, and fix the cause.  -- REW */
+	
+	RIODelay(PortP, HUNDRED_MS*10);	/* To flush the cache */
+#endif
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	** Setting this flag will make any process trying to open
+	** this port block until we are complete closing it.
+	*/
+	PortP->State |= RIO_CLOSING;
+
+	if ( (PortP->State & RIO_DELETED) ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Close on deleted RTA\n"));
+		deleted = 1;
+	}
+	
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rv = -EIO;
+		goto close_end;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("Clear bits\n"));
+	/*
+	** clear the open bits for this device
+	*/
+	PortP->State &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN);
+
+	/*
+	** If the device was open as both a Modem and a tty line
+	** then we need to wimp out here, as the port has not really
+	** been finally closed (gee, whizz!) The test here uses the
+	** bit for the OTHER mode of operation, to see if THAT is
+	** still active!
+	*/
+	if ( (PortP->State & (RIO_LOPEN|RIO_MOPEN)) ) {
+		/*
+		** The port is still open for the other task -
+		** return, pretending that we are still active.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("Channel %d still open !\n",PortP->PortNum));
+		PortP->State &= ~RIO_CLOSING;
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+	rio_dprint(RIO_DEBUG_TTY, ("Closing down - everything must go!\n"));
+
+	PortP->State &= ~RIO_DYNOROD;
+
+	/*
+	** This is where we wait for the port
+	** to drain down before closing. Bye-bye....
+	** (We never meant to do this)
+	*/
+	rio_dprint(RIO_DEBUG_TTY, ("Timeout 1 starts\n"));
+
+#if 0
+	if (!deleted)
+	while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted && 
+		(PortP->TxBufferIn != PortP->TxBufferOut) ) {
+		cprintf("Need to flush the ttyport\n");
+		if (repeat_this -- <= 0) {
+			rv = -EINTR;
+			rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n"));
+			RIOPreemptiveCmd(p, PortP, FCLOSE ); 
+			goto close_end;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("Calling timeout to flush in closing\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (RIODelay_ni(PortP, HUNDRED_MS*10) == RIO_FAIL) {
+			rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n"));
+			rv = -EINTR;
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			goto close_end;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+#endif
+	PortP->TxBufferIn = PortP->TxBufferOut = 0;
+	repeat_this = 0xff;
+
+	PortP->InUse = 0;
+	if ( (PortP->State & (RIO_LOPEN|RIO_MOPEN)) ) {
+		/*
+		** The port has been re-opened for the other task -
+		** return, pretending that we are still active.
+		*/
+		rio_dprint(RIO_DEBUG_TTY, ("Channel %d re-open!\n", PortP->PortNum));
+		PortP->State &= ~RIO_CLOSING;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		return -EIO;
+	}
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		goto close_end;
+	}
+
+	
+
+	/* Can't call RIOShortCommand with the port locked. */
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
+	  RIOPreemptiveCmd(p, PortP,FCLOSE);
+	  goto close_end;
+	}
+
+	if (!deleted)
+	  while (try && (PortP->PortState & PORT_ISOPEN)) {
+	        try--;
+		if (try == 0) {
+		  rio_dprint(RIO_DEBUG_TTY, ("Run out of tries - force the bugger shut!\n" ));
+		  RIOPreemptiveCmd(p, PortP,FCLOSE);
+		  break;
+		}
+		rio_dprint(RIO_DEBUG_TTY, ("Close: PortState:ISOPEN is %d\n", 
+					   PortP->PortState & PORT_ISOPEN));
+
+		if ( p->RIOHalted ) {
+			RIOClearUp( PortP );
+			goto close_end;
+		}
+		RIODelay_ni(PortP, HUNDRED_MS);
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Close: try was %d on completion\n", try ));
+ 
+	/* RIOPreemptiveCmd(p, PortP, FCLOSE); */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened.
+*/
+	PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
+
+
+#ifdef STATS
+	PortP->Stat.CloseCnt++;
+#endif
+	/*
+	** Count opens for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->closes++;
+
+close_end:
+	/* XXX: Why would a "DELETED" flag be reset here? I'd have
+	   thought that a "deleted" flag means that the port was
+	   permanently gone, but here we can make it reappear by it
+	   being in close during the "deletion".
+	*/
+	PortP->State &= ~(RIO_CLOSING|RIO_DELETED);
+	if (PortP->firstOpen)
+		PortP->firstOpen--;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprint(RIO_DEBUG_TTY, ("Return from close\n"));
+	return rv;
+}
+
+
+/*
+** decide if we need to use the line discipline.
+** This routine can return one of three values:
+** COOK_RAW if no processing has to be done by the line discipline or the card
+** COOK_WELL if the line discipline must be used to do the processing
+** COOK_MEDIUM if the card can do all the processing necessary.
+*/
+int
+RIOCookMode(struct ttystatics *tp)
+{
+	/*
+	** We cant handle tm.c_mstate != 0 on SCO
+	** We cant handle mapping
+	** We cant handle non-ttwrite line disc.
+	** We cant handle lflag XCASE
+	** We can handle oflag OPOST & (OCRNL, ONLCR, TAB3)
+	*/
+
+#ifdef CHECK
+	CheckTtyP( tp );
+#endif
+	if (!(tp->tm.c_oflag & OPOST))	/* No post processing */
+		return COOK_RAW;	/* Raw mode o/p */
+
+	if ( tp->tm.c_lflag & XCASE )
+		return COOK_WELL;	/* Use line disc */
+
+	if (tp->tm.c_oflag & ~(OPOST | ONLCR | OCRNL | TAB3 ) )
+		return COOK_WELL;	/* Use line disc for strange modes */
+
+	if ( tp->tm.c_oflag == OPOST )	/* If only OPOST is set, do RAW */
+		return COOK_RAW;
+
+	/*
+	** So, we need to output process!
+	*/
+	return COOK_MEDIUM;
+}
+
+
+static void
+RIOClearUp(PortP)
+struct Port *PortP;
+{
+	rio_dprint(RIO_DEBUG_TTY, ("RIOHalted set\n"));
+	PortP->Config = 0;	  /* Direct semaphore */
+	PortP->PortState = 0;
+	PortP->firstOpen = 0;
+	PortP->FlushCmdBodge = 0;
+	PortP->ModemState = PortP->CookMode = 0;
+	PortP->Mapped = 0;
+	PortP->WflushFlag = 0;
+	PortP->MagicFlags	= 0;
+	PortP->RxDataStart = 0;
+	PortP->TxBufferIn = 0;
+	PortP->TxBufferOut = 0;
+}
+
+/*
+** Put a command onto a port.
+** The PortPointer, command, length and arg are passed.
+** The len is the length *inclusive* of the command byte,
+** and so for a command that takes no data, len==1.
+** The arg is a single byte, and is only used if len==2.
+** Other values of len aren't allowed, and will cause
+** a panic.
+*/
+static int RIOShortCommand(struct rio_info *p, struct Port *PortP,
+		int command, int len, int arg)
+{
+	PKT *PacketP;
+	int		retries = 20; /* at 10 per second -> 2 seconds */
+	unsigned long flags;
+
+	rio_dprint(RIO_DEBUG_TTY, ("entering shortcommand.\n"));
+#ifdef CHECK
+	CheckPortP( PortP );
+	if ( len < 1 || len > 2 )
+		cprintf(("STUPID LENGTH %d\n",len));
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n"));
+		return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	** If the port is in use for pre-emptive command, then wait for it to 
+	** be free again.
+	*/
+	while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting for not in use (%d)\n", 
+					   retries));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+			return RIO_FAIL;
+		}
+		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+	if ( PortP->State & RIO_DELETED ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n"));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	while ( !can_add_transmit(&PacketP,PortP) && !p->RIOHalted ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Waiting to add short command to queue (%d)\n", retries));
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+		  rio_dprint(RIO_DEBUG_TTY, ("out of tries. Failing\n"));
+			return RIO_FAIL;
+		}
+		if ( RIODelay_ni(PortP, HUNDRED_MS)==RIO_FAIL ) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if ( p->RIOHalted ) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	/*
+	** set the command byte and the argument byte
+	*/
+	WBYTE(PacketP->data[0] , command);
+
+	if ( len==2 )
+		WBYTE(PacketP->data[1] , arg);
+
+	/*
+	** set the length of the packet and set the command bit.
+	*/
+	WBYTE(PacketP->len , PKT_CMD_BIT | len);
+
+	add_transmit(PortP);
+	/*
+	** Count characters transmitted for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->txchars += len;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL;
+}
+
+
+#if 0
+/*
+** This is an ioctl interface. This is the twentieth century. You know what
+** its all about.
+*/
+int
+riotioctl(p, dev, cmd, arg)
+struct rio_info *		p;
+dev_t dev;
+register int cmd;
+register caddr_t arg;
+{
+	register struct		Port *PortP;
+	register struct		ttystatics *tp;
+	int					current;
+	int					ParamSemIncremented = 0;
+	int					old_oflag, old_cflag, old_iflag, changed, oldcook;
+	int					i;
+	unsigned char		sio_regs[5];		/* Here be magic */
+	short				vpix_cflag;
+	short				divisor;
+	int					baud;
+	uint				SysPort = dev;
+	int					Modem = rio_ismodem(dev);
+	int					ioctl_processed;
+
+	rio_dprint(RIO_DEBUG_TTY, ("port ioctl SysPort %d command 0x%x argument 0x%x %s\n",
+			SysPort,cmd,arg,Modem?"Modem":"tty"));
+
+	if ( SysPort >= RIO_PORTS ) {
+		rio_dprint(RIO_DEBUG_TTY, ("Bad port number %d\n",SysPort));
+		return -ENXIO;
+	}
+
+	PortP = p->RIOPortp[SysPort];
+	tp = PortP->TtyP;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+#ifdef STATS
+	PortP->Stat.IoctlCnt++;
+#endif
+
+	if ( PortP->State & RIO_DELETED ) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+	/*
+	** Count ioctls for port statistics reporting
+	*/
+	if (PortP->statsGather)
+		PortP->ioctls++;
+
+	/*
+	** Specialix RIO Ioctl calls
+	*/
+	switch (cmd) {
+
+		case TCRIOTRIAD:
+			if ( arg )
+				PortP->State |= RIO_TRIAD_MODE;
+			else
+				PortP->State &= ~RIO_TRIAD_MODE;
+			/*
+			** Normally, when istrip is set on a port, a config is
+			** sent to the RTA instructing the CD1400 to do the
+			** stripping. In TRIAD mode, the interrupt receive routine
+			** must do the stripping instead, since it has to detect
+			** an 8 bit function key sequence. If istrip is set with
+			** TRIAD mode on(off), and 8 bit data is being read by
+			** the port, the user then turns TRIAD mode off(on), the RTA
+			** must be reconfigured (not) to do the stripping.
+			** Hence we call RIOParam here.
+			*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIOTSTATE:
+			rio_dprint(RIO_DEBUG_TTY, ("tbusy/tstop monitoring %sabled\n",
+		 		arg ? "en" : "dis"));
+			/* MonitorTstate = 0 ;*/
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP, CONFIG, Modem, OK_TO_SLEEP);
+			return 0;
+
+		case TCRIOSTATE: /* current state of Modem input pins */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE\n"));
+			if (RIOPreemptiveCmd(p, PortP, MGET) == RIO_FAIL)
+				rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE command failed\n"));
+			PortP->State |= RIO_BUSY;
+			current = PortP->ModemState;
+			if ( copyout((caddr_t)&current, (int)arg,
+							sizeof(current))==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyout failed\n"));
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOMBIS:		/* Set modem lines */
+		case TCRIOMBIC:		/* Clear modem lines */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIS/TCRIOMBIC\n"));
+			if (cmd == TCRIOMBIS) {
+				uint		state;
+				state = (uint)arg;
+				PortP->ModemState |= (ushort)state;
+				PortP->ModemLines = (ulong) arg;
+				if (RIOPreemptiveCmd(p, PortP, MBIS) == RIO_FAIL)
+					rio_dprint(RIO_DEBUG_TTY, (
+					 "TCRIOMBIS command failed\n"));
+			}
+			else {
+				uint		state;
+
+				state = (uint)arg;
+				PortP->ModemState &= ~(ushort)state;
+				PortP->ModemLines = (ulong) arg;
+				if (RIOPreemptiveCmd(p, PortP, MBIC) == RIO_FAIL)
+					rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIC command failed\n"));
+			}
+			PortP->State |= RIO_BUSY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPON: /* set Xprint ON string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPON\n"));
+			if ( copyin((int)arg, (caddr_t)PortP->Xprint.XpOn,
+						MAX_XP_CTRL_LEN)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n"));
+				PortP->Xprint.XpOn[0] = '\0';
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0';
+			PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+												RIOStrlen(PortP->Xprint.XpOff);
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPOFF: /* set Xprint OFF string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPOFF\n"));
+			if ( copyin( (int)arg, (caddr_t)PortP->Xprint.XpOff,
+						MAX_XP_CTRL_LEN)==COPYFAIL ) {
+				rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n"));
+				PortP->Xprint.XpOff[0] = '\0';
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0';
+			PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+										RIOStrlen(PortP->Xprint.XpOff);
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPCPS: /* set Xprint CPS string */
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPCPS\n"));
+			if ( (uint)arg > p->RIOConf.MaxXpCps || 
+					(uint)arg < p->RIOConf.MinXpCps ) {
+				rio_dprint(RIO_DEBUG_TTY, ("%d CPS out of range\n",arg));
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EINVAL);
+				return 0;
+			}
+			PortP->Xprint.XpCps = (uint)arg;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOXPRINT:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPRINT\n"));
+			if ( copyout((caddr_t)&PortP->Xprint, (int)arg,
+					sizeof(struct Xprint))==COPYFAIL ) {
+			        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				pseterr(EFAULT);
+			}
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXANYON:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYON\n"));
+			PortP->Config |= RIO_IXANY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXANYOFF:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYOFF\n"));
+			PortP->Config &= ~RIO_IXANY;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXONON:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONON\n"));
+			PortP->Config |= RIO_IXON;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+		case TCRIOIXONOFF:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONOFF\n"));
+			PortP->Config &= ~RIO_IXON;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** Added support for CTS and RTS flow control ioctls :
+*/
+		case TCRIOCTSFLOWEN:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWEN\n"));
+			PortP->Config |= RIO_CTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIOCTSFLOWDIS:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWDIS\n"));
+			PortP->Config &= ~RIO_CTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIORTSFLOWEN:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWEN\n"));
+			PortP->Config |= RIO_RTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+		case TCRIORTSFLOWDIS:
+			rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWDIS\n"));
+			PortP->Config &= ~RIO_RTSFLOW;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+			return 0;
+
+/* end ESIL 0761 part fix */
+
+	}
+
+
+	/* Lynx IOCTLS */
+	switch (cmd) {
+		case TIOCSETP:
+		case TIOCSETN:
+		case OTIOCSETP:
+		case OTIOCSETN:
+			ioctl_processed++;
+			ttyseth(PortP, tp, (struct old_sgttyb *)arg);
+			break;
+		case TCSETA:
+		case TCSETAW:
+		case TCSETAF:
+			ioctl_processed++;
+			rio_dprint(RIO_DEBUG_TTY, ("NON POSIX ioctl\n"));
+			ttyseth_pv(PortP, tp, (struct termios *)arg, 0);
+			break;
+		case TCSETAP:	/* posix tcsetattr() */
+		case TCSETAWP:	/* posix tcsetattr() */
+		case TCSETAFP:	/* posix tcsetattr() */
+			rio_dprint(RIO_DEBUG_TTY, ("NON POSIX SYSV ioctl\n"));
+			ttyseth_pv(PortP, tp, (struct termios *)arg, 1);
+			ioctl_processed++;
+			break;
+	}
+
+	/*
+	** If its any of the commands that require the port to be in the
+	** non-busy state wait until all output has drained 
+	*/
+	if (!ioctl_processed)
+	switch(cmd) {
+		case TCSETAW:
+		case TCSETAF:
+		case TCSETA:
+		case TCSBRK:
+#define OLD_POSIX ('x' << 8)
+#define OLD_POSIX_SETA (OLD_POSIX | 2)
+#define OLD_POSIX_SETAW (OLD_POSIX | 3)
+#define OLD_POSIX_SETAF (OLD_POSIX | 4)
+#define NEW_POSIX (('i' << 24) | ('X' << 16))
+#define NEW_POSIX_SETA (NEW_POSIX | 2)
+#define NEW_POSIX_SETAW (NEW_POSIX | 3)
+#define NEW_POSIX_SETAF (NEW_POSIX | 4)
+		case OLD_POSIX_SETA:
+		case OLD_POSIX_SETAW:
+		case OLD_POSIX_SETAF:
+		case NEW_POSIX_SETA:
+		case NEW_POSIX_SETAW:
+		case NEW_POSIX_SETAF:
+#ifdef TIOCSETP
+		case TIOCSETP:
+#endif
+		case TIOCSETD:
+		case TIOCSETN:
+			rio_dprint(RIO_DEBUG_TTY, ("wait for non-BUSY, semaphore set\n"));
+			/*
+			** Wait for drain here, at least as far as the double buffer
+			** being empty.
+			*/
+			/* XXX Does the above comment mean that this has
+			   still to be implemented? -- REW */
+			/* XXX Is the locking OK together with locking
+                           in txenable? (Deadlock?) -- REW */
+			
+			RIOTxEnable((char *)PortP);
+			break;
+		default:
+			break;
+	}
+
+	old_cflag = tp->tm.c_cflag;
+	old_iflag = tp->tm.c_iflag;
+	old_oflag = tp->tm.c_oflag;
+	oldcook = PortP->CookMode;
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		pseterr(EIO);
+		return 0;
+	}
+
+	PortP->FlushCmdBodge = 0;
+
+	/*
+	** If the port is locked, and it is reconfigured, we want
+	** to restore the state of the tty structure so the change is NOT
+	** made.
+	*/
+	if (PortP->Lock) {
+		tp->tm.c_iflag = PortP->StoredTty.iflag;
+		tp->tm.c_oflag = PortP->StoredTty.oflag;
+		tp->tm.c_cflag = PortP->StoredTty.cflag;
+		tp->tm.c_lflag = PortP->StoredTty.lflag;
+		tp->tm.c_line = PortP->StoredTty.line;
+		for (i = 0; i < NCC + 1; i++)
+			tp->tm.c_cc[i] = PortP->StoredTty.cc[i];
+	}
+	else {
+		/*
+		** If the port is set to store the parameters, and it is
+		** reconfigured, we want to save the current tty struct so it
+		** may be restored on the next open.
+		*/
+		if (PortP->Store) {
+			PortP->StoredTty.iflag = tp->tm.c_iflag;
+			PortP->StoredTty.oflag = tp->tm.c_oflag;
+			PortP->StoredTty.cflag = tp->tm.c_cflag;
+			PortP->StoredTty.lflag = tp->tm.c_lflag;
+			PortP->StoredTty.line = tp->tm.c_line;
+			for (i = 0; i < NCC + 1; i++)
+				PortP->StoredTty.cc[i] = tp->tm.c_cc[i];
+		}
+	}
+
+	changed = (tp->tm.c_cflag != old_cflag) ||
+				(tp->tm.c_iflag != old_iflag) ||
+				(tp->tm.c_oflag != old_oflag);
+
+	PortP->CookMode = RIOCookMode(tp);	/* Set new cooking mode */
+
+	rio_dprint(RIO_DEBUG_TTY, ("RIOIoctl changed %d newcook %d oldcook %d\n",
+			changed,PortP->CookMode,oldcook));
+
+#ifdef MODEM_SUPPORT
+	/*
+	** kludge to force CARR_ON if CLOCAL set
+	*/
+	if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD))	{
+		tp->tm.c_state |= CARR_ON;
+		wakeup ((caddr_t)&tp->tm.c_canq);
+	}
+#endif
+
+	if ( p->RIOHalted ) {
+		RIOClearUp( PortP );
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		pseterr(EIO);
+		return 0;
+	}
+	/*
+	** Re-configure if modes or cooking have changed
+	*/
+	if (changed || oldcook != PortP->CookMode || (ioctl_processed)) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		rio_dprint(RIO_DEBUG_TTY, ("Ioctl changing the PORT settings\n"));
+		RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP);	
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if (p->RIOHalted) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		RIOClearUp( PortP );
+		pseterr(EIO);
+		return 0;
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return 0;
+}
+
+/*
+	ttyseth -- set hardware dependant tty settings
+*/
+void
+ttyseth(PortP, s, sg)
+struct Port *		PortP;
+struct ttystatics *		s;
+struct old_sgttyb *sg;
+{
+	struct old_sgttyb *	tsg;
+	struct termios *tp = &s->tm;
+
+	tsg = &s->sg;
+
+	if (sg->sg_flags & (EVENP|ODDP))  {
+		tp->c_cflag &= PARENB;
+		if (sg->sg_flags & EVENP) {
+			if (sg->sg_flags & ODDP) {
+				tp->c_cflag &= V_CS7;
+				tp->c_cflag &= ~PARENB;
+			}
+			else {
+				tp->c_cflag &= V_CS7;
+				tp->c_cflag &= PARENB;
+				tp->c_cflag &= PARODD;
+			}
+		}
+		else if (sg->sg_flags & ODDP) {
+			tp->c_cflag &= V_CS7;
+			tp->c_cflag &= PARENB;
+			tp->c_cflag &= PARODD;
+		}
+		else {
+			tp->c_cflag &= V_CS7;
+			tp->c_cflag &= PARENB;
+		}
+	}
+/*
+ * Use ispeed as the desired speed.  Most implementations don't handle 
+ * separate input and output speeds very well. If the RIO handles this, 
+ * I will have to use separate sets of flags to store them in the 
+ * Port structure.
+ */
+	if ( !sg->sg_ospeed )
+		sg->sg_ospeed = sg->sg_ispeed;
+	else
+		sg->sg_ispeed = sg->sg_ospeed;
+	if (sg->sg_ispeed > V_EXTB ) 
+		sg->sg_ispeed = V_EXTB;
+	if (sg->sg_ispeed < V_B0)
+		sg->sg_ispeed = V_B0;
+	*tsg = *sg;
+   tp->c_cflag = (tp->c_cflag & ~V_CBAUD) | conv_bv[(int)sg->sg_ispeed];
+}
+
+/*
+	ttyseth_pv -- set hardware dependant tty settings using either the
+			POSIX termios structure or the System V termio structure.
+				sysv = 0 => (POSIX):	 struct termios *sg
+				sysv != 0 => (System V): struct termio *sg
+*/
+static void
+ttyseth_pv(PortP, s, sg, sysv)
+struct Port *PortP;
+struct ttystatics *s;
+struct termios *sg;
+int sysv;
+{
+    int speed;
+    unsigned char csize;
+    unsigned char cread;
+    unsigned int lcr_flags;
+    int ps;
+ 
+    if (sysv) {
+        /* sg points to a System V termio structure */
+        csize = ((struct termio *)sg)->c_cflag & CSIZE;
+        cread = ((struct termio *)sg)->c_cflag & CREAD;
+        speed = conv_vb[((struct termio *)sg)->c_cflag & V_CBAUD];
+    }
+    else {
+        /* sg points to a POSIX termios structure */
+        csize = sg->c_cflag & CSIZE;
+        cread = sg->c_cflag & CREAD;
+        speed = conv_vb[sg->c_cflag & V_CBAUD];
+    }
+    if (s->sg.sg_ispeed != speed || s->sg.sg_ospeed != speed) {
+        s->sg.sg_ispeed = speed;
+        s->sg.sg_ospeed = speed;
+        s->tm.c_cflag = (s->tm.c_cflag & ~V_CBAUD) |
+                         conv_bv[(int)s->sg.sg_ispeed];
+    }
+}
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riotypes.h linux/drivers/char/rio/riotypes.h
--- v2.3.99-pre6/linux/drivers/char/rio/riotypes.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riotypes.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,135 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      R I O T Y P E S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jon Brawn
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _riotypes_h
+#define _riotypes_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_riotypes_h_sccs = "@(#)riotypes.h	1.10"; */
+#endif
+#endif
+
+#ifdef INKERNEL
+
+#if !defined(MIPSAT)
+typedef unsigned short NUMBER_ptr;
+typedef unsigned short WORD_ptr;
+typedef unsigned short BYTE_ptr;
+typedef unsigned short char_ptr;
+typedef unsigned short Channel_ptr;
+typedef unsigned short FREE_LIST_ptr_ptr;
+typedef unsigned short FREE_LIST_ptr;
+typedef unsigned short LPB_ptr;
+typedef unsigned short Process_ptr;
+typedef unsigned short PHB_ptr;
+typedef unsigned short PKT_ptr;
+typedef unsigned short PKT_ptr_ptr;
+typedef unsigned short Q_BUF_ptr;
+typedef unsigned short Q_BUF_ptr_ptr;
+typedef unsigned short ROUTE_STR_ptr;
+typedef unsigned short RUP_ptr;
+typedef unsigned short short_ptr;
+typedef unsigned short u_short_ptr;
+typedef unsigned short ushort_ptr;
+#else
+/* MIPSAT types */
+typedef char RIO_POINTER[8];
+typedef RIO_POINTER NUMBER_ptr;
+typedef RIO_POINTER WORD_ptr;
+typedef RIO_POINTER BYTE_ptr;
+typedef RIO_POINTER char_ptr;
+typedef RIO_POINTER Channel_ptr;
+typedef RIO_POINTER FREE_LIST_ptr_ptr;
+typedef RIO_POINTER FREE_LIST_ptr;
+typedef RIO_POINTER LPB_ptr;
+typedef RIO_POINTER Process_ptr;
+typedef RIO_POINTER PHB_ptr;
+typedef RIO_POINTER PKT_ptr;
+typedef RIO_POINTER PKT_ptr_ptr;
+typedef RIO_POINTER Q_BUF_ptr;
+typedef RIO_POINTER Q_BUF_ptr_ptr;
+typedef RIO_POINTER ROUTE_STR_ptr;
+typedef RIO_POINTER RUP_ptr;
+typedef RIO_POINTER short_ptr;
+typedef RIO_POINTER u_short_ptr;
+typedef RIO_POINTER ushort_ptr;
+#endif
+
+#else /* not INKERNEL */
+typedef unsigned char   BYTE;
+typedef unsigned short  WORD;
+typedef unsigned long   DWORD;
+typedef short           NUMBER;
+typedef short           *NUMBER_ptr;
+typedef unsigned short  *WORD_ptr;
+typedef unsigned char   *BYTE_ptr;
+typedef unsigned char   uchar ;
+typedef unsigned short  ushort ;
+typedef unsigned int    uint ;
+typedef unsigned long   ulong ;
+typedef unsigned char   u_char ;
+typedef unsigned short  u_short ;
+typedef unsigned int    u_int ;
+typedef unsigned long   u_long ;
+typedef unsigned short  ERROR ;
+typedef unsigned long ID ;
+typedef char             *char_ptr;
+typedef Channel          *Channel_ptr;
+typedef struct FREE_LIST *FREE_LIST_ptr;
+typedef struct FREE_LIST **FREE_LIST_ptr_ptr;
+typedef struct LPB       *LPB_ptr;
+typedef struct Process   *Process_ptr;
+typedef struct PHB       *PHB_ptr;
+typedef struct PKT       *PKT_ptr;
+typedef struct PKT       **PKT_ptr_ptr;
+typedef struct Q_BUF     *Q_BUF_ptr;
+typedef struct Q_BUF     **Q_BUF_ptr_ptr;
+typedef struct ROUTE_STR *ROUTE_STR_ptr;
+typedef struct RUP       *RUP_ptr;
+typedef short            *short_ptr;
+typedef u_short          *u_short_ptr;
+typedef ushort           *ushort_ptr;
+typedef struct PKT	 PKT;
+typedef struct LPB	 LPB;
+typedef struct RUP	 RUP;
+#endif
+
+
+#endif /* __riotypes__ */
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riowinif.h linux/drivers/char/rio/riowinif.h
--- v2.3.99-pre6/linux/drivers/char/rio/riowinif.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riowinif.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,1335 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	RIO Shared Memory Window Inteface	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	7th June 1999				*/
+/*									*/
+/*	Version		:	1.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1999	*
+ *      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.
+ *									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing RIO host card shared	memory	*/
+/*				window interface structures:		*/
+/*					PARMMAP				*/
+/*					RUP				*/
+/*					PHB				*/
+/*					LPB				*/
+/*					PKT				*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+1.0.0	07/06/99 NPV	Creation. (based on PARMMAP.H)
+
+*/
+
+#ifndef	_riowinif_h				/* If RIOWINDIF.H not already defined */
+#define	_riowinif_h    1
+
+/*****************************************************************************
+********************************             *********************************
+********************************   General   *********************************
+********************************             *********************************
+*****************************************************************************/
+
+#define	TPNULL		((_u16)(0x8000))
+
+/*****************************************************************************
+********************************              ********************************
+********************************   PARM_MAP   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* The PARM_MAP structure defines global values relating to the Host Card / RTA
+   and is the main structure from which all other structures are referenced. */
+
+typedef	struct	_PARM_MAP
+{
+	_u16	phb_ptr;		/* 0x00 Pointer to the PHB array */
+	_u16	phb_num_ptr;		/* 0x02 Ptr to Number of PHB's */
+	_u16	free_list;		/* 0x04 Free List pointer */
+	_u16	free_list_end;		/* 0x06 Free List End pointer */
+	_u16	q_free_list_ptr;	/* 0x08 Ptr to Q_BUF variable */
+	_u16	unit_id_ptr;		/* 0x0A Unit Id */
+	_u16	link_str_ptr;		/* 0x0C Link Structure Array */
+	_u16	bootloader_1;		/* 0x0E 1st Stage Boot Loader */
+	_u16	bootloader_2;		/* 0x10 2nd Stage Boot Loader */
+	_u16	port_route_map_ptr;	/* 0x12 Port Route Map */
+	_u16	route_ptr;		/* 0x14 Route Map */
+	_u16	map_present;		/* 0x16 Route Map present */
+	_u16	pkt_num;		/* 0x18 Total number of packets */
+	_u16	q_num;			/* 0x1A Total number of Q packets */
+	_u16	buffers_per_port;	/* 0x1C Number of buffers per port */
+	_u16	heap_size;		/* 0x1E Initial size of heap */
+	_u16	heap_left;		/* 0x20 Current Heap left */
+	_u16	error;			/* 0x22 Error code */
+	_u16	tx_max;			/* 0x24 Max number of tx pkts per phb */
+	_u16	rx_max;			/* 0x26 Max number of rx pkts per phb */
+	_u16	rx_limit;		/* 0x28 For high / low watermarks */
+	_u16	links;			/* 0x2A Links to use */
+	_u16	timer;			/* 0x2C Interrupts per second */
+	_u16	rups;			/* 0x2E Pointer to the RUPs */
+	_u16	max_phb;		/* 0x30 Mostly for debugging */
+	_u16	living;			/* 0x32 Just increments!! */
+	_u16	init_done;		/* 0x34 Initialisation over */
+	_u16	booting_link;		/* 0x36 */
+	_u16	idle_count;		/* 0x38 Idle time counter */
+	_u16	busy_count;		/* 0x3A Busy counter */
+	_u16	idle_control;		/* 0x3C Control Idle Process */
+	_u16	tx_intr;		/* 0x3E TX interrupt pending */
+	_u16	rx_intr;		/* 0x40 RX interrupt pending */
+	_u16	rup_intr;		/* 0x42 RUP interrupt pending */
+
+} PARM_MAP;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PM_phb_ptr		0x00	/* 0x00 Pointer to the PHB array */
+#define	PM_phb_num_ptr		0x02	/* 0x02 Ptr to Number of PHB's */
+#define	PM_free_list		0x04	/* 0x04 Free List pointer */
+#define	PM_free_list_end	0x06	/* 0x06 Free List End pointer */
+#define	PM_q_free_list_ptr	0x08	/* 0x08 Ptr to Q_BUF variable */
+#define	PM_unit_id_ptr		0x0A	/* 0x0A Unit Id */
+#define	PM_link_str_ptr		0x0C	/* 0x0C Link Structure Array */
+#define	PM_bootloader_1		0x0E	/* 0x0E 1st Stage Boot Loader */
+#define	PM_bootloader_2		0x10	/* 0x10 2nd Stage Boot Loader */
+#define	PM_port_route_map_ptr	0x12	/* 0x12 Port Route Map */
+#define	PM_route_ptr		0x14	/* 0x14 Route Map */
+#define	PM_map_present		0x16	/* 0x16 Route Map present */
+#define	PM_pkt_num		0x18	/* 0x18 Total number of packets */
+#define	PM_q_num		0x1A	/* 0x1A Total number of Q packets */
+#define	PM_buffers_per_port	0x1C	/* 0x1C Number of buffers per port */
+#define	PM_heap_size		0x1E	/* 0x1E Initial size of heap */
+#define	PM_heap_left		0x20	/* 0x20 Current Heap left */
+#define	PM_error		0x22	/* 0x22 Error code */
+#define	PM_tx_max		0x24	/* 0x24 Max number of tx pkts per phb */
+#define	PM_rx_max		0x26	/* 0x26 Max number of rx pkts per phb */
+#define	PM_rx_limit		0x28	/* 0x28 For high / low watermarks */
+#define	PM_links		0x2A	/* 0x2A Links to use */
+#define	PM_timer		0x2C	/* 0x2C Interrupts per second */
+#define	PM_rups			0x2E	/* 0x2E Pointer to the RUPs */
+#define	PM_max_phb		0x30	/* 0x30 Mostly for debugging */
+#define	PM_living		0x32	/* 0x32 Just increments!! */
+#define	PM_init_done		0x34	/* 0x34 Initialisation over */
+#define	PM_booting_link		0x36	/* 0x36 */
+#define	PM_idle_count		0x38	/* 0x38 Idle time counter */
+#define	PM_busy_count		0x3A	/* 0x3A Busy counter */
+#define	PM_idle_control		0x3C	/* 0x3C Control Idle Process */
+#define	PM_tx_intr		0x3E	/* 0x4E TX interrupt pending */
+#define	PM_rx_intr		0x40	/* 0x40 RX interrupt pending */
+#define	PM_rup_intr		0x42	/* 0x42 RUP interrupt pending */
+#define	sizeof_PARM_MAP		0x44	/* structure size = 0x44 */
+
+/* PARM_MAP.error definitions... */
+#define	E_NO_ERROR		0x00
+#define	E_PROCESS_NOT_INIT	0x01
+#define	E_LINK_TIMEOUT		0x02
+#define	E_NO_ROUTE		0x03
+#define	E_CONFUSED		0x04
+#define	E_HOME			0x05
+#define	E_CSUM_FAIL		0x06
+#define	E_DISCONNECTED		0x07
+#define	E_BAD_RUP		0x08
+#define	E_NO_VIRGIN		0x09
+#define	E_BOOT_RUP_BUSY		0x10
+#define	E_CHANALLOC		0x80
+#define	E_POLL_ALLOC		0x81
+#define	E_LTTWAKE		0x82
+#define	E_LTT_ALLOC		0x83
+#define	E_LRT_ALLOC		0x84
+#define	E_CIRRUS		0x85
+#define	E_MONITOR		0x86
+#define	E_PHB_ALLOC		0x87
+#define	E_ARRAY_ALLOC		0x88
+#define	E_QBUF_ALLOC		0x89
+#define	E_PKT_ALLOC		0x8a
+#define	E_GET_TX_Q_BUF		0x8b
+#define	E_GET_RX_Q_BUF		0x8c
+#define	E_MEM_OUT		0x8d
+#define	E_MMU_INIT		0x8e
+#define	E_LTT_INIT		0x8f
+#define	E_LRT_INIT		0x90
+#define	E_LINK_RUN		0x91
+#define	E_MONITOR_ALLOC		0x92
+#define	E_MONITOR_INIT		0x93
+#define	E_POLL_INIT		0x94
+
+/* PARM_MAP.links definitions... */
+#define	RIO_LINK_ENABLE	0x80FF
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   RUP   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The RUP (Remote Unit Port) structure relates to the Remote Terminal Adapters
+   attached to the system and there is normally an array of MAX_RUPS (=16) structures
+   in a host card, defined by PARM_MAP->rup. */
+
+typedef	struct	_RUP
+{
+	_u16		txpkt;			/* 0x00 Outgoing packet */
+	_u16		rxpkt;			/* 0x02 ncoming packet */
+	_u16		link;			/* 0x04 Which link to send packet down ? */
+	_u8		rup_dest_unit[2];	/* 0x06 Destination Unit */
+	_u16		handshake;		/* 0x08 Handshaking */
+	_u16		timeout;		/* 0x0A Timeout */
+	_u16		status;			/* 0x0C Status */
+	_u16		txcontrol;		/* 0x0E Transmit control */
+	_u16		rxcontrol;		/* 0x10 Receive control */
+
+} RUP;
+
+/* Same thing again, but defined as offsets... */
+
+#define	RUP_txpkt		0x00		/* 0x00 Outgoing packet */
+#define	RUP_rxpkt		0x02		/* 0x02 Incoming packet */
+#define	RUP_link		0x04		/* 0x04 Which link to send packet down ? */
+#define	RUP_rup_dest_unit	0x06		/* 0x06 Destination Unit */
+#define	RUP_handshake		0x08		/* 0x08 Handshaking */
+#define	RUP_timeout		0x0A		/* 0x0A Timeout */
+#define	RUP_status		0x0C		/* 0x0C Status */
+#define	RUP_txcontrol		0x0E		/* 0x0E Transmit control */
+#define	RUP_rxcontrol		0x10		/* 0x10 Receive control */
+#define	sizeof_RUP		0x12		/* structure size = 0x12 */
+
+#define MAX_RUP			16
+
+/* RUP.txcontrol definitions... */
+#define	TX_RUP_INACTIVE		0		/* Nothing to transmit */
+#define	TX_PACKET_READY		1		/* Transmit packet ready */
+#define	TX_LOCK_RUP		2		/* Transmit side locked */
+
+/* RUP.txcontrol definitions... */
+#define	RX_RUP_INACTIVE		0		/* Nothing received */
+#define	RX_PACKET_READY		1		/* Packet received */
+
+#define	RUP_NO_OWNER		0xFF		/* RUP not owned by any process */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   PHB   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The PHB (Port Header Block) structure relates to the serial ports attached
+   to the system and there is normally an array of MAX_PHBS (=128) structures
+   in a host card, defined by PARM_MAP->phb_ptr and PARM_MAP->phb_num_ptr. */
+
+typedef	struct	_PHB
+{
+	_u16		source;			/* 0x00 Location of the PHB in the host card */
+	_u16		handshake;		/* 0x02 Used to manage receive packet flow control */
+	_u16		status;			/* 0x04 Internal port transmit/receive status */
+	_u16		timeout;		/* 0x06 Time period to wait for an ACK */
+	_u16		link;			/* 0x08 The host link associated with the PHB */
+	_u16		destination;		/* 0x0A Location of the remote port on the network */
+
+	_u16		tx_start;		/* 0x0C first entry in the packet array for transmit packets */
+	_u16		tx_end;			/* 0x0E last entry in the packet array for transmit packets */
+	_u16		tx_add;			/* 0x10 position in the packet array for new transmit packets */
+	_u16		tx_remove;		/* 0x12 current position in the packet pointer array */
+
+	_u16		rx_start;		/* 0x14 first entry in the packet array for receive packets */
+	_u16		rx_end;			/* 0x16 last entry in the packet array for receive packets */
+	_u16		rx_add;			/* 0x18 position in the packet array for new receive packets */
+	_u16		rx_remove;		/* 0x1A current position in the packet pointer array */
+
+} PHB;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PHB_source		0x00		/* 0x00 Location of the PHB in the host card */
+#define	PHB_handshake		0x02		/* 0x02 Used to manage receive packet flow control */
+#define	PHB_status		0x04		/* 0x04 Internal port transmit/receive status */
+#define	PHB_timeout		0x06		/* 0x06 Time period to wait for an ACK */
+#define	PHB_link		0x08		/* 0x08 The host link associated with the PHB */
+#define	PHB_destination		0x0A		/* 0x0A Location of the remote port on the network */
+#define	PHB_tx_start		0x0C		/* 0x0C first entry in the packet array for transmit packets */
+#define	PHB_tx_end		0x0E		/* 0x0E last entry in the packet array for transmit packets */
+#define	PHB_tx_add		0x10		/* 0x10 position in the packet array for new transmit packets */
+#define	PHB_tx_remove		0x12		/* 0x12 current position in the packet pointer array */
+#define	PHB_rx_start		0x14		/* 0x14 first entry in the packet array for receive packets */
+#define	PHB_rx_end		0x16		/* 0x16 last entry in the packet array for receive packets */
+#define	PHB_rx_add		0x18		/* 0x18 position in the packet array for new receive packets */
+#define	PHB_rx_remove		0x1A		/* 0x1A current position in the packet pointer array */
+#define	sizeof_PHB		0x1C		/* structure size = 0x1C */
+
+/* PHB.handshake definitions... */
+#define	PHB_HANDSHAKE_SET	0x0001		/* Set by LRT */
+#define	PHB_HANDSHAKE_RESET	0x0002		/* Set by ISR / driver */
+#define	PHB_HANDSHAKE_FLAGS	(PHB_HANDSHAKE_RESET|PHB_HANDSHAKE_SET)
+						/* Reset by ltt */
+
+#define	MAX_PHB			128		/* range 0-127 */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   LPB   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The LPB (Link Parameter Block) structure relates to a RIO Network Link
+   and there is normally an array of MAX_LINKS (=4) structures in a host card,
+   defined by PARM_MAP->link_str_ptr. */
+
+typedef	struct	_LPB
+{
+	_u16		link_number;		/* 0x00 Link Number */
+	_u16		in_ch;			/* 0x02 Link In Channel */
+	_u16		out_ch;			/* 0x04 Link Out Channel */
+	_u8		attached_serial[4];	/* 0x06 Attached serial number */
+	_u8		attached_host_serial[4];/* 0x0A Serial number of Host who booted other end */
+	_u16		descheduled;		/* 0x0E Currently Descheduled */
+	_u16		state;			/* 0x10 Current state */
+	_u16		send_poll;		/* 0x12 Send a Poll Packet */
+	_u16		ltt_p;			/* 0x14 Process Descriptor */
+	_u16		lrt_p;			/* 0x16 Process Descriptor */
+	_u16		lrt_status;		/* 0x18 Current lrt status */
+	_u16		ltt_status;		/* 0x1A Current ltt status */
+	_u16		timeout;		/* 0x1C Timeout value */
+	_u16		topology;		/* 0x1E Topology bits */
+	_u16		mon_ltt;		/* 0x20 */
+	_u16		mon_lrt;		/* 0x22 */
+	_u16		num_pkts;		/* 0x24 */
+	_u16		add_packet_list;	/* 0x26 Add packets to here */
+	_u16		remove_packet_list;	/* 0x28 Send packets from here */
+
+	_u16		lrt_fail_chan;		/* 0x2A Lrt's failure channel */
+	_u16		ltt_fail_chan;		/* 0x2C Ltt's failure channel */
+
+	RUP		rup;			/* 0x2E RUP structure for HOST to driver comms */
+	RUP		link_rup;		/* 0x40 RUP for the link (POLL, topology etc.) */
+	_u16		attached_link;		/* 0x52 Number of attached link */
+	_u16		csum_errors;		/* 0x54 csum errors */
+	_u16		num_disconnects;	/* 0x56 number of disconnects */
+	_u16		num_sync_rcvd;		/* 0x58 # sync's received */
+	_u16		num_sync_rqst;		/* 0x5A # sync requests */
+	_u16		num_tx;			/* 0x5C Num pkts sent */
+	_u16		num_rx;			/* 0x5E Num pkts received */
+	_u16		module_attached;	/* 0x60 Module tpyes of attached */
+	_u16		led_timeout;		/* 0x62 LED timeout */
+	_u16		first_port;		/* 0x64 First port to service */
+	_u16		last_port;		/* 0x66 Last port to service */
+
+} LPB;
+
+/* Same thing again, but defined as offsets... */
+
+#define	LPB_link_number		0x00		/* 0x00 Link Number */
+#define	LPB_in_ch		0x02		/* 0x02 Link In Channel */
+#define	LPB_out_ch		0x04		/* 0x04 Link Out Channel */
+#define	LPB_attached_serial	0x06		/* 0x06 Attached serial number */
+#define	LPB_attached_host_serial 0x0A		/* 0x0A Serial number of Host who booted other end */
+#define	LPB_descheduled		0x0E		/* 0x0E Currently Descheduled */
+#define	LPB_state		0x10		/* 0x10 Current state */
+#define	LPB_send_poll		0x12		/* 0x12 Send a Poll Packet */
+#define	LPB_ltt_p		0x14		/* 0x14 Process Descriptor */
+#define	LPB_lrt_p		0x16		/* 0x16 Process Descriptor */
+#define	LPB_lrt_status		0x18		/* 0x18 Current lrt status */
+#define	LPB_ltt_status		0x1A		/* 0x1A Current ltt status */
+#define	LPB_timeout		0x1C		/* 0x1C Timeout value */
+#define	LPB_topology		0x1E		/* 0x1E Topology bits */
+#define	LPB_mon_ltt		0x20		/* 0x20 */
+#define	LPB_mon_lrt		0x22		/* 0x22 */
+#define	LPB_num_pkts		0x24		/* 0x24 */
+#define	LPB_add_packet_list	0x26		/* 0x26 Add packets to here */
+#define	LPB_remove_packet_list	0x28		/* 0x28 Send packets from here */
+#define	LPB_lrt_fail_chan	0x2A		/* 0x2A Lrt's failure channel */
+#define	LPB_ltt_fail_chan	0x2C		/* 0x2C Ltt's failure channel */
+#define	LPB_rup			0x2E		/* 0x2E RUP structure for HOST to driver comms */
+#define	LPB_link_rup		0x40		/* 0x40 RUP for the link (POLL, topology etc.) */
+#define	LPB_attached_link	0x52		/* 0x52 Number of attached link */
+#define	LPB_csum_errors		0x54		/* 0x54 csum errors */
+#define	LPB_num_disconnects	0x56		/* 0x56 number of disconnects */
+#define	LPB_num_sync_rcvd	0x58		/* 0x58 # sync's received */
+#define	LPB_num_sync_rqst	0x5A		/* 0x5A # sync requests */
+#define	LPB_num_tx		0x5C		/* 0x5C Num pkts sent */
+#define	LPB_num_rx		0x5E		/* 0x5E Num pkts received */
+#define	LPB_module_attached	0x60		/* 0x60 Module tpyes of attached */
+#define	LPB_led_timeout		0x62		/* 0x62 LED timeout */
+#define	LPB_first_port		0x64		/* 0x64 First port to service */
+#define	LPB_last_port		0x66		/* 0x66 Last port to service */
+#define	sizeof_LPB		0x68		/* structure size = 0x68 */
+
+#define	LINKS_PER_UNIT		4		/* number of links from a host */
+
+/*****************************************************************************
+********************************               *******************************
+********************************   FREE_LIST   *******************************
+********************************               *******************************
+*****************************************************************************/
+
+/* Used to overlay packet headers when allocating/freeing packets from the free list */
+
+typedef	struct	_FREE_LIST
+{
+	_u16		next;			/* 0x00 offset of next list item */
+	_u16		prev;			/* 0x02 offset of previous list item */
+
+} FREE_LIST;
+
+/* Same thing again, but defined as offsets... */
+
+#define	FL_next			0x00		/* 0x00 offset of next list item */
+#define	FL_prev			0x02		/* 0x02 offset of previous list item */
+
+/*****************************************************************************
+**********************************         ***********************************
+**********************************   PKT   ***********************************
+**********************************         ***********************************
+*****************************************************************************/
+
+/* The PKT is the main unit of communication between Host Cards and RTAs across
+   the RIO network.  */
+
+#define PKT_MAX_DATA_LEN   72			/* Size of packet data */
+
+typedef	struct	_PKT
+{
+	_u8		dest_unit;		/* 0x00 Destination Unit Id */
+	_u8		dest_port;		/* 0x01 Destination Port */
+	_u8		src_unit;		/* 0x02 Source Unit Id */
+	_u8		src_port;		/* 0x03 Source Port */
+	_u8		len;			/* 0x04 Length (in bytes) of data field */
+	_u8		control;		/* 0x05 */
+	_u8		data[PKT_MAX_DATA_LEN];	/* 0x06 Actual data */
+	_u16		csum;			/* 0x4E C-SUM */
+
+} PKT;
+
+/* Same thing again, but defined as offsets... */
+
+#define	PKT_dest_unit		0x00		/* 0x00 Destination Unit Id */
+#define	PKT_dest_port		0x01		/* 0x01 Destination Port */
+#define	PKT_src_unit		0x02		/* 0x02 Source Unit Id */
+#define	PKT_src_port		0x03		/* 0x03 Source Port */
+#define	PKT_len			0x04		/* 0x04 Length (in bytes) of data field */
+#define	PKT_control		0x05		/* 0x05 */
+#define	PKT_data		0x06		/* 0x06 Actual data */
+#define	PKT_csum		0x4E		/* 0x4E C-SUM */
+#define	sizeof_PKT		0x50		/* structure size = 0x50 */
+
+/* PKT.len definitions... */
+#define	PKT_CMD_BIT		0x80
+#define	PKT_CMD_DATA		0x80
+#define	PKT_LEN_MASK		0x7F
+
+/* PKT.control definitions... */
+#define	PKT_ACK			0x40
+#define	PKT_TGL			0x20
+#define	DATA_WNDW		0x10
+#define	PKT_TTL_MASK		0x0F
+#define	MAX_TTL			0x0F
+
+/*****************************************************************************
+*****************************                     ****************************
+*****************************   Control Packets   ****************************
+*****************************                     ****************************
+*****************************************************************************/
+
+/* The following definitions and structures define the control packets sent
+   between the driver and RIO Ports, RTAs and Host Cards. */
+
+#define	PRE_EMPTIVE		0x80			/* Pre-emptive command (sent via port's RUP) */
+
+/* "in-band" and "pre-emptive" port commands... */
+#define	OPEN			0x00			/* Driver->RIO Open a port */
+#define	CONFIG			0x01			/* Driver->RIO Configure a port */
+#define	MOPEN			0x02			/* Driver->RIO Modem open (wait for DCD) */
+#define	CLOSE			0x03			/* Driver->RIO Close a port */
+#define	WFLUSH			(0x04|PRE_EMPTIVE)	/* Driver->RIO Write flush */
+#define	RFLUSH			(0x05|PRE_EMPTIVE)	/* Driver->RIO Read flush */
+#define	RESUME			(0x06|PRE_EMPTIVE)	/* Driver->RIO Behave as if XON received */
+#define	SBREAK			0x07			/* Driver->RIO Start break */
+#define	EBREAK			0x08			/* Driver->RIO End break */
+#define	SUSPEND			(0x09|PRE_EMPTIVE)	/* Driver->RIO Behave as if XOFF received */
+#define	FCLOSE			(0x0A|PRE_EMPTIVE)	/* Driver->RIO Force close */
+#define	XPRINT			0x0B			/* Driver->RIO Xprint packet */
+#define	MBIS			(0x0C|PRE_EMPTIVE)	/* Driver->RIO Set modem lines */
+#define	MBIC			(0x0D|PRE_EMPTIVE)	/* Driver->RIO Clear modem lines */
+#define	MSET			(0x0E|PRE_EMPTIVE)	/* Driver->RIO Set modem lines */
+#define	PCLOSE			0x0F			/* Driver->RIO Pseudo close */
+#define	MGET			(0x10|PRE_EMPTIVE)	/* Driver->RIO Force update of modem status */
+#define	MEMDUMP			(0x11|PRE_EMPTIVE)	/* Driver->RIO DEBUG request for RTA memory */
+#define	READ_REGISTER		(0x12|PRE_EMPTIVE)	/* Driver->RIO DEBUG read CD1400 register */
+
+/* Remote Unit Port (RUP) packet definitions... (specified in PKT.dest_unit and PKT.src_unit) */
+#define	SYNC_RUP		0xFF			/* Download internal */
+#define	COMMAND_RUP		0xFE			/* Command ack/status */
+#define	ERROR_RUP		0xFD			/* Download internal */
+#define	POLL_RUP		0xFC			/* Download internal */
+#define	BOOT_RUP		0xFB			/* Used to boot RTAs */
+#define	ROUTE_RUP		0xFA			/* Used to specify routing/topology */
+#define	STATUS_RUP		0xF9			/* Not used */
+#define	POWER_RUP		0xF8			/* Download internal */
+
+/* COMMAND_RUP definitions... */
+#define	COMPLETE		(0x20|PRE_EMPTIVE)	/* RIO->Driver Command complete */
+#define	BREAK_RECEIVED		(0x21|PRE_EMPTIVE)	/* RIO->Driver Break received */
+#define	MODEM_STATUS		(0x22|PRE_EMPTIVE)	/* RIO->Driver Modem status change */
+
+/* BOOT_RUP definitions... */
+#define	BOOT_REQUEST		0x00			/* RIO->Driver Request for boot */
+#define	BOOT_ABORT		0x01			/* Driver->RIO Abort a boot */
+#define	BOOT_SEQUENCE		0x02			/* Driver->RIO Packet with firmware details */
+#define	BOOT_COMPLETED		0x03			/* RIO->Driver Boot completed */
+#define IFOAD			0x2F			/* Driver->RIO Shutdown/Reboot RTA (Fall Over And Die) */
+#define	IDENTIFY		0x30			/* Driver->RIO Identify RTA */
+#define	ZOMBIE			0x31			/* Driver->RIO Shutdown/Flash LEDs */
+#define	UFOAD			0x32			/* Driver->RIO Shutdown/Reboot neighbouring RTA */
+#define IWAIT			0x33			/* Driver->RIO Pause booting process */
+
+/* ROUTE_RUP definitions... */
+#define	ROUTE_REQUEST		0x00			/* RIO->Driver Request an ID */
+#define	ROUTE_FOAD		0x01			/* Driver->RIO Shutdown/reboot RTA */
+#define	ROUTE_ALREADY		0x02			/* Driver->RIO Not used */
+#define	ROUTE_USED		0x03			/* Driver->RIO Not used */
+#define	ROUTE_ALLOCATE		0x04			/* Driver->RIO Allocate RTA RUP numbers */
+#define	ROUTE_REQ_TOP		0x05			/* Driver->RIO Not used */
+#define ROUTE_TOPOLOGY		0x06			/* RIO->Driver Route/Topology status */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   OPEN   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   Sent to open a port. 
+   Structure of configuration info used with OPEN, CONFIG and MOPEN packets... */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_Cor1		(PKT_Data+1)		/* Channel Option Register 1 */
+#define	PKT_Cor2		(PKT_Data+2)		/* Channel Option Register 2 */
+#define	PKT_Cor4		(PKT_Data+3)		/* Channel Option Register 4 */
+#define	PKT_Cor5		(PKT_Data+4)		/* Channel Option Register 5 */
+#define	PKT_TxXon		(PKT_Data+5)		/* Transmit XON character */
+#define	PKT_TxXoff		(PKT_Data+6)		/* Transmit XOFF character */
+#define	PKT_RxXon		(PKT_Data+7)		/* Receive XON character */
+#define	PKT_RxXoff		(PKT_Data+8)		/* Receive XOFF character */
+#define	PKT_Lnext		(PKT_Data+9)		/* Lnext character */
+#define	PKT_TxBaud		(PKT_Data+10)		/* Transmit baud rate */
+#define	PKT_RxBaud		(PKT_Data+11)		/* Receive baud rate */
+
+/* COR1 definitions... */
+#define	COR1_PARITY		0xE0			/* Parity mask */
+#define	COR1_NONE		0x00			/* No parity */
+#define	COR1_SPACE		0x20			/* Space parity */
+#define	COR1_EVEN		0x40			/* Even parity */
+#define	COR1_MARK		0xA0			/* Mark parity */
+#define	COR1_ODD		0xC0			/* Odd parity */
+
+#define	COR1_STOPBITS		0x0C			/* Stop bits mask */
+#define	COR1_STOP1		0x00			/* 1 stop bit */
+#define	COR1_STOP1_5		0x04			/* 1.5 stop bits */
+#define	COR1_STOP2		0x08			/* 2 stop bits */
+
+#define	COR1_DATABITS		0x03			/* Data bits mask */
+#define	COR1_DATA5		0x00			/* 5 data bits */
+#define	COR1_DATA6		0x01			/* 6 data bits */
+#define	COR1_DATA7		0x02			/* 7 data bits */
+#define	COR1_DATA8		0x03			/* 8 data bits */
+
+/* COR2 definitions... */
+#define	COR2_XON_TXFLOW		0x40			/* XON/XOFF Transmit Flow */
+#define	COR2_XANY_TXFLOW	0xC0			/* XON/XANY Transmit Flow */
+#define	COR2_HUPCL		0x20			/* Hang Up On Close */
+#define	COR2_DSR_TXFLOW		0x08			/* DSR Transmit Flow Control */
+#define	COR2_RTS_RXFLOW		0x04			/* RTS Receive Flow Control */
+#define	COR2_CTS_TXFLOW		0x02			/* CTS Transmit Flow Control */
+#define	COR2_XON_RXFLOW		0x01			/* XON/XOFF Receive Flow */
+
+/* COR4 definition... */
+#define	COR4_IGNCR		0x80			/* Discard received CR */
+#define	COR4_ICRNL		0x40			/* Map received CR -> NL */
+#define	COR4_INLCR		0x20			/* Map received NL -> CR */
+#define	COR4_IGNBRK		0x10			/* Ignore Received Break */
+#define	COR4_NBRKINT		0x08			/* No interrupt on rx Break */
+#define	COR4_IGNPAR		0x04			/* ignore rx parity error chars */
+#define	COR4_PARMRK		0x02			/* Mark rx parity error chars */
+#define	COR4_RAISEMOD		0x01			/* Raise modem lines on !0 baud */
+
+/* COR5 definitions... */
+#define	COR5_ISTRIP		0x80			/* Strip input chars to 7 bits */
+#define	COR5_LNE		0x40			/* Enable LNEXT processing */
+#define	COR5_CMOE		0x20			/* Match good & error characters */
+#define	COR5_TAB3		0x10			/* TAB3 mode */
+#define	COR5_TSTATE_ON		0x08			/* Enable tbusy/tstop monitoring */
+#define	COR5_TSTATE_OFF		0x04			/* Disable tbusy/tstop monitoring */
+#define	COR5_ONLCR		0x02			/* NL -> CR NL on output */
+#define	COR5_OCRNL		0x01			/* CR -> NL on output */
+
+/* RxBaud and TxBaud definitions... */
+#define	RIO_B0			0x00			/* RTS / DTR signals dropped */
+#define	RIO_B50			0x01			/* 50 baud */
+#define	RIO_B75			0x02			/* 75 baud */
+#define	RIO_B110		0x03			/* 110 baud */
+#define	RIO_B134		0x04			/* 134.5 baud */
+#define	RIO_B150		0x05			/* 150 baud */
+#define	RIO_B200		0x06			/* 200 baud */
+#define	RIO_B300		0x07			/* 300 baud */
+#define	RIO_B600		0x08			/* 600 baud */
+#define	RIO_B1200		0x09			/* 1200 baud */
+#define	RIO_B1800		0x0A			/* 1800 baud */
+#define	RIO_B2400		0x0B			/* 2400 baud */
+#define	RIO_B4800		0x0C			/* 4800 baud */
+#define	RIO_B9600		0x0D			/* 9600 baud */
+#define	RIO_B19200		0x0E			/* 19200 baud */
+#define	RIO_B38400		0x0F			/* 38400 baud */
+#define	RIO_B56000		0x10			/* 56000 baud */
+#define	RIO_B57600		0x11			/* 57600 baud */
+#define	RIO_B64000		0x12			/* 64000 baud */
+#define	RIO_B115200		0x13			/* 115200 baud */
+#define	RIO_B2000		0x14			/* 2000 baud */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   CONFIG   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   CONFIG is sent from the driver to configure an already opened port.
+   Packet structure is same as OPEN.  */
+
+/*****************************************************************************
+*********************************           **********************************
+*********************************   MOPEN   **********************************
+*********************************           **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   MOPEN is sent from the driver to open a port attached to a modem. (in-band)
+   Packet structure is same as OPEN.  */
+
+/*****************************************************************************
+*********************************           **********************************
+*********************************   CLOSE   **********************************
+*********************************           **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   CLOSE is sent from the driver to close a previously opened port.
+   No parameters.
+ */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+/*****************************************************************************
+*********************************            *********************************
+*********************************   WFLUSH   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   WFLUSH is sent pre-emptively from the driver to flush the write buffers and
+   packets of a port.  (pre-emptive)
+   
+   WFLUSH is also sent in-band from the driver to a port as a marker to end
+   write flushing previously started by a pre-emptive WFLUSH packet. (in-band)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   RFLUSH   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   RFLUSH is sent pre-emptively from the driver to flush the read buffers and
+   packets of a port.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   RESUME   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   RESUME is sent pre-emptively from the driver to cause a port to resume 
+   transmission of data if blocked by XOFF.  (as if XON had been received)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   SBREAK   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   SBREAK is sent in-band from the driver to a port to suspend data and start
+   break signal transmission.
+
+   If the break delay is 0, the break signal will be acknowledged with a
+   RUP_COMMAND, COMPLETE packet and continue until an EBREAK packet is received.
+
+   Otherwise, there is no acknowledgement and the break signal will last for the
+   specified number of mS.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_BreakDelay		(PKT_Data+1)		/* Break delay in mS */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   EBREAK   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   EBREAK is sent in-band from the driver to a port to stop transmission of a
+   break signal.
+
+   No parameters.  */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   SUSPEND   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   SUSPEND is sent pre-emptively from the driver to cause a port to suspend
+   transmission of data.  (as if XOFF had been received)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   FCLOSE   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   FCLOSE is sent pre-emptively from the driver to force close a port.
+   A force close flushes receive and transmit queues, and also lowers all output
+   modem signals if the COR5_HUPCL (Hang Up On Close) flag is set.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   XPRINT   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   XPRINT is sent as a normal I/O data packet except that the PKT_CMD_BIT of
+   the "len" field is set, and the first "data" byte is XPRINT.
+
+   The I/O data in the XPRINT packet will contain the following:
+   -	Transparent Print Start Sequence
+   -	Transparent Print Data
+   -	Transparent Print Stop Sequence.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MBIS   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MBIS is sent pre-emptively from the driver to set a port's modem signals.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+#define	PKT_ModemSet		(PKT_Data+4)		/* Modem set signals mask */
+
+/* ModemSet definitions... */
+#define	MBIS_RTS		0x01			/* RTS modem signal */
+#define	MBIS_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MBIC   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MBIC is sent pre-emptively from the driver to clear a port's modem signals.
+   */
+#if 0   
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+#define	PKT_ModemClear		(PKT_Data+4)		/* Modem clear signals mask */
+
+/* ModemClear definitions... */
+#define	MBIC_RTS		0x01			/* RTS modem signal */
+#define	MBIC_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MSET   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MSET is sent pre-emptively from the driver to set/clear a port's modem signals. */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#endif
+
+#define	PKT_ModemSet		(PKT_Data+4)		/* Modem set signals mask */
+
+/* ModemSet definitions... */
+#define	MSET_RTS		0x01			/* RTS modem signal */
+#define	MSET_DTR		0x02			/* DTR modem signal */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   PCLOSE   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+/* (Driver->RIO,in-band)
+
+   PCLOSE is sent from the driver to pseudo close a previously opened port.
+   
+   The port will close when all data has been sent/received, however, the
+   port's transmit / receive and modem signals will be left enabled and the
+   port marked internally as Pseudo Closed. */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   MGET   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MGET is sent pre-emptively from the driver to request the port's current modem signals. */
+
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   MEMDUMP   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   MEMDUMP is sent pre-emptively from the driver to request a dump of 32 bytes
+   of the specified port's RTA address space.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+
+/*****************************************************************************
+******************************                   *****************************
+******************************   READ_REGISTER   *****************************
+******************************                   *****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   READ_REGISTER is sent pre-emptively from the driver to request the contents
+   of the CD1400 register specified in address.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+
+/*****************************************************************************
+************************                            **************************
+************************   COMMAND_RUP - COMPLETE   **************************
+************************                            **************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE is sent in response to all port I/O control command
+   packets, except MEMDUMP and READ_REGISTER.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+
+/* ModemStatus definitions... */
+#define	MODEM_DSR		0x80			/* Data Set Ready modem state */
+#define	MODEM_CTS		0x40			/* Clear To Send modem state */
+#define	MODEM_RI		0x20			/* Ring Indicate modem state */
+#define	MODEM_CD		0x10			/* Carrier Detect modem state */
+#define	MODEM_TSTOP		0x08			/* Transmit Stopped state */
+#define	MODEM_TEMPTY		0x04			/* Transmit Empty state */
+#define	MODEM_DTR		0x02			/* DTR modem output state */
+#define	MODEM_RTS		0x01			/* RTS modem output state */
+
+/* PortStatus definitions... */
+#define	PORT_ISOPEN		0x01			/* Port open ? */
+#define	PORT_HUPCL		0x02			/* Hangup on close? */
+#define	PORT_MOPENPEND		0x04			/* Modem open pending */
+#define	PORT_ISPARALLEL		0x08			/* Parallel port */
+#define	PORT_BREAK		0x10			/* Port on break */
+#define	PORT_STATUSPEND		0020			/* Status packet pending */
+#define	PORT_BREAKPEND		0x40			/* Break packet pending */
+#define	PORT_MODEMPEND		0x80			/* Modem status packet pending */
+
+/*****************************************************************************
+************************                            **************************
+************************   COMMAND_RUP - COMPLETE   **************************
+************************                            **************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE is sent in response to all port I/O control command
+   packets, except MEMDUMP and READ_REGISTER.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#if 0
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#endif
+
+/* ModemStatus definitions... */
+#define	MODEM_DSR		0x80			/* Data Set Ready modem state */
+#define	MODEM_CTS		0x40			/* Clear To Send modem state */
+#define	MODEM_RI		0x20			/* Ring Indicate modem state */
+#define	MODEM_CD		0x10			/* Carrier Detect modem state */
+#define	MODEM_TSTOP		0x08			/* Transmit Stopped state */
+#define	MODEM_TEMPTY		0x04			/* Transmit Empty state */
+#define	MODEM_DTR		0x02			/* DTR modem output state */
+#define	MODEM_RTS		0x01			/* RTS modem output state */
+
+/* PortStatus definitions... */
+#define	PORT_ISOPEN		0x01			/* Port open ? */
+#define	PORT_HUPCL		0x02			/* Hangup on close? */
+#define	PORT_MOPENPEND		0x04			/* Modem open pending */
+#define	PORT_ISPARALLEL		0x08			/* Parallel port */
+#define	PORT_BREAK		0x10			/* Port on break */
+#define	PORT_STATUSPEND		0020			/* Status packet pending */
+#define	PORT_BREAKPEND		0x40			/* Break packet pending */
+#define	PORT_MODEMPEND		0x80			/* Modem status packet pending */
+
+/*****************************************************************************
+********************                                      ********************
+********************   COMMAND_RUP - COMPLETE - MEMDUMP   ********************
+********************                                      ********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE - MEMDUMP is sent as an acknowledgement for a MEMDUMP
+   port I/O control command packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#define	PKT_Address		(PKT_Data+6)		/* Requested address */
+#endif
+#define	PKT_Dump		(PKT_Data+8)		/* 32bytes of requested dump data */
+
+/*****************************************************************************
+*****************                                            *****************
+*****************   COMMAND_RUP - COMPLETE - READ_REGISTER   *****************
+*****************                                            *****************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - COMPLETE - READ_REGISTER is sent as an acknowledgement for a
+   READ_REGISTER port I/O control command packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/*Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/*Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+#define	PKT_RegisterValue	(PKT_Data+3)		/* Modem signal status */
+#if 0
+#define	PKT_PortStatus		(PKT_Data+4)		/* Port signal status */
+#define	PKT_SubCmd		(PKT_Data+5)		/* Sub Command */
+#endif
+
+/*****************************************************************************
+*********************                                  ***********************
+*********************   COMMAND_RUP - BREAK_RECEIVED   ***********************
+*********************                                  ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - BREAK_RECEIVED packets are sent when the port detects a receive BREAK signal.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#endif
+
+/*****************************************************************************
+*********************                                *************************
+*********************   COMMAND_RUP - MODEM_STATUS   *************************
+*********************                                *************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   COMMAND_RUP - MODEM_STATUS packets are sent whenever the port detects a
+   change in the input modem signal states.
+
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_PhbNum		(PKT_Data+1)		/* Port number wrt RTA */
+#define	PKT_Cmd2		(PKT_Data+2)		/* Command code copy */
+#define	PKT_ModemStatus		(PKT_Data+3)		/* Modem signal status */
+#endif
+
+/*****************************************************************************
+************************                             *************************
+************************   BOOT_RUP - BOOT_REQUEST   *************************
+************************                             *************************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP - BOOT_REQUEST packets are sent to the Driver from RIO to request
+   firmware code to load onto attached RTAs.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+
+/*****************************************************************************
+************************                              ************************
+************************   BOOT_RUP - BOOT_SEQUENCE   ************************
+************************                              ************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - BOOT_SEQUENCE packets are sent from the Driver to RIO in response
+   to a BOOT_RUP - BOOT_REQUEST packet.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_NumPackets		(PKT_Data+2)		/* Packets required to load firmware */
+#define	PKT_LoadBase		(PKT_Data+4)		/* RTA firmware load address */
+#define	PKT_CodeSize		(PKT_Data+6)		/* Size of firmware in bytes */
+#define	PKT_CmdString		(PKT_Data+8)		/* Command string */
+
+/*****************************************************************************
+************************                               ***********************
+************************   BOOT_RUP - BOOT_COMPLETED   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP - BOOT_COMPLETE is sent to the Driver from RIO when downloading of
+   RTA firmware has completed.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number RTA booted on */
+#define	PKT_SerialNumber	(PKT_Data+2)		/* 4 byte serial number */
+
+/*****************************************************************************
+************************                               ***********************
+************************   BOOT_RUP - Packet Request   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   BOOT_RUP packet without the PKT_CMD_BIT set in the PKT->len field is sent
+   from RIO to the Driver as a request for a firmware boot packet. */
+
+#define	PKT_SequenceNumber	(PKT_Data+0)		/* Packet sequence number */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   BOOT_RUP - Packet Response   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   In response to a BOOT_RUP boot packet request, the driver fills out the response
+   packet with the 70 bytes of the requested sequence.
+   */
+#if 0
+#define	PKT_SequenceNumber	(PKT_Data+0)		/* Packet sequence number */
+#endif
+#define	PKT_FirmwarePacket	(PKT_Data+2)		/* Firmware packet */
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - IFOAD   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IFOAD packets are sent from the Driver to an RTA to cause the
+   RTA to shut down and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IfoadId1		(PKT_Data+2)		/* IFOAD Id 1 */
+#define	PKT_IfoadId2		(PKT_Data+3)		/* IFOAD Id 2 */
+
+#define	IFOADID1		0xAD
+#define	IFOADID2		0xF0
+
+/*****************************************************************************
+**************************                         ***************************
+**************************   BOOT_RUP - IDENTIFY   ***************************
+**************************                         ***************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IDENTIFY packets are sent from the Driver to an RTA to cause the
+   RTA to flash its LEDs for a period of time.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IdentifyId		(PKT_Data+2)		/* defines pattern to flash */
+
+/*****************************************************************************
+****************************                       ***************************
+****************************   BOOT_RUP - ZOMBIE   ***************************
+****************************                       ***************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - ZOMBIE packets are sent from the Driver to an RTA to cause the
+   RTA to shut down and flash it's LEDs.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_ZombieId1		(PKT_Data+2)		/* ZOMBIE Id 1 */
+#define	PKT_ZombieId2		(PKT_Data+3)		/* ZOMBIE Id 2 */
+
+#define	ZOMBIEID1		0x52
+#define	ZOMBIEID2		0x21
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - UFOAD   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - UFOAD packets are sent from the Driver to an RTA to cause the RTA
+   to ask it's neighbouring RTA to shut down and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number of RTA to UFOAD */
+#endif
+#define	PKT_UfoadId1		(PKT_Data+2)		/* UFOAD Id 1 */
+#define	PKT_UfoadId2		(PKT_Data+3)		/* UFOAD Id 2 */
+
+#define	UFOADID1		0x1E
+#define	UFOADID2		0x0D
+
+/*****************************************************************************
+****************************                      ****************************
+****************************   BOOT_RUP - IWAIT   ****************************
+****************************                      ****************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   BOOT_RUP - IWAIT packets are sent from the Driver to an RTA to cause the RTA
+   to pause booting on the specified link for 30 seconds.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#define	PKT_LinkNumber		(PKT_Data+1)		/* Link number of RTA to UFOAD */
+#endif
+#define	PKT_IwaitId1		(PKT_Data+2)		/* IWAIT Id 1 */
+#define	PKT_IwaitId2		(PKT_Data+3)		/* IWAIT Id 2 */
+
+#define	IWAITID1		0xDE
+#define	IWAITID2		0xB1
+
+/*****************************************************************************
+************************                               ***********************
+************************   ROUTE_RUP - ROUTE_REQUEST   ***********************
+************************                               ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   ROUTE_RUP - ROUTE_REQUEST packets are sent from a newly booted or connected
+   RTA to a Driver to request an ID (RUP or unit number).
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_SerialNumber	(PKT_Data+2)		/* 4 byte serial number */
+#define	PKT_ModuleTypes		(PKT_Data+6)		/* RTA Module types */
+
+/* ModuleTypes definitions... */
+#define	MOD_BLANK		0x0F			/* Blank plate attached */
+#define	MOD_RS232DB25		0x00			/* RS232 DB25 connector */
+#define	MOD_RS232RJ45		0x01			/* RS232 RJ45 connector */
+#define	MOD_RS422DB25		0x02			/* RS422 DB25 connector */
+#define	MOD_RS485DB25		0x03			/* RS485 DB25 connector */
+#define	MOD_PARALLEL		0x04			/* Centronics parallel */
+
+#define	MOD2			0x08			/* Set to indicate Rev2 module */
+
+/*****************************************************************************
+*************************                            *************************
+*************************   ROUTE_RUP - ROUTE_FOAD   *************************
+*************************                            *************************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   ROUTE_RUP - ROUTE_FOAD packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST
+   packet to cause the RTA to "Fall Over And Die"., i.e. shutdown and reboot.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_RouteCmdString	(PKT_Data+2)		/* Command string */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   ROUTE_RUP - ROUTE_ALLOCATE   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (Driver->RIO,pre-emptive)
+
+   ROUTE_RUP - ROUTE_ALLOCATE packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST
+   packet to allocate the RTA's Id number (RUP number 1..16)
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_IdNum		(PKT_Data+1)		/* RUP number for ports 1..8 */
+#if 0
+#define	PKT_RouteCmdString	(PKT_Data+2)		/* Command string */
+#endif
+#define	PKT_IdNum2		(PKT_Data+0x17)		/* RUP number for ports 9..16 */
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   ROUTE_RUP - ROUTE_TOPOLOGY   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* (RIO->Driver,pre-emptive)
+
+   ROUTE_RUP - ROUTE_TOPOLOGY packet is sent to inform the driver of an RTA's
+   current link status.
+   */
+#if 0
+#define	PKT_Cmd			(PKT_Data+0)		/* Command code */
+#endif
+#define	PKT_Link1Rup		(PKT_Data+2)		/* Link 1 RUP number */
+#define	PKT_Link1Link		(PKT_Data+3)		/* Link 1 link number */
+#define	PKT_Link2Rup		(PKT_Data+4)		/* Link 2 RUP number */
+#define	PKT_Link2Link		(PKT_Data+5)		/* Link 2 link number */
+#define	PKT_Link3Rup		(PKT_Data+6)		/* Link 3 RUP number */
+#define	PKT_Link3Link		(PKT_Data+7)		/* Link 3 link number */
+#define	PKT_Link4Rup		(PKT_Data+8)		/* Link 4 RUP number */
+#define	PKT_Link4Link		(PKT_Data+9)		/* Link 4 link number */
+#define	PKT_RtaVpdProm		(PKT_Data+10)		/* 32 bytes of RTA VPD PROM Contents */
+
+#endif						/* _sxwinif_h */
+
+/* End of RIOWINIF.H */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/riscos.h linux/drivers/char/rio/riscos.h
--- v2.3.99-pre6/linux/drivers/char/rio/riscos.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/riscos.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,63 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riscos.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riscos.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riscos_h__
+#define __rio_riscos_h__
+
+#ifdef SCCS_LABELS
+static char *_riscos_h_sccs_ = "@(#)riscos.h	1.2";
+#endif
+
+/*
+** This module used to define all those little itsy bits required for RISC/OS
+** now it's full of null macros.
+*/
+
+/*
+**	RBYTE reads a byte from a location.
+**	RWORD reads a word from a location.
+**	WBYTE writes a byte to a location.
+**	WWORD writes a word to a location.
+**	RINDW reads a word through a pointer.
+**	WINDW writes a word through a pointer.
+**	RIOSWAB swaps the two bytes of a word, if needed.
+*/
+
+#define	RIOSWAB(N)      (N)
+#define	WBYTE(A,V)	(A)=(uchar)(V)
+#define WWORD(A,V)	(A)=(ushort)(V)
+#define RBYTE(A)	(uchar)(A)
+#define RWORD(A)	(ushort)(A)
+#define RINDW(A)	(*(ushort *)(A))
+#define WINDW(A,V)	(*(ushort *)(A)=(ushort)(V))
+
+#endif /* __rio_riscos_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rom.h linux/drivers/char/rio/rom.h
--- v2.3.99-pre6/linux/drivers/char/rio/rom.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rom.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,64 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      R O M
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rom_h
+#define _rom_h 1
+
+#ifndef lint
+#ifdef SCCS
+static char *_rio_rom_h_sccs = "@(#)rom.h	1.1" ;
+#endif
+#endif
+
+typedef struct  ROM  ROM ;
+struct  ROM  {
+                 u_short    slx ;
+                 char       pcb_letter_rev ;
+                 char       pcb_number_rev ;
+                 char       serial[4] ;
+                 char       year ;
+                 char       week ;
+             } ;
+
+#endif
+
+#define HOST_ROM    (ROM *) 0x7c00
+#define RTA_ROM	    (ROM *) 0x7801
+#define ROM_LENGTH  0x20
+
+/*********** end of file ***********/
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/route.h linux/drivers/char/rio/route.h
--- v2.3.99-pre6/linux/drivers/char/rio/route.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/route.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,108 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 R O U T E     H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _route_h
+#define _route_h
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_route_h_sccs = "@(#)route.h	1.3"; */
+#endif
+#endif
+
+#define MAX_LINKS 4
+#define MAX_NODES 17                          /* Maximum nodes in a subnet */
+#define NODE_BYTES ((MAX_NODES / 8) + 1)      /* Number of bytes needed for
+                                                 1 bit per node */
+#define ROUTE_DATA_SIZE  (NODE_BYTES + 2)     /* Number of bytes for complete 
+                                                 info about cost etc. */
+#define ROUTES_PER_PACKET ((PKT_MAX_DATA_LEN -2)/ ROUTE_DATA_SIZE)
+                                              /* Number of nodes we can squeeze
+                                                 into one packet */
+#define MAX_TOPOLOGY_PACKETS (MAX_NODES / ROUTES_PER_PACKET + 1)
+/************************************************
+ * Define the types of command for the ROUTE RUP.
+ ************************************************/
+#define ROUTE_REQUEST    0                    /* Request an ID */
+#define ROUTE_FOAD       1                    /* Kill the RTA */
+#define ROUTE_ALREADY    2                    /* ID given already */
+#define ROUTE_USED       3                    /* All ID's used */
+#define ROUTE_ALLOCATE   4                    /* Here it is */
+#define ROUTE_REQ_TOP    5                    /* I bet you didn't expect....
+                                                 the Topological Inquisition */
+#define ROUTE_TOPOLOGY   6                    /* Topology request answered FD */
+/*******************************************************************
+ * Define the Route Map Structure
+ *
+ * The route map gives a pointer to a Link Structure to use.
+ * This allows Disconnected Links to be checked quickly
+ ******************************************************************/
+typedef struct COST_ROUTE COST_ROUTE;
+struct COST_ROUTE {
+                      unsigned char cost;        /* Cost down this link */
+                      unsigned char route[NODE_BYTES]; /* Nodes thorough this route */
+                  } ;
+
+typedef struct ROUTE_STR ROUTE_STR ;
+struct  ROUTE_STR {
+                      COST_ROUTE cost_route[MAX_LINKS];
+                                                /* cost / route for this link */
+                      ushort favoured;          /* favoured link */
+                  } ;
+
+
+#define NO_LINK            (short) 5      /* Link unattached */
+#define ROUTE_NO_ID        (short) 100    /* No Id */
+#define ROUTE_DISCONNECT   (ushort) 0xff  /* Not connected */
+#define ROUTE_INTERCONNECT (ushort) 0x40  /* Sub-net interconnect */
+
+
+#define SYNC_RUP         (ushort) 255
+#define COMMAND_RUP      (ushort) 254
+#define ERROR_RUP        (ushort) 253
+#define POLL_RUP         (ushort) 252
+#define BOOT_RUP         (ushort) 251
+#define ROUTE_RUP        (ushort) 250
+#define STATUS_RUP       (ushort) 249
+#define POWER_RUP        (ushort) 248
+
+#define HIGHEST_RUP      (ushort) 255   /* Set to Top one */
+#define LOWEST_RUP       (ushort) 248   /* Set to bottom one */
+
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rtahw.h linux/drivers/char/rio/rtahw.h
--- v2.3.99-pre6/linux/drivers/char/rio/rtahw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rtahw.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,75 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                R T A    H A R D W A R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_rtahw_h_sccs = "@(#)rtahw.h	1.5" ;
+#endif
+#endif
+
+#define	WATCHDOG_ADDR	((unsigned short *)0x7a00)
+#define RTA_LED_ADDR	((unsigned short *)0x7c00)
+#define SERIALNUM_ADDR	((unsigned char *)0x7809)
+#define LATCH_ADDR      ((unsigned char *)0x7800)
+
+/*
+** Here we define where the cd1400 chips are in memory.
+*/
+#define CD1400_ONE_ADDR		(0x7300)
+#define CD1400_TWO_ADDR		(0x7200)
+#define CD1400_THREE_ADDR	(0x7100)
+#define CD1400_FOUR_ADDR	(0x7000)
+
+/*
+** Define the different types of modules we can have
+*/
+enum module {
+    MOD_BLANK		= 0x0f,		/* Blank plate attached */
+    MOD_RS232DB25	= 0x00,		/* RS232 DB25 connector */
+    MOD_RS232RJ45	= 0x01,		/* RS232 RJ45 connector */
+    MOD_RS422DB25	= 0x02,		/* RS422 DB25 connector */
+    MOD_RS485DB25	= 0x03,		/* RS485 DB25 connector */
+    MOD_PARALLEL	= 0x04		/* Centronics parallel */
+};
+
+#define TYPE_HOST	0
+#define TYPE_RTA8	1
+#define TYPE_RTA16	2
+
+#define	WATCH_DOG	WATCHDOG_ADDR
+
+/*********** end of file ***********/
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rup.h linux/drivers/char/rio/rup.h
--- v2.3.99-pre6/linux/drivers/char/rio/rup.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rup.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,82 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               R U P   S T R U C T U R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rup_h
+#define _rup_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_rup_h_sccs = "@(#)rup.h	1.5"; */
+#endif
+#endif
+
+#if defined( HOST ) || defined( INKERNEL )
+#define MAX_RUP          ((short) 16) 
+#endif
+#ifdef RTA
+#define MAX_RUP          ((short) 1)
+#endif
+
+#define PKTS_PER_RUP     ((short) 2)     /* They are always used in pairs */
+
+/*************************************************
+ * Define all the  packet request stuff
+ ************************************************/
+#define TX_RUP_INACTIVE          0        /* Nothing to transmit */
+#define TX_PACKET_READY          1        /* Transmit packet ready */
+#define TX_LOCK_RUP              2        /* Transmit side locked */
+
+#define RX_RUP_INACTIVE          0        /* Nothing received */
+#define RX_PACKET_READY          1        /* Packet received */
+
+#define RUP_NO_OWNER             0xff     /* RUP not owned by any process */
+
+struct RUP {
+             PKT_ptr    txpkt;            /* Outgoing packet */
+             PKT_ptr    rxpkt;            /* Incoming packet */
+             WORD       link;             /* Which link to send down? */
+             BYTE       rup_dest_unit[2]; /* Destination unit */
+             WORD       handshake;        /* For handshaking */
+             WORD       timeout;          /* Timeout */
+             WORD       status;           /* Status */
+             WORD       txcontrol;        /* Transmit control */
+             WORD       rxcontrol;        /* Receive control */
+           };
+ 
+#endif
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/rupstat.h linux/drivers/char/rio/rupstat.h
--- v2.3.99-pre6/linux/drivers/char/rio/rupstat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/rupstat.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,51 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      RUPSTAT
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rupstat_h
+#define _rupstat_h
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_rupstat_h_sccs = "@(#)rupstat.h	1.1" ;
+#endif
+#endif
+
+#define    STATUS_SYNC    0
+#define    STATUS_REQ_TOP 1
+#define    STATUS_TOPOLOGY    2
+
+#endif
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/sam.h linux/drivers/char/rio/sam.h
--- v2.3.99-pre6/linux/drivers/char/rio/sam.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/sam.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,74 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                    S A M . H
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+#ifndef _sam_h
+#define _sam_h 1
+
+#ifdef SCCS_LABELS
+#ifndef lint
+/* static char *_rio_sam_h_sccs = "@(#)sam.h	1.3"; */
+#endif
+#endif
+
+
+#if !defined( HOST ) && !defined( INKERNEL )
+#define RTA 1
+#endif
+
+#define NUM_FREE_LIST_UNITS     500
+
+#ifndef FALSE
+#define FALSE (short)  0x00
+#endif
+#ifndef TRUE
+#define TRUE  (short)  !FALSE
+#endif
+
+#define TX    TRUE
+#define RX    FALSE
+
+
+typedef struct FREE_LIST FREE_LIST ;
+struct FREE_LIST   {
+                       FREE_LIST_ptr next ;
+                       FREE_LIST_ptr prev ;
+                   } ;
+
+
+#endif
+/*********** end of file ***********/
+
+
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/selftest.h linux/drivers/char/rio/selftest.h
--- v2.3.99-pre6/linux/drivers/char/rio/selftest.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/selftest.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,73 @@
+/*
+** File:		selftest.h
+**
+** Author:		David Dix
+**
+** Created:		15th March 1993
+**
+** Last modified:	94/06/14
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef	_selftests_h_
+#define _selftests_h_
+
+/*
+** Selftest identifier...
+*/
+#define SELFTEST_MAGIC	0x5a5a
+
+/*
+** This is the structure of the packet that is sent back after each
+** selftest on a booting RTA.
+*/
+typedef struct {
+    short		magic;			/* Identifies packet type */
+    int			test;			/* Test number, see below */
+    unsigned int	result;			/* Result value */
+    unsigned int	dataIn;
+    unsigned int	dataOut;
+}selftestStruct;
+
+/*
+** The different tests are identified by the following data values.
+*/
+enum test {
+    TESTS_COMPLETE	= 0x00,
+    MEMTEST_ADDR	= 0x01,
+    MEMTEST_BIT		= 0x02,
+    MEMTEST_FILL	= 0x03,
+    MEMTEST_DATABUS	= 0x04,
+    MEMTEST_ADDRBUS	= 0x05,
+    CD1400_INIT		= 0x10,
+    CD1400_LOOP		= 0x11,
+    CD1400_INTERRUPT    = 0x12
+};
+
+enum result {
+    E_PORT		= 0x10,
+    E_TX		= 0x11,
+    E_RX		= 0x12,
+    E_EXCEPT		= 0x13,
+    E_COMPARE		= 0x14,
+    E_MODEM		= 0x15,
+    E_TIMEOUT		= 0x16,
+    E_INTERRUPT         = 0x17
+};
+#endif	/* _selftests_h_ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/space.h linux/drivers/char/rio/space.h
--- v2.3.99-pre6/linux/drivers/char/rio/space.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/space.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,45 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: space.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)space.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_space_h__
+#define __rio_space_h__
+
+#ifdef SCCS_LABELS
+static char *_space_h_sccs_ = "@(#)space.h	1.2";
+#endif
+
+extern int rio_cntls;
+extern int rio_bases[];
+extern int rio_limits[];
+extern int rio_vects[];
+
+#endif /* __rio_space_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/sysmap.h linux/drivers/char/rio/sysmap.h
--- v2.3.99-pre6/linux/drivers/char/rio/sysmap.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/sysmap.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,63 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******          S Y S T E M   M A P   H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_sysmap_h_sccs = "@(#)sysmap.h	1.1" ;
+#endif
+#endif
+
+#define SYSTEM_MAP_LEN     64           /* Len of System Map array */
+
+
+typedef struct SYS_MAP        SYS_MAP ;
+typedef struct SYS_MAP_LINK   SYS_MAP_LINK ;
+
+struct SYS_MAP_LINK {
+                        short id ;          /* Unit Id */
+                        short link ;        /* Id's Link */
+                        short been_here ;   /* Used by map_gen */
+                    } ;
+
+struct SYS_MAP {
+                   char         serial_num[4] ;
+                   SYS_MAP_LINK link[4] ;
+               } ;
+
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/timeouts.h linux/drivers/char/rio/timeouts.h
--- v2.3.99-pre6/linux/drivers/char/rio/timeouts.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/timeouts.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,51 @@
+
+/****************************************************************************
+ *******                                                              *******
+ *******                     T I M E O U T S
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef lint
+#ifdef SCCS_LABELS
+static char *_rio_defaults_h_sccs = "@(#)timeouts.h	1.3" ;
+#endif
+#endif
+
+#define MILLISECOND           (int) (1000/64)   /* 15.625 low ticks */
+#define SECOND                (int) 15625       /* Low priority ticks */
+
+#define TX_TIMEOUT          (int) (200 * MILLISECOND)
+
+
+/*********** end of file ***********/
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/top.h linux/drivers/char/rio/top.h
--- v2.3.99-pre6/linux/drivers/char/rio/top.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/top.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,49 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: top.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:19
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)top.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_top_h__
+#define __rio_top_h__
+
+#ifdef SCCS_LABELS
+static char *_top_h_sccs_ = "@(#)top.h	1.2";
+#endif
+
+/*
+** Topology information
+*/
+struct Top
+{
+    uchar Unit;
+    uchar Link;
+};
+
+#endif /* __rio_top_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/typdef.h linux/drivers/char/rio/typdef.h
--- v2.3.99-pre6/linux/drivers/char/rio/typdef.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/typdef.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,82 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: typdef.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:20
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)typdef.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_typdef_h__
+#define __rio_typdef_h__
+
+#ifdef SCCS_LABELS
+static char *_typdef_h_sccs_ = "@(#)typdef.h	1.2";
+#endif
+
+#undef VPIX
+
+/*
+** IT IS REALLY, REALLY, IMPORTANT THAT BYTES ARE UNSIGNED!
+**
+** These types are ONLY to be used for refering to data structures
+** on the RIO Host card!
+*/
+typedef	volatile unsigned char	BYTE;
+typedef volatile unsigned short	WORD;
+typedef volatile unsigned int	DWORD;
+typedef	volatile unsigned short RIOP;
+typedef	volatile short          NUMBER;
+
+
+/*
+** 27.01.199 ARG - mods to compile 'newutils' on LyxnOS -
+** These #defines are for the benefit of the 'libfuncs' library
+** only. They are not necessarily correct type mappings and
+** are here only to make the source compile.
+*/
+/* typedef unsigned int	uint; */
+typedef unsigned long	ulong_t;
+typedef unsigned short	ushort_t;
+typedef unsigned char	uchar_t;
+typedef unsigned char	queue_t;
+typedef unsigned char	mblk_t;
+typedef	unsigned int 	paddr_t;
+typedef unsigned char   uchar;
+
+#define	TPNULL	((ushort)(0x8000))
+
+
+/*
+** RIO structures defined in other include files.
+*/
+typedef struct PKT	 	PKT;
+typedef struct LPB	 	LPB;
+typedef struct RUP	 	RUP;
+typedef struct Port		Port;
+typedef struct DpRam		DpRam;
+
+#endif /* __rio_typdef_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rio/unixrup.h linux/drivers/char/rio/unixrup.h
--- v2.3.99-pre6/linux/drivers/char/rio/unixrup.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/rio/unixrup.h	Wed May 10 16:56:44 2000
@@ -0,0 +1,56 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: unixrup.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:20
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)unixrup.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_unixrup_h__
+#define __rio_unixrup_h__
+
+#ifdef SCCS_LABELS
+static char *_unixrup_h_sccs_ = "@(#)unixrup.h	1.2";
+#endif
+
+/*
+**    UnixRup data structure. This contains pointers to actual RUPs on the
+**    host card, and all the command/boot control stuff.
+*/
+struct    UnixRup
+{
+    struct CmdBlk    *CmdsWaitingP;	/* Commands waiting to be done */
+    struct CmdBlk    *CmdPendingP;	/* The command currently being sent */
+    struct RUP       *RupP;		/* the Rup to send it to */
+    uint             Id;		/* Id number */
+    uint             BaseSysPort;	/* SysPort of first tty on this RTA */
+    uint             ModTypes;		/* Modules on this RTA */
+    spinlock_t       RupLock;		/* Lock structure for MPX */
+/*    struct lockb     RupLock;	*/	/* Lock structure for MPX */
+};
+
+#endif /* __rio_unixrup_h__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.3.99-pre6/linux/drivers/char/rtc.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/rtc.c	Tue May  2 12:44:05 2000
@@ -38,9 +38,10 @@
  *	1.10    Paul Barton-Davis: add support for async I/O
  *	1.10a	Andrea Arcangeli: Alpha updates
  *	1.10b	Andrew Morton: SMP lock fix
+ *	1.10c	Cesar Barros: SMP locking fixes and cleanup
  */
 
-#define RTC_VERSION		"1.10b"
+#define RTC_VERSION		"1.10c"
 
 #define RTC_IRQ 	8	/* Can't see this changing soon.	*/
 #define RTC_IO_EXTENT	0x10	/* Only really two ports, but...	*/
@@ -124,7 +125,14 @@
 #define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
 #define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
 
-static atomic_t rtc_status = ATOMIC_INIT(0); /* bitmapped status byte.	*/
+/*
+ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
+ * protected by the big kernel lock. However, ioctl can still disable the timer
+ * in rtc_status and then with del_timer after the interrupt has read
+ * rtc_status but before mod_timer is called, which would then reenable the
+ * timer (but you would need to have an awful timing before you'd trip on it)
+ */
+static unsigned long rtc_status = 0;	/* bitmapped status byte.	*/
 static unsigned long rtc_freq = 0;	/* Current periodic IRQ rate	*/
 static unsigned long rtc_irq_data = 0;	/* our output to the world	*/
 
@@ -162,15 +170,17 @@
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+
+	if (rtc_status & RTC_TIMER_ON)
+		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
+
 	spin_unlock (&rtc_lock);
 
+	/* Now do the rest of the actions */
 	wake_up_interruptible(&rtc_wait);	
 
 	if (rtc_async_queue)
 		kill_fasync (rtc_async_queue, SIGIO, POLL_IN);
-
-	if (atomic_read(&rtc_status) & RTC_TIMER_ON)
-		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
 }
 #endif
 
@@ -200,7 +210,18 @@
 
 	current->state = TASK_INTERRUPTIBLE;
 		
-	while ((data = xchg(&rtc_irq_data, 0)) == 0) {
+	do {
+		/* First make it right. Then make it fast. Putting this whole
+		 * block within the parentheses of a while would be too
+		 * confusing. And no, xchg() is not the answer. */
+		spin_lock_irq (&rtc_lock);
+		data = rtc_irq_data;
+		rtc_irq_data = 0;
+		spin_unlock_irq (&rtc_lock);
+
+		if (data != 0)
+			break;
+
 		if (file->f_flags & O_NONBLOCK) {
 			retval = -EAGAIN;
 			goto out;
@@ -210,7 +231,7 @@
 			goto out;
 		}
 		schedule();
-	}
+	} while (1);
 
 	retval = put_user(data, (unsigned long *)buf); 
 	if (!retval)
@@ -226,8 +247,6 @@
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 		     unsigned long arg)
 {
-
-	unsigned long flags;
 	struct rtc_time wtime; 
 
 	switch (cmd) {
@@ -245,10 +264,11 @@
 	case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/
 	{
 		mask_rtc_irq_bit(RTC_PIE);
-		if (atomic_read(&rtc_status) & RTC_TIMER_ON) {
+		if (rtc_status & RTC_TIMER_ON) {
+			spin_lock_irq (&rtc_lock);
+			rtc_status &= ~RTC_TIMER_ON;
 			del_timer(&rtc_irq_timer);
-			atomic_set(&rtc_status,
-				   atomic_read(&rtc_status) & ~RTC_TIMER_ON);
+			spin_unlock_irq (&rtc_lock);
 		}
 		return 0;
 	}
@@ -262,11 +282,12 @@
 		if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE)))
 			return -EACCES;
 
-		if (!(atomic_read(&rtc_status) & RTC_TIMER_ON)) {
-			atomic_set(&rtc_status,
-				   atomic_read(&rtc_status) | RTC_TIMER_ON);
+		if (!(rtc_status & RTC_TIMER_ON)) {
+			spin_lock_irq (&rtc_lock);
 			rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
 			add_timer(&rtc_irq_timer);
+			rtc_status |= RTC_TIMER_ON;
+			spin_unlock_irq (&rtc_lock);
 		}
 		set_rtc_irq_bit(RTC_PIE);
 		return 0;
@@ -320,7 +341,7 @@
 		if (sec >= 60)
 			sec = 0xff;
 
-		spin_lock_irqsave(&rtc_lock, flags);
+		spin_lock_irq(&rtc_lock);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
@@ -331,7 +352,7 @@
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
 		CMOS_WRITE(sec, RTC_SECONDS_ALARM);
-		spin_unlock_irqrestore(&rtc_lock, flags);
+		spin_unlock_irq(&rtc_lock);
 
 		return 0;
 	}
@@ -346,8 +367,7 @@
 		unsigned char mon, day, hrs, min, sec, leap_yr;
 		unsigned char save_control, save_freq_select;
 		unsigned int yrs;
-		unsigned long flags;
-			
+
 		if (!capable(CAP_SYS_TIME))
 			return -EACCES;
 
@@ -379,11 +399,11 @@
 		if ((yrs -= epoch) > 255)    /* They are unsigned */
 			return -EINVAL;
 
-		spin_lock_irqsave(&rtc_lock, flags);
+		spin_lock_irq(&rtc_lock);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
 		    || RTC_ALWAYS_BCD) {
 			if (yrs > 169) {
-				spin_unlock_irqrestore(&rtc_lock, flags);
+				spin_unlock_irq(&rtc_lock);
 				return -EINVAL;
 			}
 			if (yrs >= 100)
@@ -412,7 +432,7 @@
 		CMOS_WRITE(save_control, RTC_CONTROL);
 		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
-		spin_unlock_irqrestore(&rtc_lock, flags);
+		spin_unlock_irq(&rtc_lock);
 		return 0;
 	}
 #ifndef __alpha__
@@ -446,13 +466,13 @@
 		if (arg != (1<<tmp))
 			return -EINVAL;
 
+		spin_lock_irq(&rtc_lock);
 		rtc_freq = arg;
 
-		spin_lock_irqsave(&rtc_lock, flags);
 		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
 		val |= (16 - tmp);
 		CMOS_WRITE(val, RTC_FREQ_SELECT);
-		spin_unlock_irqrestore(&rtc_lock, flags);
+		spin_unlock_irq(&rtc_lock);
 		return 0;
 	}
 #else
@@ -489,18 +509,18 @@
 
 static int rtc_open(struct inode *inode, struct file *file)
 {
-	unsigned long flags;
-
-	if(atomic_read(&rtc_status) & RTC_IS_OPEN)
+	/* If someday somebody decides to remove the kernel_lock on open and
+	 * close and ioctl this is gonna get open to races */
+	if(rtc_status & RTC_IS_OPEN)
 		return -EBUSY;
 
 	MOD_INC_USE_COUNT;
 
-	atomic_set(&rtc_status, atomic_read(&rtc_status) | RTC_IS_OPEN);
+	rtc_status |= RTC_IS_OPEN;
 
-	spin_lock_irqsave (&rtc_lock, flags);
+	spin_lock_irq (&rtc_lock);
 	rtc_irq_data = 0;
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	spin_unlock_irq (&rtc_lock);
 	return 0;
 }
 
@@ -512,7 +532,6 @@
 
 static int rtc_release(struct inode *inode, struct file *file)
 {
-	unsigned long flags;
 #ifndef __alpha__
 	/*
 	 * Turn off all interrupts once the device is no longer
@@ -521,19 +540,19 @@
 
 	unsigned char tmp;
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	tmp = CMOS_READ(RTC_CONTROL);
 	tmp &=  ~RTC_PIE;
 	tmp &=  ~RTC_AIE;
 	tmp &=  ~RTC_UIE;
 	CMOS_WRITE(tmp, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
-	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	if (atomic_read(&rtc_status) & RTC_TIMER_ON) {
-		atomic_set(&rtc_status, atomic_read(&rtc_status) & ~RTC_TIMER_ON);
+	if (rtc_status & RTC_TIMER_ON) {
+		rtc_status &= ~RTC_TIMER_ON;
 		del_timer(&rtc_irq_timer);
 	}
+	spin_unlock_irq(&rtc_lock);
 
 	if (file->f_flags & FASYNC) {
 		rtc_fasync (-1, file, 0);
@@ -542,10 +561,10 @@
 #endif
 	MOD_DEC_USE_COUNT;
 
-	spin_lock_irqsave (&rtc_lock, flags);
+	spin_lock_irq (&rtc_lock);
 	rtc_irq_data = 0;
-	spin_unlock_irqrestore (&rtc_lock, flags);
-	atomic_set(&rtc_status, atomic_read(&rtc_status) & ~RTC_IS_OPEN);
+	spin_unlock_irq (&rtc_lock);
+	rtc_status = rtc_status & ~RTC_IS_OPEN;
 	return 0;
 }
 
@@ -553,13 +572,13 @@
 /* Called without the kernel lock - fine */
 static unsigned int rtc_poll(struct file *file, poll_table *wait)
 {
-	unsigned long l, flags;
+	unsigned long l;
 
 	poll_wait(file, &rtc_wait, wait);
 
-	spin_lock_irqsave (&rtc_lock, flags);
+	spin_lock_irq (&rtc_lock);
 	l = rtc_irq_data;
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	spin_unlock_irq (&rtc_lock);
 
 	if (l != 0)
 		return POLLIN | POLLRDNORM;
@@ -592,7 +611,6 @@
 
 static int __init rtc_init(void)
 {
-	unsigned long flags;
 #ifdef __alpha__
 	unsigned int year, ctrl;
 	unsigned long uip_watchdog;
@@ -663,10 +681,10 @@
 		while (jiffies - uip_watchdog < 2*HZ/100)
 			barrier();
 	
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	year = CMOS_READ(RTC_YEAR);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 	
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 		BCD_TO_BIN(year);       /* This should never happen... */
@@ -684,12 +702,12 @@
 #ifndef __alpha__
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-#endif
+	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+#endif
 
 	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
 
@@ -699,9 +717,16 @@
 static void __exit rtc_exit (void)
 {
 	/* interrupts and maybe timer disabled at this point by rtc_release */
+	/* FIXME: Maybe??? */
 
-	if (atomic_read(&rtc_status) & RTC_TIMER_ON)
+	if (rtc_status & RTC_TIMER_ON) {
+		spin_lock_irq (&rtc_lock);
+		rtc_status &= ~RTC_TIMER_ON;
 		del_timer(&rtc_irq_timer);
+		spin_unlock_irq (&rtc_lock);
+
+		printk(KERN_WARNING "rtc_exit(), and timer still running.\n");
+	}
 
 	remove_proc_entry ("driver/rtc", NULL);
 	misc_deregister(&rtc_dev);
@@ -735,16 +760,24 @@
 
 static void rtc_dropped_irq(unsigned long data)
 {
-	unsigned long flags;
-
 	printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);
-	mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq (&rtc_lock);
+
+	/* Just in case someone disabled the timer from behind our back... */
+	if (rtc_status & RTC_TIMER_ON)
+		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
+
 	rtc_irq_data += ((rtc_freq/HZ)<<8);
 	rtc_irq_data &= ~0xff;
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
+
+	/* Now we have new data */
+	wake_up_interruptible(&rtc_wait);
+
+	if (rtc_async_queue)
+		kill_fasync (rtc_async_queue, SIGIO, POLL_IN);
 }
 #endif
 
@@ -759,12 +792,13 @@
 	char *p;
 	struct rtc_time tm;
 	unsigned char batt, ctrl;
-	unsigned long flags;
+	unsigned long freq;
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	batt = CMOS_READ(RTC_VALID) & RTC_VRT;
 	ctrl = CMOS_READ(RTC_CONTROL);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	freq = rtc_freq;
+	spin_unlock_irq(&rtc_lock);
 
 	p = buf;
 
@@ -821,7 +855,7 @@
 		     YN(RTC_AIE),
 		     YN(RTC_UIE),
 		     YN(RTC_PIE),
-		     rtc_freq,
+		     freq,
 		     batt ? "okay" : "dead");
 
 	return  p - buf;
@@ -844,21 +878,20 @@
 /*
  * Returns true if a clock update is in progress
  */
+/* FIXME shouldn't this be above rtc_init to make it fully inlined? */
 static inline unsigned char rtc_is_updating(void)
 {
-	unsigned long flags;
 	unsigned char uip;
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 	return uip;
 }
 
 static void get_rtc_time(struct rtc_time *rtc_tm)
 {
-
-	unsigned long flags, uip_watchdog = jiffies;
+	unsigned long uip_watchdog = jiffies;
 	unsigned char ctrl;
 
 	/*
@@ -881,7 +914,7 @@
 	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
 	 * by the RTC when initially set to a non-zero value.
 	 */
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
 	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
 	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
@@ -889,7 +922,7 @@
 	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
 	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	{
@@ -913,19 +946,18 @@
 
 static void get_rtc_alm_time(struct rtc_time *alm_tm)
 {
-	unsigned long flags;
 	unsigned char ctrl;
 
 	/*
 	 * Only the values that we read from the RTC are set. That
 	 * means only tm_hour, tm_min, and tm_sec.
 	 */
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
 	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
 	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	{
@@ -949,28 +981,28 @@
 static void mask_rtc_irq_bit(unsigned char bit)
 {
 	unsigned char val;
-	unsigned long flags;
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	val = CMOS_READ(RTC_CONTROL);
 	val &=  ~bit;
 	CMOS_WRITE(val, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
+
 	rtc_irq_data = 0;
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 }
 
 static void set_rtc_irq_bit(unsigned char bit)
 {
 	unsigned char val;
-	unsigned long flags;
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock_irq(&rtc_lock);
 	val = CMOS_READ(RTC_CONTROL);
 	val |= bit;
 	CMOS_WRITE(val, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
+
 	rtc_irq_data = 0;
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock_irq(&rtc_lock);
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.99-pre6/linux/drivers/char/serial.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/serial.c	Mon May  8 22:00:41 2000
@@ -4477,7 +4477,7 @@
 #if (LINUX_VERSION_CODE > 0x20100)
 	serial_driver.driver_name = "serial";
 #endif
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+#ifdef 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 && defined(CONFIG_DEVFS_FS))
+#ifdef CONFIG_DEVFS_FS
 	callout_driver.name = "cua/%d";
 #else
 	callout_driver.name = "cua";
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.3.99-pre6/linux/drivers/char/softdog.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/softdog.c	Fri Apr 28 22:50:13 2000
@@ -83,9 +83,7 @@
 	/*
 	 *	Activate timer
 	 */
-	del_timer(&watchdog_ticktock);
-	watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
-	add_timer(&watchdog_ticktock);
+	mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
 	timer_alive=1;
 	return 0;
 }
@@ -104,15 +102,6 @@
 	return 0;
 }
 
-static void softdog_ping(void)
-{
-	/*
-	 *	Refresh the timer.
-	 */
-
-	mod_timer(&watchdog_ticktock, jiffies + (soft_margin * HZ));
-}
-
 static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
 {
 	/*  Can't seek (pwrite) on this device  */
@@ -122,9 +111,8 @@
 	/*
 	 *	Refresh the timer.
 	 */
-	if(len)
-	{
-		softdog_ping();
+	if(len) {
+		mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
 		return 1;
 	}
 	return 0;
@@ -151,7 +139,7 @@
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0,(int *)arg);
 		case WDIOC_KEEPALIVE:
-			softdog_ping();
+			mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
 			return 0;
 	}
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- v2.3.99-pre6/linux/drivers/char/specialix.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/char/specialix.c	Sat Apr 29 09:56:12 2000
@@ -2351,11 +2351,12 @@
 			                        pdev);
 			if (!pdev) break;
 
+			if (pci_enable_device(pdev))
+				continue;
+
 			sx_board[i].irq = pdev->irq;
 
-			pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
-			/* Mask out the fact that it's IO-space */
-			sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; 
+			sx_board[i].base = pci_resource_start (pdev, 2);
 
 			sx_board[i].flags |= SX_BOARD_IS_PCI;
 			if (!sx_probe(&sx_board[i]))
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.3.99-pre6/linux/drivers/char/stallion.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/char/stallion.c	Fri Apr 28 23:00:06 2000
@@ -2778,6 +2778,8 @@
 		devp->bus->number, devp->devfn);
 #endif
 
+	if (pci_enable_device(devp))
+		return(-EIO);
 	if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
 		return(-ENOMEM);
 	if ((brdp->brdnr = stl_getbrdnr()) < 0) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/stradis.c linux/drivers/char/stradis.c
--- v2.3.99-pre6/linux/drivers/char/stradis.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/stradis.c	Fri Apr 28 23:00:06 2000
@@ -2048,6 +2048,9 @@
 	init_waitqueue_head(&saa->debiq);
 	init_waitqueue_head(&saa->vidq);
 	spin_lock_init(&saa->lock);
+
+	if (pci_enable_device(dev))
+		return -EIO;
 	
 	saa->id = dev->device;
 	saa->irq = dev->irq;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.3.99-pre6/linux/drivers/char/sx.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/sx.c	Fri Apr 28 23:00:06 2000
@@ -2472,6 +2472,8 @@
 		while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
 		                                PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
 			                              pdev))) {
+			if (pci_enable_device(pdev))
+				continue;
 #else
 			for (i=0;i< SX_NBOARDS;i++) {
 				if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
@@ -2503,14 +2505,16 @@
 
 			/* CF boards use base address 3.... */
 			if (IS_CF_BOARD (board))
-				pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3,
-				                      &tint);
+				board->hw_base = pci_resource_start (pdev, 3);
 			else
-				pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
-				                      &tint);
-			board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK;
+				board->hw_base = pci_resource_start (pdev, 2);
 			board->base2 = 
 			board->base = (ulong) ioremap(board->hw_base, WINDOW_LEN (board));
+			if (!board->base) {
+				printk(KERN_ERR "ioremap failed\n");
+				/* XXX handle error */
+			}
+
 			/* Most of the stuff on the CF board is offset by
 			   0x18000 ....  */
 			if (IS_CF_BOARD (board)) board->base += 0x18000;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.3.99-pre6/linux/drivers/char/synclink.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/synclink.c	Fri May  5 12:37:52 2000
@@ -324,8 +324,7 @@
 	char device_name[25];		/* device instance name */
 
 	unsigned int bus_type;	/* expansion bus type (ISA,EISA,PCI) */
-	unsigned char bus;		/* expansion bus number (zero based) */
-	unsigned char function;		/* PCI device number */
+	struct pci_dev *pdev;	/* pointer to PCI device info */
 
 	unsigned int io_base;		/* base I/O address of adapter */
 	unsigned int io_addr_size;	/* size of the I/O address range */
@@ -4524,50 +4523,24 @@
 #ifdef CONFIG_PCI
 	/* Auto detect PCI adapters */
 	
-	if ( pcibios_present() ) {
-		unsigned char bus;
-		unsigned char func;
+	{
 		unsigned int  shared_mem_base;
 		unsigned int  lcr_mem_base;
 		unsigned int  io_base;
 		unsigned char irq_line;
+		struct pci_dev *pdev = NULL;
 		
-		for(i=0;;i++){
-			if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
-				MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
+		while ((pdev = pci_find_device(
+				MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, pdev))) {
 				
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
-				struct pci_dev *pdev = pci_find_slot(bus,func);
 				irq_line = pdev->irq;				
-#else												
-				if (pcibios_read_config_byte(bus,func,
-					PCI_INTERRUPT_LINE,&irq_line) ) {
-					printk( "%s(%d):USC I/O addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-#endif
 
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
-					printk( "%s(%d):Shared mem addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-							
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_0,&lcr_mem_base) ) {
-					printk( "%s(%d):LCR mem addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-				
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_2,&io_base) ) {
-					printk( "%s(%d):USC I/O addr not set.\n",
-						__FILE__,__LINE__);
+				shared_mem_base = pci_resource_start (pdev, 3);
+				lcr_mem_base = pci_resource_start (pdev, 0);
+				io_base = pci_resource_start (pdev, 2);
+
+				if (pci_enable_device (pdev))
 					continue;
-				}
 				
 				info = mgsl_allocate_device();
 				if ( !info ) {
@@ -4579,29 +4552,23 @@
 		
 				/* Copy user configuration info to device instance data */
 		
-				info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK;
+				info->io_base = io_base;
 				info->irq_level = (unsigned int)irq_line;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 				info->irq_level = irq_cannonicalize(info->irq_level);
-#else		
-				if (info->irq_level == 2)
-					info->irq_level = 9;
-#endif			
-				info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
+				info->phys_memory_base = shared_mem_base;
 				
 				/* Because veremap only works on page boundaries we must map
 				 * a larger area than is actually implemented for the LCR
 				 * memory range. We map a full page starting at the page boundary.
 				 */
-				info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
+				info->phys_lcr_base = lcr_mem_base;
 				info->lcr_offset    = info->phys_lcr_base & (PAGE_SIZE-1);
 				info->phys_lcr_base &= ~(PAGE_SIZE-1);
 				
 				info->bus_type = MGSL_BUS_TYPE_PCI;
 				info->io_addr_size = 8;
 				info->irq_flags = SA_SHIRQ;
-				info->bus = bus;
-				info->function = func;
+				info->pdev = pdev;
 		
 				/* override default max frame size if arg available */
 				if ( num_devices < MAX_TOTAL_DEVICES && 
@@ -4621,9 +4588,6 @@
 				
 				/* add new device to device list */
 				mgsl_add_device( info );
-			} else {
-				break;
-			}
 		}
 	}
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.99-pre6/linux/drivers/char/tty_io.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/char/tty_io.c	Tue May  9 16:18:28 2000
@@ -1384,7 +1384,9 @@
 	    current->leader &&
 	    !current->tty &&
 	    tty->session == 0) {
+	    	task_lock(current);
 		current->tty = tty;
+		task_unlock(current);
 		current->tty_old_pgrp = 0;
 		tty->session = current->session;
 		tty->pgrp = current->pgrp;
@@ -1594,7 +1596,9 @@
 		} else
 			return -EPERM;
 	}
+	task_lock(current);
 	current->tty = tty;
+	task_unlock(current);
 	current->tty_old_pgrp = 0;
 	tty->session = current->session;
 	tty->pgrp = current->pgrp;
@@ -1761,7 +1765,9 @@
 				return -ENOTTY;
 			if (current->leader)
 				disassociate_ctty(0);
+			task_lock(current);
 			current->tty = NULL;
+			task_unlock(current);
 			return 0;
 		case TIOCSCTTY:
 			return tiocsctty(tty, arg);
@@ -1858,8 +1864,9 @@
 			send_sig(SIGKILL, p, 1);
 		else if (p->files) {
 			read_lock(&p->files->file_lock);
+			/* FIXME: p->files could change */
 			for (i=0; i < p->files->max_fds; i++) {
-				filp = fcheck_task(p, i);
+				filp = fcheck_files(p->files, i);
 				if (filp && (filp->f_op == &tty_fops) &&
 				    (filp->private_data == tty)) {
 					send_sig(SIGKILL, p, 1);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.3.99-pre6/linux/drivers/char/vt.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/char/vt.c	Tue May  2 16:48:16 2000
@@ -104,8 +104,7 @@
 void
 _kd_mksound(unsigned int hz, unsigned int ticks)
 {
-	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
-						 kd_nosound };
+	static struct timer_list sound_timer = { function: kd_nosound };
 	unsigned int count = 0;
 	unsigned long flags;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/char/zr36120.c linux/drivers/char/zr36120.c
--- v2.3.99-pre6/linux/drivers/char/zr36120.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/zr36120.c	Fri Apr 28 23:00:06 2000
@@ -1852,17 +1852,14 @@
 	unsigned char revision;
 	int zoran_num=0;
 
-	if (!pcibios_present())
-	{
-		printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n");
-		return 0;
-	}
-
 	while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
 	{
 		/* Ok, a ZR36120/ZR36125 found! */
 		ztv = &zorans[zoran_num];
 		ztv->dev = dev;
+
+		if (pci_enable_device(dev))
+			return -EIO;
 
 		pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
 		printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.99-pre6/linux/drivers/i2o/i2o_block.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_block.c	Wed May 10 16:56:42 2000
@@ -25,11 +25,17 @@
  *		Independent queues per IOP
  *		Support for dynamic device creation/deletion
  *		Code cleanup	
- *    Support for larger I/Os through merge* functions 
- *       (taken from DAC960 driver)
+ *    		Support for larger I/Os through merge* functions 
+ *       	(taken from DAC960 driver)
+ *	Boji T Kannanthanam:
+ *		Reduced the timeout during RAID 5 creation. 
+ *		This is to prevent race condition when a RAID volume
+ *		is created and immediately deleted.
  *
  *	To do:
  *		Serial number scanning to find duplicates for FC multipathing
+ *		Remove the random timeout in the code needed for RAID 5
+ *			volume creation.
  */
 
 #include <linux/major.h>
@@ -1376,7 +1382,7 @@
 	 * so we just sleep for a little while and let it do it's thing
 	 */
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(10*HZ);
+	schedule_timeout(3*HZ);
 
 	if(i2o_claim_device(d, &i2o_block_handler))
 	{
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.99-pre6/linux/drivers/i2o/i2o_config.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_config.c	Wed May 10 16:56:42 2000
@@ -515,7 +515,7 @@
 		msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
 		msg[5] = 0x50000000|65536;
 		msg[7] = 0xD4000000|(kcmd.qlen);
-		msg[8] = virt_to_phys(query);
+		msg[8] = virt_to_bus(query);
 	}
 
 	token = i2o_post_wait(c, msg, 9*4, 10);
@@ -592,7 +592,7 @@
 	msg[5]= swlen;
 	msg[6]= kxfer.sw_id;
 	msg[7]= (0xD0000000 | fragsize);
-	msg[8]= virt_to_phys(buffer);
+	msg[8]= virt_to_bus(buffer);
 
 //	printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
 	status = i2o_post_wait(c, msg, sizeof(msg), 60);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.99-pre6/linux/drivers/i2o/i2o_core.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_core.c	Wed May 10 16:56:42 2000
@@ -18,6 +18,7 @@
  *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
  *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
  *		Deepak Saxena <deepak@plexity.net> 
+ *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
  * 
  */
 
@@ -70,12 +71,11 @@
 /* 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_reset_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 *,
@@ -111,6 +111,14 @@
 static int sys_tbl_ind = 0;
 static int sys_tbl_len = 0;
 
+/*
+ * This spin lock is used to keep a device from being
+ * added and deleted concurrently across CPUs or interrupts.
+ * This can occur when a user creates a device and immediatelly
+ * deletes it before the new_dev_notify() handler is called.
+ */
+static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef MODULE
 /* 
  * Function table to send to bus specific layers
@@ -214,24 +222,12 @@
 	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
+	if (msg[0] & MSG_FAIL) // Fail bit is set
 	{
 		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);
+		i2o_report_status(KERN_INFO, "i2o_core", msg);
+		i2o_dump_message(preserved_msg);
 
 		/* If the failed request needs special treatment,
 		 * it should be done here. */
@@ -244,16 +240,18 @@
 		i2o_post_message(c, msg[7]);
 
 		/* If reply to i2o_post_wait failed, return causes a timeout */
+
 		return;
 	}       
 
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, "i2o_core", msg);
+#endif
+
 	if(msg[2]&0x80000000)	// Post wait message
 	{
 		if (msg[4] >> 24)
-		{
-			i2o_report_status(KERN_INFO, "i2o_core: post_wait reply", msg);
 			status = -(msg[4] & 0xFFFF);
-		}
 		else
 			status = I2O_POST_WAIT_OK;
 	
@@ -263,7 +261,7 @@
 
 	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
 	{
-		memcpy(events[evt_in].msg, msg, MSG_FRAME_SIZE);
+		memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2);
 		events[evt_in].iop = c;
 
 		spin_lock(&i2o_evt_lock);
@@ -471,7 +469,7 @@
 	char name[16];
 	int stat;
 
-	dprintk(KERN_INFO "Deleting controller iop%d\n", c->unit);
+	dprintk(KERN_INFO "Deleting controller %s\n", c->name);
 
 	/*
 	 * Clear event registration as this can cause weird behavior
@@ -482,7 +480,7 @@
 	spin_lock(&i2o_configuration_lock);
 	if((users=atomic_read(&c->users)))
 	{
-		dprintk(KERN_INFO "I2O: %d users for controller iop%d\n", users,
+		dprintk(KERN_INFO "I2O: %d users for controller %s\n", users,
 			c->name);
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
@@ -523,9 +521,8 @@
 	{
 		if(*p==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);
+ 			/* Ask the IOP to switch to RESET state */
+			i2o_reset_controller(c);
 
 			/* Release IRQ */
 			c->destructor(c);
@@ -578,7 +575,21 @@
 	spin_unlock(&i2o_configuration_lock);
 	return c;
 }
+
+/*
+ *	Issue UTIL_CLAIM or UTIL_RELEASE message
+ */
+static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type)
+{
+	u32 msg[5];
+
+	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = cmd << 24 | HOST_TID<<12 | tid;
+	msg[3] = 0;
+	msg[4] = type;
 	
+	return i2o_post_wait(c, msg, sizeof(msg), 60);
+}
 
 /*
  * Claim a device for use by an OSM
@@ -586,15 +597,15 @@
 int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h)
 {
 	spin_lock(&i2o_configuration_lock);
-	if(d->owner)
-	{
-		printk(KERN_INFO "issue claim called, but dev as owner!");
+	if (d->owner) {
+		printk(KERN_INFO "Device claim called, but dev allready owned by %s!",
+		       h->name);
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
 
-	if(i2o_issue_claim(d->controller,d->lct_data.tid, h->context, 1,
-		 I2O_CLAIM_PRIMARY))
+	if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, 
+			   I2O_CLAIM_PRIMARY))
 	{
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
@@ -606,21 +617,22 @@
 }
 
 /*
- * Release a device that the OS is using
+ * Release a device that the OSM is using
  */
 int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
 {
 	int err = 0;
 
 	spin_lock(&i2o_configuration_lock);
-	if(d->owner != h)
-	{
+	if (d->owner != h) {
+		printk(KERN_INFO "Claim release called, but not owned by %s!",
+		       h->name);
 		spin_unlock(&i2o_configuration_lock);
 		return -ENOENT;
 	}	
 
-	if(i2o_issue_claim(d->controller, d->lct_data.tid, h->context, 0,
-			I2O_CLAIM_PRIMARY))
+	if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, 
+			   I2O_CLAIM_PRIMARY))
 	{
 		err = -ENXIO;
 	}
@@ -684,13 +696,13 @@
 		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
+			// 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[2] = init_context;
+	msg[3] = tr_context;
 	msg[4] = evt_mask;
 
 	return i2o_post_this(c, msg, sizeof(msg));
@@ -703,6 +715,7 @@
  * 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;
@@ -819,7 +832,11 @@
 					if(i2o_handlers[i] && 
 						i2o_handlers[i]->new_dev_notify &&
 						(i2o_handlers[i]->class&d->lct_data.class_id))
+						{
+						spin_lock(&i2o_dev_lock);
 						i2o_handlers[i]->new_dev_notify(c,d);
+						spin_unlock(&i2o_dev_lock);
+						}
 				}
 			
 				break;
@@ -855,7 +872,7 @@
 				break;
 	
 			default:
-				printk(KERN_WARNING "%s: Unknown event (0x%08x)...check config\n", c->name, msg[4]);
+				printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]);
 				break;
 		}
 	}
@@ -939,7 +956,9 @@
 			if(!found) 
 			{
 				dprintk(KERN_INFO "Deleted device!\n"); 
+				spin_lock(&i2o_dev_lock);
 				i2o_delete_device(d); 
+				spin_unlock(&i2o_dev_lock);
 			} 
 			d = d1; 
 		}
@@ -1114,29 +1133,6 @@
 	}
 	return m;
 }
-
-
-/*
- *	Wait up to timeout seconds for a reply to be available.
- */
- 
-u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
-{
-	u32 m;
-	long time=jiffies;
-	
-	while((m=I2O_REPLY_READ32(c))==0xFFFFFFFF)
-	{
-		if(jiffies-time >= timeout*HZ )
-		{
-			dprintk(KERN_ERR "%s: timeout waiting for %s reply.\n",
-				c->name, why);
-			return 0xFFFFFFFF;
-		}
-		schedule();
-	}
-	return m;
-}
 	
 /*
  *	 Dump the information block associated with a given unit (TID)
@@ -1371,12 +1367,12 @@
 	/* Long timeout needed for quiesce if lots of devices */
 
 	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
-		printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n",
-			c->name, ret);
+		printk(KERN_INFO "%s: Unable to quiesce (status=%#x).\n",
+			c->name, -ret);
 	else
 		dprintk(KERN_INFO "%s: Quiesced.\n", c->name);
 
-	i2o_status_get(c); // Reread the Status Block
+	i2o_status_get(c); // Entered READY state
 
    return ret;
 
@@ -1402,12 +1398,12 @@
    /* 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",
-			c->name, ret);
+		printk(KERN_ERR "%s: Could not enable (status=%#x).\n",
+			c->name, -ret);
 	else
 		dprintk(KERN_INFO "%s: Enabled.\n", c->name);
 
-	i2o_status_get(c);
+	i2o_status_get(c); // entered OPERATIONAL state
 
 	return ret;
 }
@@ -1434,8 +1430,8 @@
 	msg[3]=0;
 
 	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
-		printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n",
-			c->name, ret);
+		printk(KERN_INFO "%s: Unable to clear (status=%#x).\n",
+			c->name, -ret);
 	else
 		dprintk(KERN_INFO "%s: Cleared.\n",c->name);
 
@@ -1470,7 +1466,6 @@
 	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;
@@ -1489,7 +1484,7 @@
 	msg[3]=0;
 	msg[4]=0;
 	msg[5]=0;
-	msg[6]=virt_to_phys(status);
+	msg[6]=virt_to_bus(status);
 	msg[7]=0;	/* 64bit host FIXME */
 
 	i2o_post_message(c,m);
@@ -1508,7 +1503,7 @@
 		barrier();
 	}
 
-	if (status[0]==0x01)
+	if (status[0]==I2O_CMD_IN_PROGRESS)
 	{ 
 		/* 
 		 * Once the reset is sent, the IOP goes into the INIT state 
@@ -1519,7 +1514,7 @@
 		 * time, we assume the IOP could not reboot properly.  
 		 */ 
 
-		dprintk(KERN_INFO "Reset succeeded...waiting for reboot\n"); 
+		dprintk(KERN_INFO "Reset in progress, waiting for reboot\n"); 
 
 		time = jiffies; 
 		m = I2O_POST_READ32(c); 
@@ -1534,21 +1529,21 @@
 			schedule(); 
 			barrier(); 
 			m = I2O_POST_READ32(c); 
-		} 
-
+		}
 		i2o_flush_reply(c,m);
-
-		dprintk(KERN_INFO "%s: Reset completed.\n", c->name);
 	}
 
 	/* If IopReset was rejected or didn't perform reset, try IopClear */
 
 	i2o_status_get(c);
-	if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET)
+	if (status[0] == I2O_CMD_REJECTED || 
+		c->status_block->iop_state != ADAPTER_STATE_RESET)
 	{
 		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name);
 		i2o_clear_controller(c);
 	}
+	else
+		dprintk(KERN_INFO "%s: Reset completed.\n", c->name);
 
 	/* Enable other IOPs */
 
@@ -1598,7 +1593,7 @@
 	msg[3]=0;
 	msg[4]=0;
 	msg[5]=0;
-	msg[6]=virt_to_phys(c->status_block);
+	msg[6]=virt_to_bus(c->status_block);
 	msg[7]=0;   /* 64bit host FIXME */
 	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
 
@@ -1618,9 +1613,6 @@
 		barrier();
 	}
 
-	/* Ok the reply has arrived. Fill in the important stuff */
-	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) {
@@ -1678,11 +1670,11 @@
 		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
 		msg[3]= 0;
 		msg[4]= (0xD0000000 | size);	/* Simple transaction */
-		msg[5]= virt_to_phys(c->hrt);	/* Dump it here */
+		msg[5]= virt_to_bus(c->hrt);	/* Dump it here */
 
 		if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
-			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n",
-				c->name, ret);	
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n",
+				c->name, -ret);	
 			return ret;
 		}
 
@@ -1730,18 +1722,20 @@
  	 * Private i/o space declaration  
  	 */
 	msg[6] = 0x54000000 | sys_tbl_len;
-	msg[7] = virt_to_phys(sys_tbl);
+	msg[7] = virt_to_bus(sys_tbl);
 	msg[8] = 0x54000000 | 0;
-	msg[9] = virt_to_phys(privmem);
+	msg[9] = virt_to_bus(privmem);
 	msg[10] = 0xD4000000 | 0;
-	msg[11] = virt_to_phys(privio);
+	msg[11] = virt_to_bus(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);
+		printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", 
+			iop->name, -ret);
 	else
 		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
 
+	i2o_status_get(iop); // Entered READY state
+
 	return ret;	
 
  }
@@ -1761,7 +1755,8 @@
 		dprintk(KERN_INFO "Calling i2o_activate_controller for %s\n", 
 			iop->name);
 		niop = iop->next;
-		i2o_activate_controller(iop);
+		if (i2o_activate_controller(iop) < 0)
+			i2o_delete_controller(iop);
 	}
 
 	/* Active IOPs in HOLD state */
@@ -1784,8 +1779,10 @@
 	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)
+		if (i2o_online_controller(iop) < 0) {
+			i2o_delete_controller(iop);	
 			goto rebuild_sys_tab;
+		}
 	}
 	
 	/* Active IOPs now in OPERATIONAL state */
@@ -1835,17 +1832,12 @@
 
 	if (i2o_status_get(iop) < 0) {
 		printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n");
-		i2o_reset_controller(iop);
-		if (i2o_status_get(iop) < 0) {
-			printk(KERN_ERR "%s: IOP not responding.\n", iop->name);
-			i2o_delete_controller(iop);
+		if (i2o_reset_controller(iop) < 0)
 			return -1;
-		}
 	}
 
 	if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
 		printk(KERN_CRIT "%s: hardware fault\n", iop->name);
-		i2o_delete_controller(iop);
 		return -1;
 	}
 
@@ -1855,37 +1847,26 @@
 	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
 	{
 		u32 m[MSG_FRAME_SIZE];
-		dprintk(KERN_INFO "%s: already running...trying to reset\n",
+		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_REPLY_WRITE32(iop,virt_to_bus(m));
 
-		i2o_reset_controller(iop);			
-
-		if (i2o_status_get(iop) < 0 || 
-			iop->status_block->iop_state != ADAPTER_STATE_RESET)
-		{
-			printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name);
-			i2o_delete_controller(iop);
+		if (i2o_reset_controller(iop) < 0)
 			return -1;
-		}
 	}
 
-	if (i2o_init_outbound_q(iop) < 0) {
-		i2o_delete_controller(iop);
+	if (i2o_init_outbound_q(iop) < 0)
 		return -1;
-	}
 
 	if (i2o_post_outbound_messages(iop)) 
 		return -1;
 
 	/* In HOLD state */
 	
-	if (i2o_hrt_get(iop) < 0) {
-		i2o_delete_controller(iop);
+	if (i2o_hrt_get(iop) < 0)
 		return -1;
-	}
 
 	return 0;
 }
@@ -1909,29 +1890,28 @@
 
 	status = kmalloc(4,GFP_KERNEL);
 	if (status==NULL) {
-		printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+		printk(KERN_ERR "%s: Outbound Queue initialization failed - no free memory.\n",
 			c->name);
 		return -ENOMEM;
 	}
 	memset(status, 0, 4);
 
-
 	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<<16|0x80;	/* Outbound msg frame size and Initcode */
-	msg[6]= 0xD0000004;					/* Simple SG LE, EOB */
+	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */
 	msg[7]= virt_to_bus(status);
 
 	i2o_post_message(c,m);
 	
 	barrier();
 	time=jiffies;
-	while(status[0]<0x02)
+	while(status[0] < I2O_CMD_REJECTED)
 	{
 		if((jiffies-time)>=30*HZ)
 		{
@@ -1948,7 +1928,7 @@
 		barrier();
 	}  
 
-	if(status[0] != I2O_CMD_OUTBOUND_INIT_COMPLETE)
+	if(status[0] != I2O_CMD_COMPLETED)
 	{
 		printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name);
 		kfree(status);
@@ -1970,7 +1950,7 @@
 			c->name);
 		return -ENOMEM;
 	}
-	m=virt_to_phys(c->page_frame);
+	m=virt_to_bus(c->page_frame);
 
 	/* Post frames */
 
@@ -2012,8 +1992,8 @@
 		msg[7] = virt_to_bus(c->lct);
 
 		if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
-			printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 
-				c->name, ret);	
+			printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", 
+				c->name, -ret);	
 			return ret;
 		}
 
@@ -2057,26 +2037,20 @@
  */
 int i2o_online_controller(struct i2o_controller *iop)
 {
-	if (i2o_systab_send(iop) < 0) {
-		i2o_delete_controller(iop);
+	if (i2o_systab_send(iop) < 0)
 		return -1;
-	}
 
 	/* In READY state */
 
 	dprintk(KERN_INFO "Attempting to enable iop%d\n", iop->unit);
-	if (i2o_enable_controller(iop) < 0) {
-		i2o_delete_controller(iop);
+	if (i2o_enable_controller(iop) < 0)
 		return -1;
-	}
 
 	/* 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);
+	if (i2o_lct_get(iop) < 0)
 		return -1;
-	}
 
 	return 0;
 }
@@ -2147,7 +2121,7 @@
 		sys_tbl->iops[count].iop_capabilities = 
 				iop->status_block->iop_capabilities;
 		sys_tbl->iops[count].inbound_low = 
-				(u32)virt_to_phys(iop->post_port);
+				(u32)virt_to_bus(iop->post_port);
 		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support
 
 		count++;
@@ -2241,7 +2215,7 @@
 
 #ifdef DRIVERDEBUG
 	if(status == -ETIMEDOUT)
-		printk(KERN_INFO "POST WAIT TIMEOUT\n");
+		printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name);
 #endif
 
 	/* 
@@ -2305,26 +2279,6 @@
 	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)
-{
-	u32 msg[5];
-
-	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	if(onoff)
-		msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid;
-	else	
-		msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
-
-	msg[3] = 0;
-	msg[4] = type;
-	
-	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.
@@ -2541,44 +2495,69 @@
 	return size;
 }
 
-/*
- *	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)
-{
-	u16 *opblk; 
-	u8  resblk[32]; /* min 8 bytes for header */
-	int size;
 
-	opblk = kmalloc(keyslen+64, GFP_KERNEL);
-	if (opblk == NULL)
-	{
-		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
-		return -ENOMEM;
-	}
+/*
+ * Used for error reporting/debugging purposes.
+ * Following fail status are common to all classes.
+ * The preserved message must be handled in the reply handler. 
+ */
+void i2o_report_fail_status(u8 req_status, u32* msg)
+{
+	static char *FAIL_STATUS[] = { 
+		"0x80",				/* not used */
+		"SERVICE_SUSPENDED", 		/* 0x81 */
+		"SERVICE_TERMINATED", 		/* 0x82 */
+		"CONGESTION",
+		"FAILURE",
+		"STATE_ERROR",
+		"TIME_OUT",
+		"ROUTING_FAILURE",
+		"INVALID_VERSION",
+		"INVALID_OFFSET",
+		"INVALID_MSG_FLAGS",
+		"FRAME_TOO_SMALL",
+		"FRAME_TOO_LARGE",
+		"INVALID_TARGET_ID",
+		"INVALID_INITIATOR_ID",
+		"INVALID_INITIATOR_CONTEX",	/* 0x8F */
+		"UNKNOWN_FAILURE"		/* 0xFF */
+	};
 
-	opblk[0] = 1;			/* operation count */
-	opblk[1] = 0;			/* pad */
-	opblk[2] = I2O_PARAMS_ROW_DELETE;
-	opblk[3] = group;	
-	opblk[4] = keycount;
-	memcpy(opblk+5, keys, keyslen);
+	if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
+		printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status);
+	else
+		printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]);
 
-	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
-				opblk, 10+keyslen, resblk, sizeof(resblk));
+	/* Dump some details */
 
-	kfree(opblk);
-	return size;
+	printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
+		(msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); 
+	printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
+		(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+	printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
+		msg[5] >> 16, msg[5] & 0xFFF);
+
+	printk(KERN_ERR "  Severity:  0x%02X ", (msg[4] >> 16) & 0xFF); 
+	if (msg[4] & (1<<16))
+		printk("(FormatError), "
+			"this msg can never be delivered/processed.\n");
+	if (msg[4] & (1<<17))
+		printk("(PathError), "
+			"this msg can no longer be delivered/processed.\n");
+	if (msg[4] & (1<<18))
+		printk("(PathState), "
+			"the system state does not allow delivery.\n");
+	if (msg[4] & (1<<19))
+		printk("(Congestion), resources temporarily not available;"
+			"do not retry immediately.\n");
 }
 
 /*
- * Used for error reporting/debugging purposes
+ * Used for error reporting/debugging purposes.
+ * Following reply status are common to all classes.
  */
 void i2o_report_common_status(u8 req_status)
 {
-	/* the following reply status strings are common to all classes */
-
 	static char *REPLY_STATUS[] = { 
 		"SUCCESS", 
 		"ABORT_DIRTY", 
@@ -2595,23 +2574,18 @@
 	};
 
 	if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT)
-		printk("%0#4x / ", req_status);
+		printk("RequestStatus = %0#2x", req_status);
 	else
-		printk("%s / ", REPLY_STATUS[req_status]);
-	
-	return;
+		printk("%s", REPLY_STATUS[req_status]);
 }
 
 /*
- * Used for error reporting/debugging purposes
+ * Used for error reporting/debugging purposes.
+ * Following detailed status are valid  for executive class, 
+ * utility class, DDM class and for transaction error replies.
  */
 static void i2o_report_common_dsc(u16 detailed_status)
 {
-	/* The following detailed statuscodes are valid 
-	   - for executive class, utility class, DDM class and
-	   - for transaction error replies
-	*/	
-
 	static char *COMMON_DSC[] = { 
 		"SUCCESS",
 		"0x01",				// not used
@@ -2645,11 +2619,9 @@
 	};
 
 	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
-		printk("%0#4x.\n", detailed_status);
+		printk(" / DetailedStatus = %0#4x.\n", detailed_status);
 	else
-		printk("%s.\n", COMMON_DSC[detailed_status]);
-
-	return;
+		printk(" / %s.\n", COMMON_DSC[detailed_status]);
 }
 
 /*
@@ -2680,11 +2652,9 @@
 	};
 
 	if (detailed_status > I2O_DSC_INVALID_REQUEST)
-		printk("%0#4x.\n", detailed_status);
+		printk(" / %0#4x.\n", detailed_status);
 	else
-		printk("%s.\n", LAN_DSC[detailed_status]);
-
-	return;	
+		printk(" / %s.\n", LAN_DSC[detailed_status]);
 }
 
 /*
@@ -2736,10 +2706,8 @@
 		printk("UTIL_REPLY_FAULT_NOTIFY, ");
 		break;
 	default:
-		printk("%0#2x, ",cmd);	
+		printk("Cmd = %0#2x, ",cmd);	
 	}
-
-	return;	
 }
 
 /*
@@ -2848,10 +2816,8 @@
 		printk("EXEC_SYS_TAB_SET, ");
 		break;
 	default:
-		printk("%02x, ",cmd);	
+		printk("Cmd = %#02x, ",cmd);	
 	}
-
-	return;	
 }
 
 /*
@@ -2876,51 +2842,48 @@
 		printk("LAN_SUSPEND, ");
 		break;
 	default:
-		printk("%02x, ",cmd);	
+		printk("Cmd = %0#2x, ",cmd);	
 	}	
-
-	return;
 }
 
 /*
- * Used for error reporting/debugging purposes
+ * Used for error reporting/debugging purposes.
+ * Report Cmd name, Request status, Detailed Status.
  */
-void i2o_report_status(const char *severity, const char *module, u32 *msg)
+void i2o_report_status(const char *severity, const char *str, 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);
+	printk("%s%s: ", severity, str);
 
-	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 < 0x1F) 			// Utility cmd
+		i2o_report_util_cmd(cmd);
+	
+	else if (cmd >= 0xA0 && cmd <= 0xEF) 	// Executive cmd
+		i2o_report_exec_cmd(cmd);
+	
+	else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
+		i2o_report_lan_cmd(cmd);	// LAN cmd
+	else
+        	printk("Cmd = %0#2x, ", cmd);	// Other cmds
 
-		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);
+	if (msg[0] & MSG_FAIL) {
+		i2o_report_fail_status(req_status, msg);
+		return;
 	}
+	
+	i2o_report_common_status(req_status);
+
+	if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
+		i2o_report_common_dsc(detailed_status);
+		
+	if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F)
+		i2o_report_lan_dsc(detailed_status);
+	else
+		printk(" / DetailedStatus = %0#4x.\n", detailed_status); 
 }
 
 /* Used to dump a message to syslog during debugging */
@@ -3005,7 +2968,6 @@
 EXPORT_SYMBOL(i2o_query_table);
 EXPORT_SYMBOL(i2o_clear_table);
 EXPORT_SYMBOL(i2o_row_add_table);
-EXPORT_SYMBOL(i2o_row_delete_table);
 EXPORT_SYMBOL(i2o_issue_params);
 
 EXPORT_SYMBOL(i2o_event_register);
@@ -3013,6 +2975,7 @@
 
 EXPORT_SYMBOL(i2o_report_status);
 EXPORT_SYMBOL(i2o_dump_message);
+
 EXPORT_SYMBOL(i2o_get_class_name);
 
 MODULE_AUTHOR("Red Hat Software");
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.99-pre6/linux/drivers/i2o/i2o_lan.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_lan.c	Wed May 10 16:56:43 2000
@@ -1,7 +1,7 @@
 /*
  *	drivers/i2o/i2o_lan.c
  *
- * 	I2O LAN CLASS OSM 		April 3rd 2000
+ * 	I2O LAN CLASS OSM 		May  4th 2000
  *
  *	(C) Copyright 1999, 2000 	University of Helsinki,
  *		      			Department of Computer Science
@@ -22,8 +22,7 @@
  *			in Gigabit Eth environment (using SysKonnect's DDM)
  *			in Fast Ethernet environment (using Intel 82558 DDM)
  *
- *	TODO:		check error checking / timeouts
- *			code / test for other LAN classes
+ *	TODO:		tests for other LAN classes (Token Ring, Fibre Channel)
  */
 
 #include <linux/config.h>
@@ -62,8 +61,8 @@
 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;
+static u8  tx_batch_mode   = I2O_LAN_TX_BATCH_MODE;
+static u32 i2o_event_mask  = I2O_LAN_EVENT_MASK;
 
 #define MAX_LAN_CARDS 16
 static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];
@@ -139,8 +138,7 @@
 	struct sk_buff *skb = NULL;
 	u8 le_flag;
 
-// To be added to i2o_core.c
-//	i2o_report_failure(KERN_INFO, iop, dev->name, msg);
+	i2o_report_status(KERN_INFO, dev->name, msg);
 
 	/* If PacketSend failed, free sk_buffs reserved by upper layers */
 
@@ -190,8 +188,7 @@
 	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);
+	i2o_report_status(KERN_INFO, dev->name, msg);
 
 	/* If PacketSend was rejected, free sk_buff reserved by upper layers */
 
@@ -253,17 +250,15 @@
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	u8 trl_count  = msg[3] & 0x000000FF;
 
-#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 */
 	}
 
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
 	/* DDM has handled transmit request(s), free sk_buffs */
 
 	while (trl_count) {
@@ -284,7 +279,7 @@
  * i2o_lan_receive_post_reply(): Callback function to process incoming packets.
  */
 static void i2o_lan_receive_post_reply(struct i2o_handler *h,
-				       struct i2o_controller *iop, struct i2o_message *m)
+			struct i2o_controller *iop, struct i2o_message *m)
 {
 	u32 *msg = (u32 *)m;
 	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
@@ -297,10 +292,6 @@
 	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;
@@ -313,44 +304,46 @@
 			return;
 		}
 
-		/* Which DetailedStatusCodes need special treatment? */
+		/* If other DetailedStatusCodes need special code, add it here */
 	}
 
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
 	/* Else we are receiving incoming post. */
 
 	while (trl_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) {
+		/* Sanity checks: Any weird characteristics in bucket? */
 
+		if (packet->flags & 0x0f || ! packet->flags & 0x40) {
 			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;
-		}
+				printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n",
+					dev->name, packet->status & 0xff);
+
+			/* The following shouldn't happen, unless parameters in
+			 * LAN_OPERATION group are changed during the run time.
+			 */
+			 if (packet->flags & 0x0c)
+				printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", 
+					dev->name);
+					
+			if (! packet->flags & 0x40)
+				printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", 
+					dev->name);
+
+			dev_kfree_skb_irq(skb);
 
-		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
+
+		/* Copy short packet to a new skb */
+		
 		if (packet->len < priv->rx_copybreak) {
 			old_skb = skb;
 			skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);
@@ -366,13 +359,17 @@
 				priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;
 			else
 				dev_kfree_skb_irq(old_skb);
+
 			spin_unlock_irqrestore(&priv->fbl_lock, flags);
 		} else
 			skb_put(skb, packet->len);
 
+		/* Deliver to upper layers */
+
 		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 "
@@ -387,7 +384,7 @@
 		       dev->name, atomic_read(&priv->buckets_out));
 #endif
 
-	/* If DDM has already consumed bucket_tresh buckets, post new ones */
+	/* If DDM has already consumed bucket_thresh buckets, post new ones */
 
 	if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) {
 		i2o_post_buckets_task.data = (void *)dev;
@@ -409,10 +406,6 @@
 	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;
@@ -420,6 +413,10 @@
 		/* This should NOT be reached */
 	}
 
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
 	switch (msg[1] >> 24) {
 	case LAN_RESET:
 	case LAN_SUSPEND:
@@ -465,6 +462,7 @@
 	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 max_evt_data_size =iop->status_block->inbound_frame_size-5;
 	struct i2o_reply {
 		u8  version_offset;
 		u8  msg_flags;
@@ -475,7 +473,7 @@
 		u32 initiator_context;
 		u32 transaction_context;
 		u32 evt_indicator;
-		u32 data[(iop->inbound_size - 20) / 4];	/* max */
+		u32 data[max_evt_data_size]; /* max */
 	} *evt = (struct i2o_reply *)msg;
 	int evt_data_len = (evt->msg_size - 5) * 4;	/* real */
 
@@ -534,8 +532,8 @@
 
 	case I2O_EVT_IND_FIELD_MODIFIED: {
 		u16 *work16 = (u16 *)evt->data;
-		printk("Group 0x%04x, field %d changed.\n", work16[0],
-		       work16[1]);
+		printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]);
+
 		break;
 	}
 
@@ -564,7 +562,7 @@
 		break;
 
 	default:
-		printk("Event Indicator = 0x%08x.\n", evt->evt_indicator);
+		printk("0x%08x. No handler.\n", evt->evt_indicator);
 	}
 
 	/* Note: EventAck necessary only for events that cause the device to
@@ -660,7 +658,7 @@
 	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] = 0;				// keep posted buckets
+	msg[4] = 0;				 // Keep posted buckets
 
 	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
 		return -ETIMEDOUT;
@@ -694,43 +692,22 @@
 }
 
 /*
- * i2o_set_batch_mode(): Set DDM into batch mode.
+ * i2o_set_ddm_parameters:
+ * These settings are done to ensure proper initial values for DDM.
+ * They can be changed via proc file system or vai configuration utility.
  */
-static void i2o_set_batch_mode(struct net_device *dev)
+static void i2o_set_ddm_parameters(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 val;
 
-	/* Set defaults LAN_BATCH_CONTROL attributes */
-	/* May be changed via /proc or Configuration Utility */
-
-	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);
-	else
-		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,
+	 * When PacketOrphanlimit is set to the maximum packet length,
 	 * the packets will never be split into two separate buckets
 	 */
-	val = dev->mtu + dev->hard_header_len; // 2 = PacketOrphanLimit
+	val = dev->mtu + dev->hard_header_len;
 	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);
@@ -738,6 +715,15 @@
 		dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n",
 			dev->name, val);
 
+	/* When RxMaxPacketsBucket = 1, DDM puts only one packet into bucket */
+
+	val = 1;
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0008, 4, &val, sizeof(val)) <0)
+		printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n",
+		       dev->name);
+	else
+		dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to &d.\n", 
+			dev->name, val);
 	return;
 }
 
@@ -779,7 +765,7 @@
 	priv->i2o_fbl_tail = -1;
 	priv->send_active = 0;
 
-	i2o_set_batch_mode(dev);
+	i2o_set_ddm_parameters(dev);
 	i2o_lan_receive_post(dev);
 
 	netif_start_queue(dev);
@@ -795,9 +781,9 @@
 	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 ret = 0;
 
 	netif_stop_queue(dev);
-
 	i2o_lan_suspend(dev);
 
 	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
@@ -805,19 +791,20 @@
 		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
 		       dev->name);
 
+	while (priv->i2o_fbl_tail >= 0)
+		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+
+	kfree(priv->i2o_fbl);
+
 	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);
-		return -EBUSY;
+		ret = -EBUSY;
 	}
 
-	while (priv->i2o_fbl_tail >= 0)
-		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
-	kfree(priv->i2o_fbl);
-
 	MOD_DEC_USE_COUNT;
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -829,12 +816,12 @@
 		netif_start_queue(dev);
 }
 
-#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
+ * i2o_lan_batch_send(): Send packets in batch. 
+ * Both i2o_lan_sdu_send and i2o_lan_packet_send use this.
+ *
+ * This is a coarse first approximation for the tx_batching.
+ * If you come up with something better, please tell me. -taneli 
  */
 static void i2o_lan_batch_send(struct net_device *dev)
 {
@@ -848,20 +835,16 @@
 		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;
+	spin_unlock_irq(&priv->tx_lock);
 }
 
+#ifdef CONFIG_NET_FC
 /*
  * 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;
@@ -876,6 +859,16 @@
 	priv->tx_count++;
 	atomic_inc(&priv->tx_out);
 
+	/* 
+	 * If tx_batch_mode = 0x00 forced to immediate mode
+	 * If tx_batch_mode = 0x01 forced to batch mode
+	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
+	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
+	 *	If gap between two packets is > 2 ticks, switch to immediate
+	 */
+	if (priv->tx_batch_mode >> 1) // switch automatically
+		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
+
 	if (priv->tx_count == 1) {
 		m = I2O_POST_READ32(iop);
 		if (m == 0xFFFFFFFF) {
@@ -888,14 +881,15 @@
 		__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(1 << 30 | 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) {
+
+		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
 			priv->send_active = 1;
 			queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
 		}
@@ -915,7 +909,7 @@
 
 	/* If tx not in batch mode or frame is full, send immediatelly */
 
-	if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) {
+	if (!(priv->tx_batch_mode & 0x01) || 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);
@@ -930,6 +924,7 @@
 	spin_unlock_irq(&priv->tx_lock);
 	return 0;
 }
+#endif CONFIG_NET_FC
 
 /*
  * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
@@ -951,6 +946,16 @@
 	priv->tx_count++;
 	atomic_inc(&priv->tx_out);
 
+	/* 
+	 * If tx_batch_mode = 0x00 forced to immediate mode
+	 * If tx_batch_mode = 0x01 forced to batch mode
+	 * If tx_batch_mode = 0x10 switch automatically, current mode immediate
+	 * If tx_batch_mode = 0x11 switch automatically, current mode batch
+	 *	If gap between two packets is > 0 ticks, switch to immediate
+	 */
+	if (priv->tx_batch_mode >> 1) // switch automatically
+		priv->tx_batch_mode = tickssofar ? 0x02 : 0x03;
+
 	if (priv->tx_count == 1) {
 		m = I2O_POST_READ32(iop);
 		if (m == 0xFFFFFFFF) {
@@ -963,12 +968,14 @@
 		__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_send_context, msg+2); // InitiatorContext
-		__raw_writel(1 << 3, msg+3); 		 	     // TransmitControlWord
-
+		__raw_writel(1 << 30 | 1 << 3, msg+3); 		 	  // TransmitControlWord
+			// bit 30: reply as soon as transmission attempt is complete
+			// bit 3: Supress CRC generation
 		__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);
-		if (batching(priv, !tickssofar) && !priv->send_active) {
+
+		if ((priv->tx_batch_mode & 0x01) && !priv->send_active) {
 			priv->send_active = 1;
 			queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
 		}
@@ -984,9 +991,9 @@
 		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
 	}
 
-	/* If tx not in batch mode or frame is full, send immediatelly */
+	/* If tx is in immediate mode or frame is full, send now */
 
-	if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) {
+	if (!(priv->tx_batch_mode & 0x01) || 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);
@@ -1141,12 +1148,14 @@
 	u32 max_size_mc_table;
 	u32 mc_addr_group[64];
 
-// This isn't safe yet. Needs to be async.
+// This isn't safe yet in SMP. Needs to be async.
+// Seems to work in uniprocessor environment.
+
 return;
 
 //	read_lock_bh(&dev_mc_lock);
-//	spin_lock(&dev->xmit_lock);
-//	dev->xmit_lock_owner = smp_processor_id();
+	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 ) {
@@ -1212,15 +1221,13 @@
  *       Queue routine i2o_lan_set_mc_list() to be called later.
  *       Needs to be async.
  */
-
 static void i2o_lan_set_multicast_list(struct net_device *dev)
 {
-	if (!in_interrupt()) {
+	if (in_interrupt()) {
 		i2o_lan_set_mc_list_task.data = (void *)dev;
 		queue_task(&i2o_lan_set_mc_list_task, &tq_scheduler);
-	} else {
+	} else 
 		i2o_lan_set_mc_list(dev);
-	}
 }
 
 /*
@@ -1236,10 +1243,20 @@
 		 	     0x0000, 6, &max_pkt_size, 4) < 0)
 		return -EFAULT;
 
-	if (new_mtu < 68 || max_pkt_size < new_mtu)
+	if (new_mtu < 68 || new_mtu > 9000 || new_mtu > max_pkt_size)
 		return -EINVAL;
 
 	dev->mtu = new_mtu;
+
+	i2o_lan_suspend(dev);   	// to SUSPENDED state, return buckets
+
+	while (priv->i2o_fbl_tail >= 0) // free buffered buckets
+		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+
+	i2o_lan_reset(dev);		// to OPERATIONAL state
+	i2o_set_ddm_parameters(dev); 	// reset some parameters
+	i2o_lan_receive_post(dev); 	// post new buckets (new size)
+
 	return 0;
 }
 
@@ -1287,15 +1304,13 @@
 #ifdef CONFIG_FDDI
 	case I2O_LAN_FDDI:
 	{
-		int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local)
-			+ sizeof("fddi%d ");
+		int size = sizeof(struct net_device) + 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) {
 			printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n");
@@ -1335,7 +1350,7 @@
 	priv = (struct i2o_lan_local *)dev->priv;
 	priv->i2o_dev = i2o_dev;
 	priv->type_trans = type_trans;
-	priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12;
+	priv->sgl_max = (i2o_dev->controller->status_block->inbound_frame_size - 4) / 3;
 	atomic_set(&priv->buckets_out, 0);
 
 	/* Set default values for user configurable parameters */
@@ -1344,7 +1359,7 @@
 	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->tx_batch_mode   = tx_batch_mode & 0x03;
 	priv->i2o_event_mask  = i2o_event_mask;
 
 	priv->tx_lock	      = SPIN_LOCK_UNLOCKED;
@@ -1362,7 +1377,6 @@
 		kfree(dev);
 		return NULL;
 	}
-
 	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]);
@@ -1417,9 +1431,9 @@
 	struct net_device *dev;
 	int i;
 
-	printk(KERN_INFO "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 */
+	/* Module params are used as global defaults for private values */
 
 	if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT)
 		max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
@@ -1549,7 +1563,7 @@
 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");
+MODULE_PARM(tx_batch_mode, "0-2" "i");
+MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically");
 
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.3.99-pre6/linux/drivers/i2o/i2o_lan.h	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_lan.h	Wed May 10 16:56:43 2000
@@ -18,12 +18,12 @@
 
 /* Default values for tunable parameters first */
 
-#define I2O_LAN_MAX_BUCKETS_OUT 256
+#define I2O_LAN_MAX_BUCKETS_OUT 96
 #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 */
+#define I2O_LAN_TX_BATCH_MODE	2	/* 2=automatic, 1=on, 0=off */
+#define I2O_LAN_EVENT_MASK	0;	/* 0=None, 0xFFC00002=All */
 
 /* LAN types */
 #define I2O_LAN_ETHERNET	0x0030
@@ -126,6 +126,7 @@
 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 */
@@ -133,7 +134,7 @@
 	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 */
+	u32 m;				/* IOP address of the batch msg frame */
 
 	struct tq_struct i2o_batch_send_task;
 	int send_active;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.99-pre6/linux/drivers/i2o/i2o_pci.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/i2o/i2o_pci.c	Wed May 10 16:56:43 2000
@@ -6,6 +6,7 @@
  *	
  *	Written by Alan Cox, Building Number Three Ltd
  * 	Modified by Deepak Saxena <deepak@plexity.net>
+ * 	Modified by Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -53,10 +54,10 @@
 	iounmap(((u8 *)c->post_port)-0x40);
 
 #ifdef CONFIG_MTRR
-       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);
+	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
 }
 
@@ -178,21 +179,21 @@
 	 * Enable Write Combining MTRR for IOP's memory region
 	 */
 #ifdef CONFIG_MTRR
-       c->bus.pci.mtrr_reg0 =
-                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");
-       }
+	c->bus.pci.mtrr_reg1 = -1;
+	if(dev->vendor == PCI_VENDOR_ID_INTEL)
+	{
+	printk(KERN_INFO "I2O: 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
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.3.99-pre6/linux/drivers/ide/ide-cd.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/ide/ide-cd.c	Wed May 10 17:33:57 2000
@@ -282,9 +282,12 @@
  *			  - cdrom_read_capacity returns one frame too little.
  *			  - Fix real capacity reporting.
  *
+ * 4.58  May 1, 2000	- Clean up ACER50 stuff.
+ *			- Fix small problem with ide_cdrom_capacity
+ *
  *************************************************************************/
  
-#define IDECD_VERSION "4.57"
+#define IDECD_VERSION "4.58"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -1521,7 +1524,7 @@
 		memset(&pc, 0, sizeof(pc));
 		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-		pc.c[4] = (lockflag != 0);
+		pc.c[4] = lockflag ? 3 : 0;
 		stat = cdrom_queue_packet_command (drive, &pc);
 	}
 
@@ -1857,6 +1860,10 @@
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
 	cgc->stat = cdrom_queue_packet_command(drive, &pc);
+
+	/*
+	 * FIXME: copy sense, don't just assign pointer!!
+	 */
 	cgc->sense = pc.sense;
 
 	return cgc->stat;
@@ -2159,9 +2166,9 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
-	int minor = (drive->select.b.unit)<<PARTN_BITS;
+	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor | CD_PART_MASK);
+	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
 	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2195,22 +2202,23 @@
 	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_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;
 	struct cdrom_generic_command cgc;
-	int stat, attempts = 3;
+	int stat, attempts = 3, size = sizeof(*cap);
+
+	/*
+	 * ACER50 (and others?) require the full spec length mode sense
+	 * page capabilities size, but older drives break.
+	 */
+	if (drive->id) {
+		if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+		    !strcmp(drive->id->model, "WPI CDS-32X")))
+			size -= sizeof(cap->pad);
+	}
 
 	/* we have to cheat a little here. the packet will eventually
 	 * be queued with ide_cdrom_packet(), which extracts the
@@ -2220,7 +2228,7 @@
 	 */
 	cdi->handle = (ide_drive_t *) drive;
 	cdi->ops = &ide_cdrom_dops;
-	init_cdrom_command(&cgc, cap, sizeof(*cap), CGC_DATA_UNKNOWN);
+	init_cdrom_command(&cgc, cap, size, 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);
 		if (!stat)
@@ -2513,9 +2521,8 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_fops.check_media_change
-		(MKDEV (HWIF (drive)->major,
-			(drive->select.b.unit)<<PARTN_BITS));
+	return cdrom_fops.check_media_change(MKDEV (HWIF (drive)->major,
+			(drive->select.b.unit) << PARTN_BITS));
 }
 
 static
@@ -2545,8 +2552,7 @@
 {
 	unsigned capacity;
 
-	capacity = cdrom_read_capacity(drive, &capacity, NULL);
-	return capacity ? 0 : capacity * SECTORS_PER_FRAME;
+	return cdrom_read_capacity(drive, &capacity, NULL) ? 0 : capacity * SECTORS_PER_FRAME;
 }
 
 static
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- v2.3.99-pre6/linux/drivers/ide/ide-cd.h	Wed Apr 26 16:34:07 2000
+++ linux/drivers/ide/ide-cd.h	Thu May 11 11:28:50 2000
@@ -10,15 +10,6 @@
 #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. */
@@ -114,6 +105,7 @@
 	char *buffer;
 	int buflen;
 	int stat;
+	int quiet;
 	struct request_sense *sense;
 	unsigned char c[12];
 };
@@ -410,9 +402,7 @@
 	unsigned short buffer_size;
 	/* Current speed (in kB/s). */
 	unsigned short curspeed;
-#if !BROKEN_CAP_PAGE
 	char pad[4];
-#endif
 };
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ide/ide-cs.c linux/drivers/ide/ide-cs.c
--- v2.3.99-pre6/linux/drivers/ide/ide-cs.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/ide/ide-cs.c	Mon May  8 21:26:05 2000
@@ -183,7 +183,6 @@
 static void ide_detach(dev_link_t *link)
 {
     dev_link_t **linkp;
-    long flags;
     int ret;
 
     DEBUG(0, "ide_detach(0x%p)\n", link);
@@ -194,14 +193,7 @@
     if (*linkp == NULL)
 	return;
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-    
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	ide_release((u_long)link);
     
@@ -425,11 +417,8 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    link->release.expires = jiffies + HZ/20;
-	    link->state |= DEV_RELEASE_PENDING;
-	    add_timer(&link->release);
-	}
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.3.99-pre6/linux/drivers/ide/ide-tape.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/ide/ide-tape.c	Wed May  3 01:45:19 2000
@@ -5887,24 +5887,20 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idetape_driver = {
-	"ide-tape",		/* name */
-	IDETAPE_VERSION,	/* version */
-	ide_tape,		/* media */
-	1,			/* busy */
-	1,			/* supports_dma */
-	1,			/* supports_dsc_overlap */
-	idetape_cleanup,	/* cleanup */
-	idetape_do_request,	/* do_request */
-	idetape_end_request,	/* end_request */
-	idetape_blkdev_ioctl,	/* ioctl */
-	idetape_blkdev_open,	/* open */
-	idetape_blkdev_release,	/* release */
-	NULL,			/* media_change */
-	NULL,			/* revalidate */
-	idetape_pre_reset,	/* pre_reset */
-	NULL,			/* capacity */
-	NULL,			/* special */
-	idetape_proc		/* proc */
+	name:		"ide-tape",
+	version:	IDETAPE_VERSION,
+	media:		ide_tape,
+	busy:		1,
+	supports_dma:	1,
+	supports_dsc_overlap: 1,
+	cleanup:	idetape_cleanup,
+	do_request:	idetape_do_request,
+	end_request:	idetape_end_request,
+	ioctl:		idetape_blkdev_ioctl,
+	open:		idetape_blkdev_open,
+	release:	idetape_blkdev_release,
+	pre_reset:	idetape_pre_reset,
+	proc:		idetape_proc,
 };
 
 int idetape_init (void);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.3.99-pre6/linux/drivers/ide/ide.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/ide/ide.c	Tue May  2 17:38:02 2000
@@ -1256,7 +1256,7 @@
 				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
 					sleep = jiffies + WAIT_MIN_SLEEP;
 #if 1
-				if (hwgroup->timer.next || hwgroup->timer.prev)
+				if (timer_pending(&hwgroup->timer))
 					printk("ide_set_handler: timer already active\n");
 #endif
 				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.3.99-pre6/linux/drivers/ieee1394/ohci1394.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ieee1394/ohci1394.c	Wed May  3 01:45:18 2000
@@ -1386,6 +1386,7 @@
 	}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	/* XXX check return value */
 	pci_enable_device(dev);
 #endif
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c
--- v2.3.99-pre6/linux/drivers/isdn/act2000/module.c	Thu Nov 11 20:11:35 1999
+++ linux/drivers/isdn/act2000/module.c	Fri Apr 28 22:50:13 2000
@@ -279,9 +279,7 @@
 	act2000_receive(card);
         save_flags(flags);
         cli();
-        del_timer(&card->ptimer);
-        card->ptimer.expires = jiffies + 3;
-        add_timer(&card->ptimer);
+        mod_timer(&card->ptimer, jiffies+3);
         restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.3.99-pre6/linux/drivers/isdn/avmb1/t1pci.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/isdn/avmb1/t1pci.c	Fri Apr 28 23:00:05 2000
@@ -305,9 +305,11 @@
 	while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
 		struct capicardparams param;
 
-		param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+		param.port = pci_resource_start (dev, 1);
 		param.irq = dev->irq;
-		param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+		param.membase = pci_resource_start (dev, 0);
+
+		pci_enable_device (dev); /* XXX check return */
 
 		printk(KERN_INFO
 			"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- v2.3.99-pre6/linux/drivers/isdn/hisax/fsm.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/hisax/fsm.c	Thu May  4 11:20:50 2000
@@ -156,7 +156,7 @@
 			(long) ft, millisec, where);
 #endif
 
-	if (ft->tl.next || ft->tl.prev) {
+	if (timer_pending(&ft->tl)) {
 		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
 		ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
 		return -1;
@@ -180,7 +180,7 @@
 			(long) ft, millisec, where);
 #endif
 
-	if (ft->tl.next || ft->tl.prev)
+	if (timer_pending(&ft->tl))
 		del_timer(&ft->tl);
 	init_timer(&ft->tl);
 	ft->event = event;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- v2.3.99-pre6/linux/drivers/isdn/hisax/isdnl3.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/isdn/hisax/isdnl3.c	Thu May  4 11:21:18 2000
@@ -238,7 +238,7 @@
 L3AddTimer(struct L3Timer *t,
 	   int millisec, int event)
 {
-	if (t->tl.next || t->tl.prev) {
+	if (timer_pending(&t->tl)) {
 		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
 		return -1;
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c
--- v2.3.99-pre6/linux/drivers/isdn/hisax/saphir.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/hisax/saphir.c	Fri Apr 28 22:50:13 2000
@@ -173,11 +173,9 @@
 		goto Start_ISAC;
 	}
 	/* Watchdog */
-	if (cs->hw.saphir.timer.function) {
-		del_timer(&cs->hw.saphir.timer);
-		cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-		add_timer(&cs->hw.saphir.timer);
-	} else
+	if (cs->hw.saphir.timer.function) 
+		mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
+	else
 		printk(KERN_WARNING "saphir: Spurious timer!\n");
 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
@@ -192,9 +190,7 @@
 {
         /* 5 sec WatchDog, so read at least every 4 sec */
 	cs->readisac(cs, ISAC_RBCH);
-	del_timer(&cs->hw.saphir.timer);
-	cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-	add_timer(&cs->hw.saphir.timer);
+	mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
 }
 
 void
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- v2.3.99-pre6/linux/drivers/isdn/hysdn/hysdn_net.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Thu May  4 11:31:20 2000
@@ -323,7 +323,6 @@
 	dev->base_addr = card->iobase;	/* IO address */
 	dev->irq = card->irq;	/* irq */
 	dev->init = net_init;	/* the init function of the device */
-	dev->name = ((struct net_local *) dev)->dev_name;	/* device name */
 	if ((i = register_netdev(dev))) {
 		printk(KERN_WARNING "HYSDN: unable to create network device\n");
 		kfree(dev);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.3.99-pre6/linux/drivers/isdn/icn/icn.c	Thu Nov 11 20:11:38 1999
+++ linux/drivers/isdn/icn/icn.c	Fri Apr 28 22:50:13 2000
@@ -602,9 +602,7 @@
 		/* schedule b-channel polling again */
 		save_flags(flags);
 		cli();
-		del_timer(&card->rb_timer);
-		card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-		add_timer(&card->rb_timer);
+		mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD);
 		card->flags |= ICN_FLAGS_RBTIMER;
 		restore_flags(flags);
 	} else
@@ -905,9 +903,7 @@
 	/* schedule again */
 	save_flags(flags);
 	cli();
-	del_timer(&card->st_timer);
-	card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-	add_timer(&card->st_timer);
+	mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.3.99-pre6/linux/drivers/isdn/isdn_common.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/isdn/isdn_common.c	Fri Apr 28 22:50:13 2000
@@ -685,9 +685,7 @@
 
 		save_flags(flags);
 		cli();
-		del_timer(&dev->timer);
-		dev->timer.expires = jiffies + ISDN_TIMER_RES;
-		add_timer(&dev->timer);
+		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
 		restore_flags(flags);
 	}
 }
@@ -708,11 +706,8 @@
 		dev->tflags |= tf;
 	else
 		dev->tflags &= ~tf;
-	if (dev->tflags) {
-		if (!del_timer(&dev->timer))	/* del_timer is 1, when active */
-			dev->timer.expires = jiffies + ISDN_TIMER_RES;
-		add_timer(&dev->timer);
-	}
+	if (dev->tflags)
+		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.3.99-pre6/linux/drivers/isdn/isdn_net.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/isdn/isdn_net.c	Thu May  4 11:31:21 2000
@@ -2799,7 +2799,7 @@
 		strcpy(netdev->local->name, "         ");
 	else
 		strcpy(netdev->local->name, name);
-	netdev->dev.name = netdev->local->name;
+	strcpy(netdev->dev.name, netdev->local->name);
 	netdev->dev.priv = netdev->local;
 	netdev->dev.init = isdn_net_init;
 	netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/isdn/sc/timer.c linux/drivers/isdn/sc/timer.c
--- v2.3.99-pre6/linux/drivers/isdn/sc/timer.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/sc/timer.c	Fri Apr 28 22:50:13 2000
@@ -91,9 +91,7 @@
 	else  {
 		pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
 			adapter[card]->devicename, CHECKRESET_TIME);
-		del_timer(&adapter[card]->reset_timer);
-		adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
-		add_timer(&adapter[card]->reset_timer);
+		mod_timer(&adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
 	}
 	restore_flags(flags);
 		
@@ -138,9 +136,7 @@
 	/* Reinitialize the timer */
 	save_flags(flags);
 	cli();
-	del_timer(&adapter[card]->stat_timer);
-	adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
-	add_timer(&adapter[card]->stat_timer);
+	mod_timer(&adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
 	restore_flags(flags);
 
 	/* Send a new cePhyStatus message */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.3.99-pre6/linux/drivers/macintosh/mediabay.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/macintosh/mediabay.c	Fri May  5 12:22:54 2000
@@ -252,7 +252,7 @@
 		MBDBG("mediabay%d: powering up\n", which);
 	} else {
 		feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable);
-		feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_enable);
+		feature_clear(mb->dev_node, FEATURE_IDE1_enable);
 		feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable);
 		feature_clear(mb->dev_node, FEATURE_SWIM3_enable);
 		feature_clear(mb->dev_node, FEATURE_Mediabay_power);
@@ -271,9 +271,9 @@
 	
 	switch (id) {
 	case MB_CD:
-		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+		feature_set(bay->dev_node, FEATURE_IDE1_enable);
 		udelay(10);
-		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_reset);
+		feature_set(bay->dev_node, FEATURE_IDE1_reset);
 		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
 		break;
 	case MB_FD:
@@ -397,7 +397,7 @@
 	    	}
 #ifdef CONFIG_BLK_DEV_IDE
 		MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
-	    	feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_reset);
+	    	feature_clear(bay->dev_node, FEATURE_IDE1_reset);
 	    	bay->timer = MS_TO_HZ(MB_IDE_WAIT);
 	    	bay->state = mb_ide_resetting;
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.3.99-pre6/linux/drivers/net/3c501.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/net/3c501.c	Wed May  3 01:45:19 2000
@@ -243,7 +243,7 @@
 	if (base_addr > 0x1ff)	/* Check a single specified location. */
 		return el1_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
-		return ENXIO;
+		return -ENXIO;
 
 	for (i = 0; netcard_portlist[i]; i++)
 	{
@@ -254,7 +254,7 @@
 			return 0;
 	}
 
-	return ENODEV;
+	return -ENODEV;
 }
 #endif
 
@@ -303,13 +303,14 @@
 		mname = "NP943";
     	}
     	else
-		return ENODEV;
+		return -ENODEV;
 
 	/*
 	 *	Grab the region so we can find the another board if autoIRQ fails.
 	 */
 
-	request_region(ioaddr, EL1_IO_EXTENT,"3c501");
+	if (!request_region(ioaddr, EL1_IO_EXTENT,"3c501"))
+		return -ENODEV;
 
 	/*
 	 *	We auto-IRQ by shutting off the interrupt line and letting it float
@@ -331,7 +332,7 @@
 		{
 			printk("%s probe at %#x failed to detect IRQ line.\n",
 				mname, ioaddr);
-			return EAGAIN;
+			return -EAGAIN;
 		}
 	}
 
@@ -406,11 +407,15 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned long flags;
 
+	MOD_INC_USE_COUNT;
+
 	if (el_debug > 2)
 		printk("%s: Doing el_open()...", dev->name);
 
-	if (request_irq(dev->irq, &el_interrupt, 0, "3c501", dev))
+	if (request_irq(dev->irq, &el_interrupt, 0, "3c501", dev)) {
+		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
+	}
 
 	spin_lock_irqsave(&lp->lock, flags);
 	el_reset(dev);
@@ -419,7 +424,6 @@
 	lp->txing = 0;		/* Board in RX mode */
 	outb(AX_RX, AX_CMD);	/* Aux control, irq and receive enabled */
 	netif_start_queue(dev);
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -917,11 +921,9 @@
 
 #ifdef MODULE
 
-static char devicename[9] = { 0, };
-
 static struct net_device dev_3c501 =
 {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	"", /* device name is inserted by linux/drivers/net/net_init.c */
 	0, 0, 0, 0,
 	0x280, 5,
 	0, 0, 0, NULL, el1_probe
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.3.99-pre6/linux/drivers/net/3c503.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/net/3c503.c	Tue May  2 12:40:58 2000
@@ -621,12 +621,10 @@
 }
 #ifdef MODULE
 #define MAX_EL2_CARDS	4	/* Max number of EL2 cards per module */
-#define NAMELEN 	8	/* #of chars for storing dev->name */
 
-static char namelist[NAMELEN * MAX_EL2_CARDS] = { 0, };
 static struct net_device dev_el2[MAX_EL2_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -649,7 +647,6 @@
 
 	for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
 		struct net_device *dev = &dev_el2[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_end = xcvr[this_dev];	/* low 4bits = xcvr sel. */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.3.99-pre6/linux/drivers/net/3c505.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/net/3c505.c	Tue May  2 12:40:58 2000
@@ -1607,11 +1607,9 @@
 }
 
 #ifdef MODULE
-#define NAMELEN 9
-static char devicename[ELP_MAX_CARDS][NAMELEN] = {{0,}};
 static struct net_device dev_3c505[ELP_MAX_CARDS] =
 {
-	{ NULL,		/* device name is inserted by net_init.c */
+	{ "",		/* device name is inserted by net_init.c */
 	0, 0, 0, 0,
 	0, 0,
 	0, 0, 0, NULL, elplus_probe},
@@ -1630,7 +1628,6 @@
 
 	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
 		struct net_device *dev = &dev_3c505[this_dev];
-		dev->name = devicename[this_dev];
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		if (dma[this_dev]) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.3.99-pre6/linux/drivers/net/3c507.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/3c507.c	Tue May  2 12:40:58 2000
@@ -860,9 +860,8 @@
 	lp->rx_tail = rx_tail;
 }
 #ifdef MODULE
-static char devicename[9] = { 0, };
 static struct net_device dev_3c507 = {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	"", /* device name is inserted by linux/drivers/net/net_init.c */
 	0, 0, 0, 0,
 	0, 0,
 	0, 0, 0, NULL, el16_probe
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.3.99-pre6/linux/drivers/net/3c515.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/3c515.c	Tue May  2 12:40:59 2000
@@ -300,7 +300,6 @@
 };
 
 struct corkscrew_private {
-	char devname[8];	/* "ethN" string, also for kernel debug. */
 	const char *product_name;
 	struct net_device *next_module;
 	/* The Rx and Tx rings are here to keep them quad-word-aligned. */
@@ -564,7 +563,6 @@
 	dev->priv =
 	    (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15);
 	vp = (struct corkscrew_private *) dev->priv;
-	dev->name = vp->devname;	/* An empty string. */
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->dma =
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.3.99-pre6/linux/drivers/net/3c523.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/net/3c523.c	Tue May  2 12:40:59 2000
@@ -1207,15 +1207,11 @@
 
 /* Increase if needed ;) */
 #define MAX_3C523_CARDS 4
-/* I'm not sure where this magic 9 comes from */
-#define NAMELEN 9
-
-static char devicenames[NAMELEN * MAX_3C523_CARDS] = {0,};
 
 static struct net_device dev_elmc[MAX_3C523_CARDS] =
 {	
 	{
-	NULL /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
+	"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
 	},
 };
 
@@ -1232,7 +1228,6 @@
 	for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) 
 		{
 		struct net_device *dev = &dev_elmc[this_dev];
-		dev->name=devicenames+(NAMELEN*this_dev);
 		dev->irq=irq[this_dev];
 		dev->base_addr=io[this_dev];
 		dev->init=elmc_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c527.c linux/drivers/net/3c527.c
--- v2.3.99-pre6/linux/drivers/net/3c527.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/3c527.c	Tue May  2 12:40:59 2000
@@ -1457,9 +1457,8 @@
 
 #ifdef MODULE
 
-static char devicename[9] = { 0, };
 static struct net_device this_device = {
-	devicename, /* will be inserted by linux/drivers/net/mc32_init.c */
+	"", /* will be inserted by linux/drivers/net/mc32_init.c */
 	0, 0, 0, 0,
 	0, 0,  /* I/O address, IRQ */
 	0, 0, 0, NULL, mc32_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.99-pre6/linux/drivers/net/3c59x.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/3c59x.c	Fri May  5 12:37:52 2000
@@ -15,13 +15,14 @@
 
 	Linux Kernel Additions:
 	
+ 	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
 	LK1.1.2 (March 19, 2000)
 	* New PCI interface (jgarzik)
 
-*/
-
-/*
-    22Apr00, Andrew Morton <andrewm@uow.edu.au>
+    LK1.1.3 25 April 2000, 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
@@ -43,7 +44,25 @@
     - Handle resource allocation failures.
     - Fix 3CCFE575CT LED polarity
     - Make tx_interrupt_mitigation the default
+
+    LK1.1.4 25 April 2000, Andrew Morton <andrewm@uow.edu.au>    
     - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
+    - Put vortex_info_tbl into __devinitdata
+    - In the vortex_error StatsFull HACK, disable stats in vp->intr_enable as well
+      as in the hardware.
+    - Increased the loop counter in wait_for_completion from 2,000 to 4,000.
+
+    LK1.1.5 28 April 2000, andrewm
+    - Added powerpc defines
+    - Some extra diagnostics
+    - In vortex_error(), reset the Tx on maxCollisions.  Otherwise most
+      chips usually get a Tx timeout.
+    - Added extra_reset module parm
+    - Replaced some inline timer manip with mod_timer
+      (Franois romieu <Francois.Romieu@nic.fr>)
+    - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway
+      (this came across from 3c575_cb).
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
 */
 
@@ -56,9 +75,6 @@
  * 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.
    Setting to > 1512 effectively disables this feature. */
@@ -67,10 +83,15 @@
 static const int mtu = 1500;
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 32;
+/* Give the NIC an extra reset at the end of vortex_up() */
+static int extra_reset = 0;
 
 /* 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.
+ * AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts
+ * in a heavily loaded (collision-prone) 10BaseT LAN.  Should be OK with
+ * switched Ethernet.
  */
 #define tx_interrupt_mitigation 1
 
@@ -96,8 +117,8 @@
 #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 file with the correct options!
+#error See the last lines of the source file.
 #error You must compile this driver with "-O".
 #endif
 
@@ -120,6 +141,12 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* John Daniel <jdaniel@etresoft.com> said these work... */
+#ifdef __powerpc__
+#define outsl outsl_ns
+#define insl insl_ns
+#endif
+
 /* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
    This is only in the support-all-kernels source code. */
 
@@ -127,6 +154,9 @@
 
 #include <linux/delay.h>
 
+static char version[] __devinitdata =
+"3c59x.c:v0.99L+LK1.1.5  30 Apr 2000  Donald Becker and others  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html " "$Revision: 1.78 $\n";
+
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
 MODULE_PARM(debug, "i");
@@ -134,6 +164,7 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(extra_reset, "i");
 MODULE_PARM(compaq_ioaddr, "i");
 MODULE_PARM(compaq_irq, "i");
 MODULE_PARM(compaq_device_id, "i");
@@ -291,7 +322,7 @@
 	int flags;
 	int drv_flags;
 	int io_size;
-} vortex_info_tbl[] = {
+} vortex_info_tbl[] __devinitdata = {
 	{"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 */
@@ -551,8 +582,7 @@
 
 	/* PCI configuration space information. */
 	struct pci_dev *pdev;
-	char *cb_fn_base;			/* CardBus function status addr space. */
-	int chip_id;
+	char *cb_fn_base;					/* CardBus function status addr space. */
 
 	/* The remainder are related to chip state, mostly media selection. */
 	struct timer_list timer;			/* Media selection timer. */
@@ -564,7 +594,9 @@
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
 		hw_csums:1,						/* Has hardware checksums. */
 		tx_full:1,
+		has_nway:1,
 		open:1;
+	int tx_reset_resume;				/* Flag to retart timer after vortex_error handling */
 	u16 status_enable;
 	u16 intr_enable;
 	u16 available_media;				/* From Wn3_Options. */
@@ -573,6 +605,7 @@
 	unsigned char phys[2];				/* MII device addresses. */
 	u16 deferred;						/* Resend these interrupts when we
 										 * bale from the ISR */
+	u16 io_size;						/* Size of PCI region (for release_region) */
 	spinlock_t lock;
 };
 
@@ -620,6 +653,7 @@
 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 dump_tx_ring(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);
@@ -775,13 +809,15 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->mtu = mtu;
+	vp->has_nway = (vortex_info_tbl[chip_idx].drv_flags & HAS_NWAY) ? 1 : 0;
+	vp->io_size = vortex_info_tbl[chip_idx].io_size;
 
 	/* 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 */
@@ -795,7 +831,6 @@
 
 		/* 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;
 		}
@@ -806,7 +841,6 @@
 	}
 
 	vp->lock = SPIN_LOCK_UNLOCKED;
-	vp->chip_id = chip_idx;
 	vp->pdev = pdev;
 
 	/* Makes sure rings are at least 16 byte aligned. */
@@ -898,15 +932,15 @@
 			   dev->irq);
 #endif
 
-	if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+	if (pdev && vortex_info_tbl[chip_idx].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);
-#if 0 /* AKPM */
-		if (vortex_pci_tbl[vp->chip_id].device != 0x5257) {
+#if 1 /* AKPM: the 575_cb and 905B LEDs seem OK without this */
+		if (vortex_pci_tbl[chip_idx].device != 0x5257) {
 			EL3WINDOW(2);
 			outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
 		}
@@ -925,7 +959,7 @@
 	}
 
 	{
-		static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		union wn3_config config;
 		EL3WINDOW(3);
 		vp->available_media = inw(ioaddr + Wn3_Options);
@@ -1010,6 +1044,7 @@
 free_region:
 	release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
 free_dev:
+	unregister_netdev(dev);
 	kfree (dev);
 	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
 out:
@@ -1018,7 +1053,7 @@
 
 static void wait_for_completion(struct net_device *dev, int cmd)
 {
-	int i = 2000;
+	int i = 4000;
 
 	outw(cmd, dev->base_addr + EL3_CMD);
 	while (--i > 0)
@@ -1054,7 +1089,7 @@
 				   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) {
+		if (vp->has_nway) {
 			printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name);
 			dev->if_port = XCVR_NWAY;
 		} else {
@@ -1062,7 +1097,7 @@
 			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",
+			printk(KERN_INFO "%s: first available media type: %s\n",
 					dev->name,
 					media_tbl[dev->if_port].name);
 		}
@@ -1084,7 +1119,7 @@
 
 	vp->full_duplex = vp->force_fd;
 	config.u.xcvr = dev->if_port;
-	if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+//AKPM	if (!vp->has_nway)
 	{
 		if (vortex_debug > 6)
 			printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n",
@@ -1136,6 +1171,7 @@
 		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... */
@@ -1180,7 +1216,7 @@
 		/* 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);
+		outl(vp->rx_ring_dma, ioaddr + UpListPtr);
 	}
 	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
 		dev->hard_start_xmit = &boomerang_start_xmit;
@@ -1218,9 +1254,16 @@
 	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
 		writel(0x8000, vp->cb_fn_base + 4);
 
-	/* AKPM: unjam the 3CCFE575CT */
-	wait_for_completion(dev, TxReset);
-	outw(TxEnable, ioaddr + EL3_CMD);
+	if (extra_reset)
+	{
+		/* AKPM: unjam the 3CCFE575CT */
+		wait_for_completion(dev, TxReset);
+		if (vp->full_bus_master_tx) {
+			outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+			outw(DownUnstall, ioaddr + EL3_CMD);
+		}
+		outw(TxEnable, ioaddr + EL3_CMD);
+	}
 }
 
 static int
@@ -1244,7 +1287,7 @@
 			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].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);
@@ -1253,10 +1296,10 @@
 				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));
+			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(virt_to_bus(&vp->rx_ring[0]));
+		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
 	}
 
 	vortex_up(dev);
@@ -1294,7 +1337,7 @@
 				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 has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
 		break;
 	case XCVR_MII: case XCVR_NWAY:
@@ -1323,6 +1366,9 @@
 						outb((vp->full_duplex ? 0x20 : 0) |
 							(dev->mtu > 1500 ? 0x40 : 0),
 							ioaddr + Wn3_MAC_Ctrl);
+						if (vortex_debug > 1)
+							printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n");
+						/* AKPM: bug: should reset Tx and Rx after setting Duplex.  Page 180 */
 					}
 					next_tick = 60*HZ;
 				}
@@ -1365,6 +1411,9 @@
 
 		outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
 			 ioaddr + EL3_CMD);
+		if (vortex_debug > 1)
+			printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config.i);
+		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
 	}
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
@@ -1411,23 +1460,8 @@
 		}
 	}
 
-	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));
-			}
-		}
-	}
+	if (vortex_debug > 1)
+		dump_tx_ring(dev);
 
 	wait_for_completion(dev, TxReset);
 
@@ -1441,7 +1475,7 @@
 				 ioaddr + DownListPtr);
 		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
 			vp->tx_full = 0;
-			netif_start_queue (dev);
+			netif_wake_queue (dev);
 		}
 		if (vp->tx_full)
 			netif_stop_queue (dev);
@@ -1468,25 +1502,30 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
+	unsigned char tx_status = 0;
 
-	if (vortex_debug > 2)
+	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);
+		tx_status = inb(ioaddr + TxStatus);
 		/* Presumably a tx-timeout. We must merely re-enable. */
 		if (vortex_debug > 2
-			|| (tx_status != 0x88 && vortex_debug > 0))
+			|| (tx_status != 0x88 && vortex_debug > 0)) {
 			printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
 				   dev->name, tx_status);
+			dump_tx_ring(dev);
+		}
 		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)
+		if (tx_status & 0x38)	/* AKPM: tx reset after 16 collisions, despite what the manual says */
 			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);
@@ -1504,6 +1543,7 @@
 				   "stats as an interrupt source.\n", dev->name);
 			EL3WINDOW(5);
 			outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+			vp->intr_enable &= ~StatsFull;
 			EL3WINDOW(7);
 			DoneDidThat++;
 		}
@@ -1534,11 +1574,41 @@
 			outw(AckIntr | HostError, ioaddr + EL3_CMD);
 		}
 	}
+
+	/*
+	 * Black magic.  If we're resetting the transmitter,  remember the current downlist
+	 * pointer and restore it afterwards.  We can't usr cur_tx because that could
+	 * lag the actual hardware index.
+	 */
 	if (do_tx_reset) {
-		wait_for_completion(dev, TxReset);
-		outw(TxEnable, ioaddr + EL3_CMD);
-	}
+		if (vp->full_bus_master_tx) {
+			unsigned long old_down_list_ptr;
 
+			wait_for_completion(dev, DownStall);
+			old_down_list_ptr = inl(ioaddr + DownListPtr);
+			wait_for_completion(dev, TxReset);
+			outw(TxEnable, ioaddr + EL3_CMD);
+
+			/* Restart DMA if necessary */
+			outl(old_down_list_ptr, ioaddr + DownListPtr);
+			if (vortex_debug > 2)
+					printk(KERN_DEBUG "reset DMA to 0x%08x\n", inl(ioaddr + DownListPtr));
+			outw(DownUnstall, ioaddr + EL3_CMD);
+
+			/*
+			 * Here we make a single attempt to prevent a timeout by
+			 * restarting the timer if we think that the ISR has a good
+			 * chance of unjamming things.
+			 */
+			if (vp->tx_reset_resume == 0 && vp->tx_full) {
+				vp->tx_reset_resume = 1;
+				dev->trans_start = jiffies;
+			}
+		} else {
+			wait_for_completion(dev, TxReset);
+			outw(TxEnable, ioaddr + EL3_CMD);
+		}
+	}
 }
 
 static int
@@ -1547,8 +1617,6 @@
 	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) {
@@ -1559,16 +1627,18 @@
 		outw(len, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
 		outw(StartDMADown, ioaddr + EL3_CMD);
-		/* dev->tbusy will be cleared at the DMADone interrupt. */
+		/* netif_wake_queue() will be called 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
+			netif_start_queue (dev);	/* AKPM: redundant? */
+		} else {
 			/* Interrupt us when the FIFO has room for max-sized packet. */
+			netif_stop_queue(dev);
 			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+		}
 	}
 
 	dev->trans_start = jiffies;
@@ -1601,57 +1671,53 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
+	/* 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 > 6)
 		printk(KERN_DEBUG "boomerang_start_xmit()\n");
 
-	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;
-
-		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(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
-		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(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++;
-		}
-
-		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 (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(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
+	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(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++;
+	}
+
+	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);
+		prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
 #endif
-			netif_start_queue (dev);
-		}
-		outw(DownUnstall, ioaddr + EL3_CMD);
-		spin_unlock_irqrestore(&vp->lock, flags);
-		dev->trans_start = jiffies;
-		return 0;
+		/* netif_start_queue (dev); */		/* AKPM: redundant? */
 	}
+	outw(DownUnstall, ioaddr + EL3_CMD);
+	vp->tx_reset_resume = 0;
+	spin_unlock_irqrestore(&vp->lock, flags);
+	dev->trans_start = jiffies;
+	return 0;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
@@ -1667,17 +1733,16 @@
 	struct net_device *dev = dev_id;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr;
-	int latency, status;
+	int 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);
+		printk("vortex_interrupt(). status=0x%4x\n", status);
 
 	if (status & IntReq) {
 		status |= vp->deferred;
@@ -1689,7 +1754,7 @@
 
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
-			   dev->name, status, latency);
+			   dev->name, status, inb(ioaddr + Timer));
 	do {
 		if (vortex_debug > 5)
 				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
@@ -1709,12 +1774,17 @@
 			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 */
+				dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */
 				if (inw(ioaddr + TxFree) > 1536) {
-					netif_wake_queue (dev);
+					/*
+					 * AKPM: FIXME: I don't think we need this.  If the queue was stopped due to
+					 * insufficient FIFO room, the TxAvailable test will succeed and call
+					 * netif_wake_queue()
+					 */
+					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 */
+					netif_stop_queue(dev);		/* AKPM: This is new */
 				}
 			}
 		}
@@ -1736,9 +1806,7 @@
 				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);
+			mod_timer(&vp->timer, jiffies + 1*HZ);
 			break;
 		}
 		/* Acknowledge the IRQ. */
@@ -1765,33 +1833,31 @@
 	struct net_device *dev = dev_id;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr;
-	int latency, status;
+	int 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 (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 (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
-			   dev->name, status, latency);
+			   dev->name, status, inb(ioaddr + Timer));
 	do {
 		if (vortex_debug > 5)
 				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
@@ -1837,11 +1903,8 @@
 			netif_stop_queue (dev);
 
 		/* Check for all uncommon interrupts at once. */
-		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
-			if (status == 0xffff)
-				break;
+		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
 			vortex_error(dev, status);
-		}
 
 		if (--work_done < 0) {
 			printk(KERN_WARNING "%s: Too much work in interrupt, status "
@@ -1854,9 +1917,7 @@
 				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);
+			mod_timer(&vp->timer, jiffies + 1*HZ);
 			break;
 		}
 		/* Acknowledge the IRQ. */
@@ -1952,9 +2013,8 @@
 	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG "boomerang_rx(): status %4.4x, rx_status "
-			   "%4.4x.\n",
-			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+		printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", inw(ioaddr+EL3_STATUS));
+
 	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
 		if (--rx_work_limit < 0)
 			break;
@@ -2112,6 +2172,38 @@
 	return 0;
 }
 
+static void
+dump_tx_ring(struct net_device *dev)
+{
+	if (vortex_debug > 0) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		long ioaddr = dev->base_addr;
+		
+		if (vp->full_bus_master_tx) {
+			int i;
+			int stalled = inl(ioaddr + PktStatus) & 0x04;	/* Possible racy. But it's only debug stuff */
+
+			wait_for_completion(dev, DownStall);
+			printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d(%d) "
+					"current %d(%d).\n",
+					vp->full_bus_master_tx, vp->tx_full,
+					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
+					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
+			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 (!stalled)
+				outw(DownUnstall, ioaddr + EL3_CMD);
+		}
+	}
+}
+
 static struct net_device_stats *vortex_get_stats(struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
@@ -2348,15 +2440,21 @@
 	struct net_device *dev = pdev->driver_data;
 	struct vortex_private *vp;
 
-	if (!dev)
-		return;
+	if (!dev) {
+		printk("vortex_remove_one called for EISA device!\n");
+		BUG();
+	}
 
 	vp = (void *)(dev->priv);
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	/* AKPM: FIXME: we should have
+	 *	if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
+	 * here
+	 */
 	unregister_netdev(dev);
 	outw(TotalReset, dev->base_addr + EL3_CMD);
-	release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+	release_region(dev->base_addr, vp->io_size);
 	kfree(dev);
 }
 
@@ -2379,8 +2477,6 @@
 {
 	int rc;
 	
-	MOD_INC_USE_COUNT;
-
 	rc = pci_module_init (&vortex_driver);
 	if (rc < 0)
 		goto out;
@@ -2396,7 +2492,6 @@
 		vortex_have_eisa = 1;
 
 out:
-	MOD_DEC_USE_COUNT;
 	return rc;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.3.99-pre6/linux/drivers/net/8139too.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/8139too.c	Thu Apr 27 15:43:19 2000
@@ -84,10 +84,11 @@
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.4"
+#define RTL8139_VERSION "0.9.4.1"
 #define RTL8139_MODULE_NAME "8139too"
 #define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX RTL8139_MODULE_NAME ": "
@@ -122,6 +123,9 @@
 
 
 /* A few user-configurable values. */
+/* media options */
+static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
@@ -132,17 +136,24 @@
 /* Size of the in-memory receive ring. */
 #define RX_BUF_LEN_IDX	2	/* 0==8K, 1==16K, 2==32K, 3==64K */
 #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+#define RX_BUF_PAD 16
+#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC	4
+
 /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
 #define TX_BUF_SIZE	1536
+#define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
 
 /* PCI Tuning Parameters
    Threshold is bytes transferred to chip before transmission starts. */
 #define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
 
-/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
 #define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST	4	/* Calculate as 16<<val. */
+#define RX_DMA_BURST	4	/* Maximum PCI burst, '7' is unlimited */
+#define TX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 */
 
 
 /* Operational parameters that usually are not changed. */
@@ -156,7 +167,7 @@
 };
 
 #define RTL_MIN_IO_SIZE 0x80
-#define RTL8139B_IO_SIZE 0xFF
+#define RTL8139B_IO_SIZE 256
 
 #define RTL8139_CAPS	HAS_CHIP_XCVR|HAS_LNK_CHNG
 
@@ -167,13 +178,13 @@
 	/*MPX5030,*/
 	DELTA8139,
 	ADDTRON8139,
-} chip_t;
+} board_t;
 
 
-/* indexed by chip_t, above */
+/* indexed by board_t, above */
 static struct {
 	const char *name;
-} chip_info[] __devinitdata = {
+} board_info[] __devinitdata = {
 	{ "RealTek RTL8139 Fast Ethernet" },
 	{ "RealTek RTL8139B PCI/CardBus" },
 	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
@@ -196,7 +207,6 @@
 
 
 /* The rest of these values should never change. */
-#define NUM_TX_DESC	4	/* Number of Tx descriptor registers. */
 
 /* Symbolic offsets to registers. */
 enum RTL8139_registers {
@@ -220,8 +230,8 @@
 	Config0 = 0x51,
 	Config1 = 0x52,
 	FlashReg = 0x54,
-	GPPinData = 0x58,
-	GPPinDir = 0x59,
+	MediaStatus = 0x58,
+	Config3 = 0x59,
 	Config4 = 0x5A,		/* absent on RTL-8139A */
 	HltClk = 0x5B,
 	MultiIntr = 0x5C,
@@ -236,6 +246,13 @@
 	CSCR = 0x74,		/* Chip Status and Configuration Register. */
 	PARA78 = 0x78,
 	PARA7c = 0x7c,		/* Magic transceiver parameter register. */
+	Config5 = 0xD8,		/* absent on RTL-8139A */
+};
+
+enum ClearBitMasks {
+	MultiIntrClear = 0xF000,
+	ChipCmdClear = 0xE2,
+	Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
 };
 
 enum ChipCmdBits {
@@ -300,6 +317,19 @@
 };
 
 enum RxConfigBits {
+	/* Early Rx threshold, none or X/16 */
+	RxCfgEarlyRxNone = 0,
+	RxCfgEarlyRxShift = 24,
+	
+	/* rx fifo threshold */
+	RxCfgFIFOShift = 13,
+	RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+	/* Max DMA burst */
+	RxCfgDMAShift = 8,
+	RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+	/* rx ring buffer length */
 	RxCfgRcv8K = 0,
 	RxCfgRcv16K = (1 << 11),
 	RxCfgRcv32K = (1 << 12),
@@ -339,10 +369,33 @@
 	dma_addr_t mapping;
 };
 
+typedef enum {
+	CH_8139 = 0,
+	CH_8139A,
+	CH_8139B,
+} chip_t;
+
+/* directly indexed by chip_t, above */
+const static struct {
+	const char *name;
+	u32 RxConfigMask; /* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+	{ "RTL-8139",
+	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	},
+	
+	{ "RTL-8139A",
+	  0xf0fe0040,
+	},
+	
+	{ "RTL-8139B(L)",
+	  0xf0fc0040
+	},
+};
+
 
-#define PRIV_ALIGN	15	/* Required alignment mask */
 struct rtl8139_private {
-	chip_t chip;
+	board_t board;
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
@@ -350,7 +403,9 @@
 	struct timer_list timer;	/* Media selection timer. */
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
-	unsigned int cur_tx, dirty_tx, tx_flag;
+	unsigned int tx_flag;
+	atomic_t cur_tx;
+	atomic_t dirty_tx;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct ring_info tx_info[NUM_TX_DESC];
 	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
@@ -365,8 +420,8 @@
 	unsigned int media2:4;	/* Secondary monitored media port. */
 	unsigned int medialock:1;	/* Don't sense media type. */
 	unsigned int mediasense:1;	/* Media sensing in progress. */
-	int extended_regs;		/* bool: supports regs > 0x80 ? */
 	spinlock_t lock;
+	chip_t chipset;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -374,6 +429,7 @@
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (debug, "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
 
 static int read_eeprom (void *ioaddr, int location, int addr_len);
 static int rtl8139_open (struct net_device *dev);
@@ -429,17 +485,21 @@
 	TxErr | TxOK | RxErr | RxOK;
 
 static const unsigned int rtl8139_rx_config =
-	    (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) |
-	    (RX_DMA_BURST << 8);
+	  RxCfgEarlyRxNone | RxCfgFIFONone | RxCfgRcv32K | RxCfgDMAUnlimited;
 
 
-static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
+static int __devinit rtl8139_init_board (struct pci_dev *pdev,
+					 struct net_device **dev_out,
+					 void **ioaddr_out)
 {
 	void *ioaddr = NULL;
+	struct net_device *dev;
+	struct rtl8139_private *tp;
 	u8 tmp8;
-	int rc;
+	int rc, i;
 	u32 pio_start, pio_end, pio_flags, pio_len;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+	u32 tmp;
 
 	DPRINTK ("ENTER\n");
 
@@ -447,6 +507,16 @@
 	assert (ioaddr_out != NULL);
 
 	*ioaddr_out = NULL;
+	*dev_out = NULL;
+
+	/* dev zeroed in init_etherdev */
+	dev = init_etherdev (NULL, sizeof (*tp));
+	if (dev == NULL) {
+		printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+		DPRINTK ("EXIT, returning -ENOMEM\n");
+		return -ENOMEM;
+	}
+	tp = dev->priv;
 
 	pio_start = pci_resource_start (pdev, 0);
 	pio_end = pci_resource_end (pdev, 0);
@@ -458,6 +528,13 @@
 	mmio_flags = pci_resource_flags (pdev, 1);
 	mmio_len = pci_resource_len (pdev, 1);
 
+	/* set this immediately, we need to know before
+	 * we talk to the chip directly */
+	DPRINTK("PIO region size == 0x%02X\n", pio_len);
+	DPRINTK("MMIO region size == 0x%02X\n", mmio_len);
+	if (pio_len == RTL8139B_IO_SIZE)
+		tp->chipset = CH_8139B;
+
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
 		printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
@@ -482,14 +559,14 @@
 	}
 
 	/* make sure our PIO region in PCI space is available */
-	if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) {
+	if (!request_region (pio_start, pio_len, dev->name)) {
 		printk (KERN_ERR PFX "no I/O resource available, aborting\n");
 		rc = -EBUSY;
 		goto err_out;
 	}
 	
 	/* make sure our MMIO region in PCI space is available */
-	if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) {
+	if (!request_mem_region (mmio_start, mmio_len, dev->name)) {
 		printk (KERN_ERR PFX "no mem resource available, aborting\n");
 		rc = -EBUSY;
 		goto err_out_free_pio;
@@ -514,9 +591,32 @@
 		goto err_out_free_mmio;
 	}
 
+	/* Soft reset the chip. */
+	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay (10);
+
 	/* Bring the chip out of low-power mode. */
-	RTL_W8 (Config1, 0x00);
+	if (tp->chipset == CH_8139B) {
+		RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4));
+		RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2));
+	} else {
+		/* handle RTL8139A and RTL8139 cases */
+		/* XXX from becker driver. is this right?? */
+		RTL_W8 (Config1, 0);
+	}
 
+	/* sanity checks -- ensure PIO and MMIO registers agree */
+	assert (inb (pio_start+Config0) == readb (ioaddr+Config0));
+	assert (inb (pio_start+Config1) == readb (ioaddr+Config1));
+	assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));
+	assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
+	
 	/* make sure chip thinks PIO and MMIO are enabled */
 	tmp8 = RTL_R8 (Config1);
 	if ((tmp8 & Cfg1_PIO) == 0) {
@@ -530,14 +630,26 @@
 		goto err_out_iounmap;
 	}
 	
-	/* sanity checks -- ensure PIO and MMIO registers agree */
-	assert (inb (pio_start+Config0) == RTL_R8 (Config0));
-	assert (inb (pio_start+Config1) == RTL_R8 (Config1));
-	assert (inb (pio_start+TxConfig) == RTL_R8 (TxConfig));
-	assert (inb (pio_start+RxConfig) == RTL_R8 (RxConfig));
-
+	/* identify chip attached to board */
+	tmp = RTL_R32 (TxConfig);
+	if (((tmp >> 28) & 7) == 7) {
+		if (pio_len == RTL8139B_IO_SIZE)
+			tp->chipset = CH_8139B;
+		else
+			tp->chipset = CH_8139A;
+	} else {
+		tp->chipset = CH_8139;
+	}
+	DPRINTK ("chipset id (%d/%d/%d) == %d, '%s'\n",
+		CH_8139,
+		CH_8139A,
+		CH_8139B,
+		tp->chipset,
+		rtl_chip_info[tp->chipset].name);
+	
 	DPRINTK ("EXIT, returning 0\n");
 	*ioaddr_out = ioaddr;
+	*dev_out = dev;
 	return 0;	
 
 err_out_iounmap:
@@ -548,6 +660,8 @@
 err_out_free_pio:
 	release_region (pio_start, pio_len);
 err_out:
+	unregister_netdev (dev);
+	kfree (dev);
 	DPRINTK ("EXIT, returning %d\n", rc);
 	return rc;
 }
@@ -556,10 +670,12 @@
 static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 				       const struct pci_device_id *ent)
 {
-	struct net_device *dev;
+	struct net_device *dev = NULL;
 	struct rtl8139_private *tp;
-	int i, addr_len, option = -1;
+	int i, addr_len, option;
 	void *ioaddr = NULL;
+	static int board_idx = -1;
+	u8 tmp;
 
 #ifndef RTL8139_NDEBUG
 	static int printed_version = 0;
@@ -570,29 +686,24 @@
 	assert (pdev != NULL);
 	assert (ent != NULL);
 
-#ifndef RTL8139_NDEBUG
+	board_idx++;
+
 	if (!printed_version) {
 		printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n");
 		printed_version = 1;
 	}
-#endif /* RTL8139_NDEBUG */
 
-	i = rtl8139_init_pci (pdev, &ioaddr);
+	i = rtl8139_init_board (pdev, &dev, &ioaddr);
 	if (i < 0) {
 		DPRINTK ("EXIT, returning %d\n", i);
 		return i;
 	}
 	
+	tp = dev->priv;
+	
 	assert (ioaddr != NULL);
-
-	/* dev zeroed in init_etherdev */
-	dev = init_etherdev (NULL, sizeof (*tp) + PRIV_ALIGN);
-	if (dev == NULL) {
-		iounmap (ioaddr);
-		printk (KERN_ERR PFX "unable to alloc new ethernet\n");
-		DPRINTK ("EXIT, returning -ENOMEM\n");
-		return -ENOMEM;
-	}
+	assert (dev != NULL);
+	assert (tp != NULL);
 
 	addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
 	for (i = 0; i < 3; i++)
@@ -612,38 +723,47 @@
 	dev->irq = pdev->irq;
 	dev->base_addr = pci_resource_start (pdev, 1);
 
-	/* dev->priv/tp zeroed in init_etherdev */
-	dev->priv = tp = (void *)
-		(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+	/* dev->priv/tp zeroed and aligned in init_etherdev */
+	tp = dev->priv;
 
+	/* note: tp->chipset set in rtl8139_init_board */
 	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
 			PCI_COMMAND_MASTER | RTL8139_CAPS;
 	tp->pci_dev = pdev;
-	tp->chip = ent->driver_data;
+	tp->board = ent->driver_data;
 	tp->mmio_addr = ioaddr;
-	tp->extended_regs =
-		(pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0;
 	tp->lock = SPIN_LOCK_UNLOCKED;
 
 	PCI_SET_DRIVER_DATA (pdev, dev);
 
 	tp->phys[0] = 32;
 
-	printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s "
+	printk (KERN_INFO "%s: '%s' board found at 0x%lx, IRQ %d\n",
+		dev->name, board_info[ent->driver_data].name,
+		dev->base_addr, dev->irq);
+
+	printk (KERN_INFO "%s:   Chip is '%s'\n",
+		dev->name,
+		rtl_chip_info[tp->chipset].name);
+
+	printk (KERN_INFO "%s:   MAC address "
 		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
-		dev->name, chip_info[ent->driver_data].name,
-		dev->base_addr, dev->irq,
-		tp->extended_regs ? " 8139B regs," : "",
+		dev->name,
 		dev->dev_addr[0], dev->dev_addr[1],
 		dev->dev_addr[2], dev->dev_addr[3],
 		dev->dev_addr[4], dev->dev_addr[5]);
 
 	/* Put the chip into low-power mode. */
-	RTL_W8 (Cfg9346, Cfg9346_Unlock);
-	RTL_W8 (Config1, 0x03);	/* Enable PM & PCI VPD */
-	RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+
+	tmp = RTL_R8 (Config1) & Config1Clear;
+	tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
+	RTL_W8_F (Config1, tmp);
+
+	RTL_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
 
 	/* The lower four bits are the media type. */
+	option = (board_idx > 7) ? 0 : media[board_idx];
 	if (option > 0) {
 		tp->full_duplex = (option & 0x200) ? 1 : 0;
 		tp->default_port = option & 15;
@@ -686,10 +806,9 @@
 
 #ifndef RTL8139_NDEBUG
 	/* poison memory before freeing */
-	memset (dev, 0xC0,
+	memset (dev, 0xBC,
 		sizeof (struct net_device) +
-		sizeof (struct rtl8139_private) +
-		PRIV_ALIGN);
+		sizeof (struct rtl8139_private));
 #endif /* RTL8139_NDEBUG */
 
 	kfree (dev);
@@ -911,18 +1030,18 @@
 		return -EBUSY;
 	}
 
-	tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+	tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
 					   &tp->tx_bufs_dma);
-	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
 					   &tp->rx_ring_dma);
 	if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
 		free_irq(dev->irq, dev);
 
 		if (tp->tx_bufs)
-			pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+			pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
 					    tp->tx_bufs, tp->tx_bufs_dma);
 		if (tp->rx_ring)
-			pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+			pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
 					    tp->rx_ring, tp->rx_ring_dma);
 
 		DPRINTK ("EXIT, returning -ENOMEM\n");
@@ -931,16 +1050,16 @@
 		
 	}
 	
-	rtl8139_init_ring (dev);
 	tp->full_duplex = tp->duplex_lock;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
 
+	rtl8139_init_ring (dev);
 	rtl8139_hw_start (dev);
 
 	DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
 			" GP Pins %2.2x %s-duplex.\n",
 			dev->name, pci_resource_start (tp->pci_dev, 1),
-			dev->irq, RTL_R8 (GPPinData),
+			dev->irq, RTL_R8 (MediaStatus),
 			tp->full_duplex ? "full" : "half");
 
 	/* Set the timer to switch to check for link beat and perhaps switch
@@ -961,15 +1080,14 @@
 {
 	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
 	void *ioaddr = tp->mmio_addr;
-	int i;
-	unsigned long flags;
+	u32 i;
+	u8 tmp;
 
 	DPRINTK ("ENTER\n");
 	
-	spin_lock_irqsave (&tp->lock, flags);
-
 	/* Soft reset the chip. */
-	RTL_W8 (ChipCmd, CmdReset);
+	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
+	udelay (100);
 
 	/* Check that the chip has finished the reset. */
 	for (i = 1000; i > 0; i--)
@@ -981,53 +1099,100 @@
 	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
 
 	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8 (Cfg9346, Cfg9346_Unlock);
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+	udelay (100);
 
 	tp->cur_rx = 0;
 
-	/* Must enable Tx/Rx before setting transfer thresholds! */
-	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-	RTL_W32 (RxConfig, rtl8139_rx_config);
-	/* Check this value: the documentation contradicts ifself.  Is the
-	   IFG correct with bit 28:27 zero, or with |0x03000000 ? */
-	RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
+	/* init Rx ring buffer DMA address */
+	RTL_W32_F (RxBuf, tp->rx_ring_dma);
 
-	/* Reset N-Way to chipset defaults */
-	RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
-	for (i = 1000; i > 0; i--)
-		if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
-			break;
-	
-	/* Set N-Way to sane defaults */
-	RTL_W16 (FIFOTMS, 0x0000);
-	RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
-	RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
-	
-	/* check_duplex() here. */
-	RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+	/* init Tx buffer DMA addresses */
+	for (i = 0; i < NUM_TX_DESC; i++)
+		RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
 
-	/* lock Config[01234] and BMCR register writes */
-	RTL_W8 (Cfg9346, Cfg9346_Lock);
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) |
+			   CmdRxEnb | CmdTxEnb);
 
-	RTL_W32 (RxBuf, tp->rx_ring_dma);
+	i = rtl8139_rx_config |
+	    (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+	RTL_W32_F (RxConfig, i);
+
+	/* Check this value: the documentation for IFG contradicts ifself. */
+	RTL_W32 (TxConfig, (TX_DMA_BURST << 8));
+
+	/* if link status not ok... */
+	if ((RTL_R16 (BasicModeStatus) & (1<<2)) == 0) {
+		printk (KERN_INFO "%s: no link, starting NWay\n", dev->name);
+
+		/* Reset N-Way to chipset defaults */
+		RTL_W16 (BasicModeCtrl, RTL_R16 (BasicModeCtrl) | (1<<15));
+		for (i = 1000; i > 0; i--)
+			if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+				break;
+	
+		/* Set N-Way to sane defaults */
+		RTL_W16_F (FIFOTMS, RTL_R16 (FIFOTMS) & ~(1<<7));
+		RTL_W16_F (NWayAdvert, RTL_R16 (NWayAdvert) |
+			  (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<0));
+		RTL_W16_F (BasicModeCtrl, RTL_R16 (BasicModeCtrl) |
+			(1<<13)|(1<<12)|(1<<9)|(1<<8));
+		RTL_W8_F (MediaStatus, RTL_R8 (MediaStatus) | (1<<7) | (1<<6));
+	
+		/* check_duplex() here. */
+		/* XXX writing Config1 here is flat out wrong */
+		/* RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); */
+	}
+
+	tmp = RTL_R8 (Config1) & Config1Clear;
+	tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
+	RTL_W8_F (Config1, tmp);
+
+	if (tp->chipset == CH_8139B) {
+		tmp = RTL_R8 (Config4) & ~(1<<2);
+		/* chip will clear Rx FIFO overflow automatically */
+		tmp |= (1<<7);  
+		RTL_W8 (Config4, tmp);
+	}
+	
+	/* disable magic packet scanning, which is enabled
+	 * when PM is enabled above (Config1) */
+	RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));
 
-	/* Start the chip's Tx and Rx process. */
-	RTL_W32 (RxMissed, 0);
+	RTL_W32_F (RxMissed, 0);
 
-	/* release lock cuz set_rx_mode wants it */
-	spin_unlock_irqrestore (&tp->lock, flags);
 	rtl8139_set_rx_mode (dev);
-	spin_lock_irqsave (&tp->lock, flags);
 
-	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+	/* no early-rx interrupts */
+	RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
-	RTL_W16 (IntrMask, rtl8139_intr_mask);
+	RTL_W16_F (IntrMask, rtl8139_intr_mask);
 
-	if (netif_queue_stopped (dev))
-		netif_start_queue (dev);
+	netif_start_queue (dev);
 
-	spin_unlock_irqrestore (&tp->lock, flags);
+	DPRINTK ("EXIT\n");
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	tp->cur_rx = 0;
+	atomic_set (&tp->cur_tx, 0);
+	atomic_set (&tp->dirty_tx, 0);
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->tx_info[i].skb = NULL;
+		tp->tx_info[i].mapping = 0;
+		tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+	}
 
 	DPRINTK ("EXIT\n");
 }
@@ -1134,11 +1299,8 @@
 	void *ioaddr = tp->mmio_addr;
 	int next_tick = 60 * HZ;
 	int mii_reg5;
-	unsigned long flags;
 
-	DPRINTK ("ENTER\n");
-	
-	spin_lock_irqsave (&tp->lock, flags);
+	spin_lock_irq (&tp->lock);
 
 	mii_reg5 = mdio_read (dev, tp->phys[0], 5);
 
@@ -1154,7 +1316,6 @@
 				tp->phys[0], mii_reg5);
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
-			RTL_W8 (Cfg9346, Cfg9346_Lock);
 		}
 	}
 
@@ -1171,12 +1332,10 @@
 		 dev->name, RTL_R8 (Config0),
 		 RTL_R8 (Config1));
 
-	spin_unlock_irqrestore (&tp->lock, flags);
+	spin_unlock_irq (&tp->lock);
 
 	tp->timer.expires = jiffies + next_tick;
 	add_timer (&tp->timer);
-
-	DPRINTK ("EXIT\n");
 }
 
 
@@ -1184,38 +1343,37 @@
 {
 	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
 	void *ioaddr = tp->mmio_addr;
-	int mii_reg, i;
-	unsigned long flags;
-
-	DPRINTK ("ENTER\n");
-
-	spin_lock_irqsave (&tp->lock, flags);
+	int i;
 
 	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
 		 "media %2.2x.\n", dev->name,
 		 RTL_R8 (ChipCmd),
 		 RTL_R16 (IntrStatus),
-		 RTL_R8 (GPPinData));
+		 RTL_R8 (MediaStatus));
+
+	spin_lock_irq (&tp->lock);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	RTL_W16 (IntrMask, 0x0000);
+
+	spin_unlock_irq (&tp->lock);
+	
 	/* Emit info to figure out what went wrong. */
 	printk (KERN_DEBUG
 		"%s: Tx queue start entry %d  dirty entry %d.\n",
-		dev->name, tp->cur_tx, tp->dirty_tx);
+		dev->name, atomic_read (&tp->cur_tx),
+		atomic_read (&tp->dirty_tx));
 	for (i = 0; i < NUM_TX_DESC; i++)
 		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",
 			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
 			i ==
-		      tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
-	printk (KERN_DEBUG "%s: MII #%d registers are:", dev->name,
-		tp->phys[0]);
-	for (mii_reg = 0; mii_reg < 8; mii_reg++)
-		printk (" %4.4x", mdio_read (dev, tp->phys[0], mii_reg));
-	printk (".\n");
+		      atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? " (queue head)" : "");
+
+	spin_lock_irq (&tp->lock);
 
 	/* Stop a shared interrupt from scavenging while we are. */
-	tp->dirty_tx = tp->cur_tx = 0;
+	atomic_set (&tp->cur_tx, 0);
+	atomic_set (&tp->dirty_tx, 0);
 
 	/* Dump the unsent Tx packets. */
 	for (i = 0; i < NUM_TX_DESC; i++) {
@@ -1230,79 +1388,43 @@
 			rp->mapping = 0;
 		}
 	}
-
-	spin_unlock_irqrestore (&tp->lock, flags);
+	
+	spin_unlock_irq (&tp->lock);
 
 	rtl8139_hw_start (dev);
-
-	DPRINTK ("EXIT\n");
 }
 
 
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void rtl8139_init_ring (struct net_device *dev)
-{
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
-	int i;
-
-	DPRINTK ("ENTER\n");
-
-	tp->cur_rx = 0;
-	tp->dirty_tx = tp->cur_tx = 0;
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		tp->tx_info[i].skb = NULL;
-		tp->tx_info[i].mapping = 0;
-		tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
-	}
-
-	DPRINTK ("EXIT\n");
-}
-
 
 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
 	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int entry;
-	unsigned long flags;
-
-	DPRINTK ("ENTER\n");
-	
-	spin_lock_irqsave (&tp->lock, flags);
 
 	/* Calculate the next Tx descriptor entry. */
-	entry = tp->cur_tx % NUM_TX_DESC;
+	entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC;
 
 	tp->tx_info[entry].skb = skb;
-	if ((long) skb->data & 3) {	/* Must use alignment buffer. */
-		tp->tx_info[entry].mapping = 0;
-		memcpy (tp->tx_buf[entry], skb->data, skb->len);
+	tp->tx_info[entry].mapping = 0;
+	memcpy (tp->tx_buf[entry], skb->data, skb->len);
 
-		assert (tp->tx_bufs_dma > 0);
-		RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
-	} else {
-		tp->tx_info[entry].mapping =
-			pci_map_single(tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	spin_lock_irq (&tp->lock);
 
-		assert (tp->tx_info[entry].mapping > 0);
-		RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping);
-	}
-	
 	/* Note: the chip doesn't have auto-pad! */
-	RTL_W32 (TxStatus0 + entry * 4,
+	RTL_W32 (TxStatus0 + (entry * sizeof(u32)),
 		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
+	spin_unlock_irq (&tp->lock);
+
 	dev->trans_start = jiffies;
-	if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC)
+	atomic_inc (&tp->cur_tx);
+	if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC)
 		netif_stop_queue (dev);
 
-	spin_unlock_irqrestore (&tp->lock, flags);
-
 	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
 		 dev->name, skb->data, skb->len, entry);
 
-	DPRINTK ("EXIT\n");
 	return 0;
 }
 
@@ -1317,12 +1439,19 @@
 	assert (tp != NULL);
 	assert (ioaddr != NULL);
 	
-	dirty_tx = tp->dirty_tx;
+	/* drop lock held in rtl8139_interrupt */
+	spin_unlock (&tp->lock);
+	
+	dirty_tx = atomic_read (&tp->dirty_tx);
 
-	while (tp->cur_tx - dirty_tx > 0) {
+	while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) {
 		int entry = dirty_tx % NUM_TX_DESC;
-		int txstatus = RTL_R32 (TxStatus0 + (entry * 4));
+		int txstatus;
 
+		spin_lock (&tp->lock);
+		txstatus = RTL_R32 (TxStatus0 + (entry * 4));
+		spin_unlock (&tp->lock);
+		
 		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
 			break;	/* It still hasn't been Txed */
 
@@ -1334,7 +1463,9 @@
 			tp->stats.tx_errors++;
 			if (txstatus & TxAborted) {
 				tp->stats.tx_aborted_errors++;
-				RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x03000001);
+				spin_lock (&tp->lock);
+				RTL_W32 (TxConfig, (TX_DMA_BURST << 8));
+				spin_unlock (&tp->lock);
 			}
 			if (txstatus & TxCarrierLost)
 				tp->stats.tx_carrier_errors++;
@@ -1356,39 +1487,36 @@
 			tp->stats.tx_packets++;
 		}
 
-		if (tp->tx_info[entry].mapping != 0) {
-			pci_unmap_single (tp->pci_dev,
-					  tp->tx_info[entry].mapping,
-					  tp->tx_info[entry].skb->len,
-					  PCI_DMA_TODEVICE);
-			tp->tx_info[entry].mapping = 0;
-		}
 		/* Free the original skb. */
 		dev_kfree_skb_irq (tp->tx_info[entry].skb);
 		tp->tx_info[entry].skb = NULL;
 		dirty_tx++;
-		if (tp->cur_tx - dirty_tx < NUM_TX_DESC)
+		if (netif_queue_stopped (dev) &&
+		    (atomic_read (&tp->cur_tx) - dirty_tx < NUM_TX_DESC))
 			netif_wake_queue (dev);
 	}
 
 #ifndef RTL8139_NDEBUG
-	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+	if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
 		printk (KERN_ERR
 		  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
-		     dev->name, dirty_tx, tp->cur_tx);
+		     dev->name, dirty_tx, atomic_read (&tp->cur_tx));
 		dirty_tx += NUM_TX_DESC;
 	}
 #endif /* RTL8139_NDEBUG */
 
-	tp->dirty_tx = dirty_tx;
+	atomic_set (&tp->dirty_tx, dirty_tx);
+	
+	/* obtain lock need for rtl8139_interrupt */
+	spin_lock (&tp->lock);
 }
 
 
 /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
    field alignments and semantics. */
-static inline void rtl8139_rx_interrupt (struct net_device *dev,
-					 struct rtl8139_private *tp,
-					 void *ioaddr)
+static void rtl8139_rx_interrupt (struct net_device *dev,
+				  struct rtl8139_private *tp,
+				  void *ioaddr)
 {
 	unsigned char *rx_ring;
 	u16 cur_rx;
@@ -1440,6 +1568,9 @@
 		if (rx_status &
 		    (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr |
 		     RxBadAlign)) {
+			u8 tmp8;
+			int tmp_work = 1000;
+
 			DPRINTK ("%s: Ethernet frame had errors,"
 					" status %8.8x.\n", dev->name,
 					rx_status);
@@ -1457,10 +1588,23 @@
 				tp->stats.rx_crc_errors++;
 			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
 			tp->cur_rx = 0;
-			RTL_W8 (ChipCmd, CmdTxEnb);
+
+			/* disable receive */
+			tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
+			RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb);
+
 			/* A.C.: Reset the multicast list. */
 			rtl8139_set_rx_mode (dev);
-			RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+			while (--tmp_work > 0) {
+				tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
+				if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
+					break;
+				RTL_W8_F (ChipCmd, tmp8 | CmdRxEnb | CmdTxEnb);
+			}
+
+			if (tmp_work <= 0)			
+				printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
 		} else {
 			/* Malloc up new buffer, compatible with net-2e. */
 			/* Omit the four octet CRC from the length. */
@@ -1478,6 +1622,7 @@
 			}
 			skb->dev = dev;
 			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+
 			if (ring_offset + rx_size + 4 > RX_BUF_LEN) {
 				int semi_count =
 				    RX_BUF_LEN - ring_offset - 4;
@@ -1485,27 +1630,24 @@
 				memcpy (skb_put (skb, semi_count),
 					&rx_ring[ring_offset + 4],
 					semi_count);
-				memcpy (skb_put
-					(skb, rx_size - semi_count),
+				memcpy (skb_put (skb, rx_size - semi_count),
 					rx_ring, rx_size - semi_count);
 #ifdef RTL8139_DEBUG
 				{
 				int i;
-				printk (KERN_DEBUG
-					"%s:  Frame wrap @%d",
+				printk (KERN_DEBUG "%s:  Frame wrap @%d",
 					dev->name, semi_count);
 				for (i = 0; i < 16; i++)
-					printk (" %2.2x",
-						rx_ring[i]);
-				printk (".\n");
+					printk (" %2.2x", rx_ring[i]);
+				printk ("\n");
 				memset (rx_ring, 0xcc, 16);
 				}
 #endif /* RTL8139_DEBUG */
 
 			} else {
 				eth_copy_and_sum (skb,
-						  &rx_ring[ring_offset +
-							   4], rx_size, 0);
+						  &rx_ring[ring_offset + 4],
+						  rx_size, 0);
 				skb_put (skb, rx_size);
 			}
 			skb->protocol = eth_type_trans (skb, dev);
@@ -1526,10 +1668,10 @@
 }
 
 
-static inline int rtl8139_weird_interrupt (struct net_device *dev,
-					   struct rtl8139_private *tp,
-					   void *ioaddr,
-					   int status, int link_changed)
+static int rtl8139_weird_interrupt (struct net_device *dev,
+				    struct rtl8139_private *tp,
+				    void *ioaddr,
+				    int status, int link_changed)
 {
 	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
 		 dev->name, status);
@@ -1552,7 +1694,6 @@
 			tp->full_duplex = duplex;
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
-			RTL_W8 (Cfg9346, Cfg9346_Lock);
 		}
 		status &= ~RxUnderrun;
 	}
@@ -1594,9 +1735,6 @@
 
 	spin_lock (&tp->lock);
 	
-	/* disable interrupt generation while handling this interrupt */
-	RTL_W16 (IntrMask, 0x0000);
-
 	do {
 		status = RTL_R16 (IntrStatus);
 
@@ -1628,7 +1766,7 @@
 		   CPU speed, lower CPU speed --> more errors).
 		   After clearing the RxOverflow bit the transfer of the
 		   packet was repeated and all data are error free transfered */
-		RTL_W16 (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
+		RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
 
 		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
 				dev->name, status,
@@ -1664,14 +1802,10 @@
 		RTL_W16 (IntrStatus, 0xffff);
 	}
 
-	/* Enable all known interrupts by setting the interrupt mask. */
-	RTL_W16 (IntrMask, rtl8139_intr_mask);
-
 	spin_unlock (&tp->lock);
 	
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
-
 }
 
 
@@ -1695,7 +1829,7 @@
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Stop the chip's Tx and Rx DMA processes. */
-	RTL_W8 (ChipCmd, 0x00);
+	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
 
 	/* Update the error counts. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
@@ -1724,9 +1858,9 @@
 		tp->tx_info[i].mapping = 0;
 	}
 
-	pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+	pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
 			    tp->rx_ring, tp->rx_ring_dma);
-	pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+	pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
 			    tp->tx_bufs, tp->tx_bufs_dma);
 	tp->rx_ring = NULL;
 	tp->tx_bufs = NULL;
@@ -1838,6 +1972,7 @@
 	void *ioaddr = tp->mmio_addr;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
+	u32 tmp;
 	unsigned long flags=0;
 
 	DPRINTK ("ENTER\n");
@@ -1863,13 +1998,10 @@
 		struct dev_mc_list *mclist;
 		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
 		mc_filter[1] = mc_filter[0] = 0;
-		for (i = 0, mclist = dev->mc_list;
-		     mclist && i < dev->mc_count;
-		     i++, mclist =
-		     mclist->next) set_bit (ether_crc (ETH_ALEN,
-						       mclist->
-						       dmi_addr) >> 26,
-					    mc_filter);
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next)
+			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
+				 mc_filter);
 	}
 	
 	/* if called from irq handler, lock already acquired */
@@ -1877,7 +2009,9 @@
 		spin_lock_irqsave (&tp->lock, flags);
 
 	/* We can safely update without stopping the chip. */
-	RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode);
+	tmp = rtl8139_rx_config | rx_mode |
+		(RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+	RTL_W32_F (RxConfig, tmp);
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
@@ -1901,7 +2035,7 @@
 
 	/* Disable interrupts, stop Tx and Rx. */
 	RTL_W16 (IntrMask, 0x0000);
-	RTL_W8 (ChipCmd, 0x00);
+	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
 
 	/* Update the error counts. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.3.99-pre6/linux/drivers/net/82596.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/82596.c	Tue May  2 12:40:59 2000
@@ -1152,7 +1152,8 @@
 		if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
 			return -ENODEV;
 
-		request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+		if (!request_region(ioaddr, I596_TOTAL_SIZE, "i596"))
+			return -ENODEV;
 
 		dev->base_addr = ioaddr;
 		dev->irq = 10;
@@ -1493,11 +1494,9 @@
 #endif
 
 #ifdef MODULE
-static char devicename[9] =
-{0,};
 static struct net_device dev_82596 =
 {
-	devicename,	/* device name inserted by drivers/net/net_init.c */
+	"",	/* device name inserted by drivers/net/net_init.c */
 	0, 0, 0, 0,
 	0, 0,		/* base, irq */
 	0, 0, 0, NULL, i82596_probe};
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.99-pre6/linux/drivers/net/Config.in	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/Config.in	Mon May  8 22:21:58 2000
@@ -53,18 +53,18 @@
    fi
    bool '  3COM cards' CONFIG_NET_VENDOR_3COM
    if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
-      tristate '    3c501 support' CONFIG_EL1
-      tristate '    3c503 support' CONFIG_EL2
-      tristate '    3c505 support' CONFIG_ELPLUS
+      tristate '    3c501 "EtherLink" support' CONFIG_EL1
+      tristate '    3c503 "EtherLink II" support' CONFIG_EL2
+      tristate '    3c505 "EtherLink Plus" support' CONFIG_ELPLUS
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 tristate '    3c507 support (EXPERIMENTAL)' CONFIG_EL16
       fi
-      tristate '    3c509/3c529 (MCA)/3c579 support' CONFIG_EL3
+      tristate '    3c509/3c529 (MCA)/3c579 "EtherLink III" support' CONFIG_EL3
       tristate '    3c515 ISA Fast EtherLink' CONFIG_3C515
       if [ "$CONFIG_MCA" = "y" ]; then
-	 tristate '    3c523 support' CONFIG_ELMC
+	 tristate '    3c523 EtherLinkMC support' CONFIG_ELMC
 	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    tristate '    3c527 support (EXPERIMENTAL)' CONFIG_ELMC_II
+	    tristate '    3c527 EtherLink/MC 32 support (EXPERIMENTAL)' CONFIG_ELMC_II
 	 fi
       fi
       tristate '    3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
@@ -219,6 +219,9 @@
    dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
    dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
    dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   	dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+   fi
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.99-pre6/linux/drivers/net/Makefile	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/Makefile	Mon May  8 22:21:58 2000
@@ -27,7 +27,7 @@
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs     :=	8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \
-			ppp_generic.o slhc.o
+			ppp_generic.o slhc.o pppox.o
 
 ifeq ($(CONFIG_PCMCIA),y)
   SUB_DIRS += pcmcia
@@ -214,12 +214,14 @@
   ifeq ($(CONFIG_PPP_BSDCOMP),m)
     obj-m += bsd_comp.o
   endif
+  obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 else
   ifeq ($(CONFIG_PPP),m)
     obj-m += ppp_generic.o slhc.o
     obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
     obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
     obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
+    obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
     ifeq ($(CONFIG_PPP_BSDCOMP),m)
       obj-m += bsd_comp.o
     endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v2.3.99-pre6/linux/drivers/net/ac3200.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/ac3200.c	Tue May  2 12:40:59 2000
@@ -344,11 +344,9 @@
 
 #ifdef MODULE
 #define MAX_AC32_CARDS	4	/* Max number of AC32 cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_AC32_CARDS] = { 0, };
 static struct net_device dev_ac32[MAX_AC32_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -369,7 +367,6 @@
 
 	for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ac32[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];		/* Currently ignored by driver */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/aironet4500_card.c linux/drivers/net/aironet4500_card.c
--- v2.3.99-pre6/linux/drivers/net/aironet4500_card.c	Fri Mar 10 16:40:42 2000
+++ linux/drivers/net/aironet4500_card.c	Fri Apr 28 23:00:05 2000
@@ -121,7 +121,8 @@
 //				printk(KERN_ERR "aironet4X00 mem addrs not available for maping \n");
 //				continue;
 //		}
-		request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr");
+		if (!request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"))
+			continue;
 //		request_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
 //		request_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
 
@@ -998,4 +999,4 @@
 #endif
 
 }
-#endif
\ No newline at end of file
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c
--- v2.3.99-pre6/linux/drivers/net/appletalk/cops.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/net/appletalk/cops.c	Tue May  2 12:41:00 2000
@@ -1008,11 +1008,9 @@
 }
 
 #ifdef MODULE
-static char lt_name[16];
-
 static struct net_device cops0_dev =
 {
-	lt_name,	/* device name */
+	"",	/* device name */
         0, 0, 0, 0,
         0x0, 0,  /* I/O address, IRQ */
         0, 0, 0, NULL, cops_probe
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c
--- v2.3.99-pre6/linux/drivers/net/appletalk/ltpc.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/appletalk/ltpc.c	Tue May  2 12:41:00 2000
@@ -1272,10 +1272,8 @@
 
 #ifdef MODULE
 
-static char dev_name[8];
-
 static struct net_device dev_ltpc = {
-		dev_name, 
+		"", 
 		0, 0, 0, 0,
 	 	0x0, 0,
 	 	0, 0, 0, NULL, ltpc_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/arc-rimi.c linux/drivers/net/arcnet/arc-rimi.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/arc-rimi.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/arc-rimi.c	Tue May  2 12:36:09 2000
@@ -163,6 +163,7 @@
 		BUGMSG(D_NORMAL, "Can't allocate device data!\n");
 		goto err_free_irq;
 	}
+	lp->card_name = "RIM I";
 	lp->hw.command = arcrimi_command;
 	lp->hw.status = arcrimi_status;
 	lp->hw.intmask = arcrimi_setmask;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/arcnet.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/arcnet/arcnet.c	Tue May  2 12:36:09 2000
@@ -41,7 +41,7 @@
  *     <jojo@repas.de>
  */
 
-#define VERSION "arcnet: v3.92 BETA 2000/02/13 - by Avery Pennarun et al.\n"
+#define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -584,6 +584,8 @@
 	soft = &pkt->soft.rfc1201;
 	proto = arc_proto_map[soft->proto];
 
+	BUGMSG(D_SKB_SIZE, "skb: transmitting %d bytes to %02X\n",
+		skb->len, pkt->hard.dest);
 	BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx");
 
 	/* fits in one packet? */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/com20020-isa.c linux/drivers/net/arcnet/com20020-isa.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/com20020-isa.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/com20020-isa.c	Tue May  2 12:36:09 2000
@@ -52,6 +52,7 @@
 {
 	int ioaddr;
 	unsigned long airqmask;
+	struct arcnet_local *lp = dev->priv;
 
 #ifndef MODULE
 	arcnet_init();
@@ -103,6 +104,8 @@
 			}
 		}
 	}
+
+	lp->card_name = "ISA COM20020";
 	return com20020_found(dev, 0);
 }
 
@@ -119,7 +122,8 @@
 static char *device;		/* use eg. device="arc1" to change name */
 static int timeout = 3;
 static int backplane = 0;
-static int clock = 0;
+static int clockp = 0;
+static int clockm = 0;
 
 MODULE_PARM(node, "i");
 MODULE_PARM(io, "i");
@@ -127,7 +131,8 @@
 MODULE_PARM(device, "s");
 MODULE_PARM(timeout, "i");
 MODULE_PARM(backplane, "i");
-MODULE_PARM(clock, "i");
+MODULE_PARM(clockp, "i");
+MODULE_PARM(clockm, "i");
 
 static void com20020isa_open_close(struct net_device *dev, bool open)
 {
@@ -155,7 +160,8 @@
 		dev->dev_addr[0] = node;
 
 	lp->backplane = backplane;
-	lp->clock = clock & 7;
+	lp->clockp = clockp & 7;
+	lp->clockm = clockm & 3;
 	lp->timeout = timeout & 3;
 	lp->hw.open_close_ll = com20020isa_open_close;
 
@@ -174,13 +180,7 @@
 
 void cleanup_module(void)
 {
-	struct net_device *dev = my_dev;
-
-	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-	kfree(dev->priv);
-	kfree(dev);
+	com20020_remove(my_dev);
 }
 
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/com20020-pci.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/com20020-pci.c	Tue May  2 13:06:35 2000
@@ -42,11 +42,21 @@
 
 #define VERSION "arcnet: COM20020 PCI support\n"
 
-#ifdef MODULE
-#define MAX_CARDS	16
-static struct net_device *cards[MAX_CARDS];
-static int numcards;
-#endif
+/* Module parameters */
+
+static int node = 0;
+static char *device;		/* use eg. device="arc1" to change name */
+static int timeout = 3;
+static int backplane = 0;
+static int clockp = 0;
+static int clockm = 0;
+
+MODULE_PARM(node, "i");
+MODULE_PARM(device, "s");
+MODULE_PARM(timeout, "i");
+MODULE_PARM(backplane, "i");
+MODULE_PARM(clockp, "i");
+MODULE_PARM(clockm, "i");
 
 static void com20020pci_open_close(struct net_device *dev, bool open)
 {
@@ -56,111 +66,99 @@
 		MOD_DEC_USE_COUNT;
 }
 
-/*
- * No need to probe for PCI cards - just ask the PCI layer and launch all the
- * ones we find.
- */
-static int __init com20020pci_probe(char *name_template, int node, int backplane, int clock, int timeout)
+static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct net_device *dev;
 	struct arcnet_local *lp;
-	struct pci_dev *pdev = NULL;
-	int ioaddr, gotone = 0, err;
+	int ioaddr, err;
 
-	BUGLVL(D_NORMAL) printk(VERSION);
-
-	while ((pdev = pci_find_device(0x1571, 0xa004, pdev))) {
-		if (pci_enable_device(pdev))
-			continue;
-		dev = dev_alloc(name_template ? : "arc%d", &err);
-		if (!dev)
-			return err;
-		lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
-		if (!lp)
-			return -ENOMEM;
-		memset(lp, 0, sizeof(struct arcnet_local));
-
-		ioaddr = pdev->resource[2].start;
-		dev->base_addr = ioaddr;
-		dev->irq = pdev->irq;
-		dev->dev_addr[0] = node;
-		lp->backplane = backplane;
-		lp->clock = clock;
-		lp->timeout = timeout;
-		lp->hw.open_close_ll = com20020pci_open_close;
-
-		BUGMSG(D_INIT, "PCI BIOS reports a device at %Xh, IRQ %d\n",
-		       ioaddr, dev->irq);
-
-		if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
-			BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
-			       ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
-			continue;
-		}
-		if (ASTATUS() == 0xFF) {
-			BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
-			       "but seems empty!\n", ioaddr);
-			continue;
-		}
-		if (com20020_check(dev))
-			continue;
-
-		if (!com20020_found(dev, SA_SHIRQ)) {
-#ifdef MODULE
-			if(numcards==MAX_CARDS)
-				printk(KERN_WARNING "com20020pci: Too many cards. Ignoring.\n");
-			else
-				cards[numcards++] = dev;
-#endif
-			gotone++;
-		}
+	if (pci_enable_device(pdev))
+		return -EIO;
+	dev = dev_alloc(device ? : "arc%d", &err);
+	if (!dev)
+		return err;
+	lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+	memset(lp, 0, sizeof(struct arcnet_local));
+	pdev->driver_data = dev;
+
+	ioaddr = pci_resource_start(pdev, 2);
+	dev->base_addr = ioaddr;
+	dev->irq = pdev->irq;
+	dev->dev_addr[0] = node;
+	lp->card_name = pdev->name;
+	lp->card_flags = id->driver_data;
+	lp->backplane = backplane;
+	lp->clockp = clockp & 7;
+	lp->clockm = clockm & 3;
+	lp->timeout = timeout;
+	lp->hw.open_close_ll = com20020pci_open_close;
+
+	if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
+		BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
+		       ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
+		return -EBUSY;
 	}
+	if (ASTATUS() == 0xFF) {
+		BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
+		       "but seems empty!\n", ioaddr);
+		return -EIO;
+	}
+	if (com20020_check(dev))
+		return -EIO;
 
-	return gotone ? 0 : -ENODEV;
+	return com20020_found(dev, SA_SHIRQ);
 }
 
-
-#ifdef MODULE
-
-/* Module parameters */
-
-static int node = 0;
-static char *device;		/* use eg. device="arc1" to change name */
-static int timeout = 3;
-static int backplane = 0;
-static int clock = 0;
-
-MODULE_PARM(node, "i");
-MODULE_PARM(device, "s");
-MODULE_PARM(timeout, "i");
-MODULE_PARM(backplane, "i");
-MODULE_PARM(clock, "i");
-
-int init_module(void)
+static void __devexit com20020pci_remove(struct pci_dev *pdev)
 {
-	return com20020pci_probe(device, node, backplane, clock & 7, timeout & 3);
+	com20020_remove(pdev->driver_data);
 }
 
-void cleanup_module(void)
-{
-	struct net_device *dev;
-	int count;
+static struct pci_device_id com20020pci_id_table[] __devinitdata = {
+	{ 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+	{ 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+	{ 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+	{ 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+	{ 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+	{ 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{ 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{ 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{ 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{ 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{ 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+	{0,}
+};
+
+static struct pci_driver com20020pci_driver __devinitdata = {
+	name:		"com20020",
+	id_table:	com20020pci_id_table,
+	probe:		com20020pci_probe,
+	remove:		com20020pci_remove
+};
 
-	for (count = 0; count < numcards; count++) {
-		dev = cards[count];
-		unregister_netdev(dev);
-		free_irq(dev->irq, dev);
-		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-		kfree(dev->priv);
-		kfree(dev);
-	}
+int com20020pci_init(void)
+{
+	BUGLVL(D_NORMAL) printk(VERSION);
+#ifndef MODULE
+	arcnet_init();
+#endif
+	return pci_module_init(&com20020pci_driver);
 }
 
-#else
-
-void __init com20020pci_probe_all(void)
+void com20020pci_cleanup(void)
 {
-	com20020pci_probe(NULL, 0, 0, 0, 3);
+	pci_unregister_driver(&com20020pci_driver);
 }
 
-#endif				/* MODULE */
+module_init(com20020pci_init)
+module_exit(com20020pci_cleanup)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/com20020.c linux/drivers/net/arcnet/com20020.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/com20020.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/com20020.c	Tue May  2 12:36:09 2000
@@ -42,9 +42,9 @@
 #define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n"
 
 static char *clockrates[] =
-{"2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s",
- "156.25 Kb/s", "Reserved", "Reserved",
- "Reserved"};
+{"10 Mb/s", "Reserved", "5 Mb/s",
+ "2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s",
+ "156.25 Kb/s", "Reserved", "Reserved", "Reserved"};
 
 static void com20020_command(struct net_device *dev, int command);
 static int com20020_status(struct net_device *dev);
@@ -87,7 +87,7 @@
 
 
 /* Reset the card and check some basic stuff during the detection stage. */
-int __init com20020_check(struct net_device *dev)
+int __devinit com20020_check(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr, status;
 	struct arcnet_local *lp = dev->priv;
@@ -95,15 +95,25 @@
 	ARCRESET0;
 	mdelay(RESETtime);
 
-	lp->setup = lp->clock << 1;
+	lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
+	lp->setup2 = (lp->clockm << 4) | 8;
 
-	REGSETUP;
-	SETCONF(lp->config);
-	outb(lp->setup, ioaddr + 7);
+	SET_SUBADR(SUB_SETUP1);
+	outb(lp->setup, _XREG);
+
+	if (lp->card_flags & ARC_CAN_10MBIT)
+	{
+		SET_SUBADR(SUB_SETUP2);
+		outb(lp->setup2, _XREG);
+	
+		/* must now write the magic "restart operation" command */
+		mdelay(1);
+		outb(0x18, _COMMAND);
+	}
 
 	lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
 	/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
-	SETCONF(lp->config);
+	SETCONF;
 	outb(0x42, ioaddr + 7);
 
 	status = ASTATUS();
@@ -139,7 +149,7 @@
 /* Set up the struct net_device associated with this card.  Called after
  * probing succeeds.
  */
-int __init com20020_found(struct net_device *dev, int shared)
+int __devinit com20020_found(struct net_device *dev, int shared)
 {
 	struct arcnet_local *lp;
 	int ioaddr = dev->base_addr;
@@ -166,16 +176,24 @@
 	if (!dev->dev_addr[0])
 		dev->dev_addr[0] = inb(ioaddr + 8);	/* FIXME: do this some other way! */
 
-	lp->setup = lp->clock << 1;
+	SET_SUBADR(SUB_SETUP1);
+	outb(lp->setup, _XREG);
+
+	if (lp->card_flags & ARC_CAN_10MBIT)
+	{
+		SET_SUBADR(SUB_SETUP2);
+		outb(lp->setup2, _XREG);
+	
+		/* must now write the magic "restart operation" command */
+		mdelay(1);
+		outb(0x18, _COMMAND);
+	}
 
-	REGSETUP;
-	SETCONF(lp->config);
-	outb(lp->setup, ioaddr + 7);
 
 	lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1;
 	/* Default 0x38 + register: Node ID */
-	SETCONF(lp->config);
-	outb(dev->dev_addr[0], ioaddr + 7);
+	SETCONF;
+	outb(dev->dev_addr[0], _XREG);
 
 	/* reserve the irq */
 	if (request_irq(dev->irq, &arcnet_interrupt, shared,
@@ -183,22 +201,26 @@
 		BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
 		return -ENODEV;
 	}
-	/* reserve the I/O region - guaranteed to work by check_region */
-	request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)");
+	/* reserve the I/O region */
+	if (request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
+		free_irq(dev->irq, dev);
+		return -EBUSY;
+	}
 	dev->base_addr = ioaddr;
 
-	BUGMSG(D_NORMAL, "COM20020: station %02Xh found at %03lXh, IRQ %d.\n",
-	       dev->dev_addr[0], dev->base_addr, dev->irq);
+	BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
+	       lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
 
 	if (lp->backplane)
 		BUGMSG(D_NORMAL, "Using backplane mode.\n");
 
 	if (lp->timeout != 3)
 		BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout);
-	if (lp->setup) {
-		BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
-		       lp->setup >> 1, clockrates[lp->setup >> 1]);
-	}
+
+	BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
+	       lp->setup >> 1, 
+	       clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
+
 	if (!dev->init && register_netdev(dev)) {
 		free_irq(dev->irq, dev);
 		release_region(ioaddr, ARCNET_TOTAL_SIZE);
@@ -227,7 +249,7 @@
 
 	lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
 	/* power-up defaults */
-	SETCONF(lp->config);
+	SETCONF;
 
 	if (really_reset) {
 		/* reset the card */
@@ -283,7 +305,7 @@
 	else {
 		/* disable transmitter */
 		lp->config &= ~TXENcfg;
-		SETCONF(lp->config);
+		SETCONF;
 		MOD_DEC_USE_COUNT;
 	}
 	lp->hw.open_close_ll(dev, open);
@@ -305,39 +327,34 @@
 	if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {	/* Enable promiscuous mode */
 		if (!(lp->setup & PROMISCset))
 			BUGMSG(D_NORMAL, "Setting promiscuous flag...\n");
-		REGSETUP;
-		SETCONF(lp->config);
+		SET_SUBADR(SUB_SETUP1);
 		lp->setup |= PROMISCset;
-		outb(lp->setup, _SETUP);
+		outb(lp->setup, _XREG);
 	} else
 		/* Disable promiscuous mode, use normal mode */
 	{
 		if ((lp->setup & PROMISCset))
 			BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
-		REGSETUP;
-		SETCONF(lp->config);
+		SET_SUBADR(SUB_SETUP1);
 		lp->setup &= ~PROMISCset;
-		outb(lp->setup, _SETUP);
+		outb(lp->setup, _XREG);
 	}
 }
 
-
-/*
- * FIXME: put this somewhere!
- * 
- if ((dstatus = inb(_DIAGSTAT)) & NEWNXTIDflag)
- {
- REGNXTID;
- SETCONF(lp->config);
- BUGMSG(D_EXTRA, "New NextID detected: %X\n", inb(ioaddr + 7));
- }
- */
-
+void __devexit com20020_remove(struct net_device *dev)
+{
+	unregister_netdev(dev);
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
+	kfree(dev->priv);
+	kfree(dev);
+}
 
 #ifdef MODULE
 
 EXPORT_SYMBOL(com20020_check);
 EXPORT_SYMBOL(com20020_found);
+EXPORT_SYMBOL(com20020_remove);
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/com90io.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/arcnet/com90io.c	Tue May  2 12:36:09 2000
@@ -253,6 +253,7 @@
 	memset(dev->priv, 0, sizeof(struct arcnet_local));
 
 	lp = (struct arcnet_local *) (dev->priv);
+	lp->card_name = "COM90xx I/O";
 	lp->hw.command = com90io_command;
 	lp->hw.status = com90io_status;
 	lp->hw.intmask = com90io_setmask;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/com90xx.c linux/drivers/net/arcnet/com90xx.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/com90xx.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/com90xx.c	Tue May  2 12:36:09 2000
@@ -452,6 +452,7 @@
 
 	/* Initialize the rest of the device structure. */
 	memset(lp, 0, sizeof(struct arcnet_local));
+	lp->card_name = "COM90xx";
 	lp->hw.command = com90xx_command;
 	lp->hw.status = com90xx_status;
 	lp->hw.intmask = com90xx_setmask;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/arcnet/rfc1201.c linux/drivers/net/arcnet/rfc1201.c
--- v2.3.99-pre6/linux/drivers/net/arcnet/rfc1201.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/rfc1201.c	Tue May  2 12:36:09 2000
@@ -280,6 +280,7 @@
 			if (in->numpackets > 16) {
 				BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
 				       soft->split_flag);
+				lp->rfc1201.aborted_seq = soft->sequence;
 				lp->stats.rx_errors++;
 				lp->stats.rx_length_errors++;
 				return;
@@ -288,6 +289,7 @@
 						  GFP_ATOMIC);
 			if (skb == NULL) {
 				BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n");
+				lp->rfc1201.aborted_seq = soft->sequence;
 				lp->stats.rx_dropped++;
 				return;
 			}
@@ -355,6 +357,10 @@
 			in->skb = NULL;
 			in->lastpacket = in->numpackets = 0;
 
+	    BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (unsplit)\n",
+    		skb->len, pkt->hard.source);
+	    BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (split)\n",
+    		skb->len, pkt->hard.source);
 			BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
 
 			skb->protocol = type_trans(skb, dev);
@@ -442,8 +448,11 @@
 		hard->offset[0] = 0;
 		hard->offset[1] = ofs = 512 - softlen;
 	} else if (softlen > MTU) {	/* exception packet - add an extra header */
-		struct arc_rfc1201 excsoft =
-		{soft->proto, 0xFF, 0xFFFF};
+		struct arc_rfc1201 excsoft;
+
+		excsoft.proto = soft->proto;
+		excsoft.split_flag = 0xff;
+		excsoft.sequence = 0xffff;
 
 		hard->offset[0] = 0;
 		ofs = 512 - softlen;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.3.99-pre6/linux/drivers/net/at1700.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/at1700.c	Tue May  2 12:40:59 2000
@@ -877,9 +877,8 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
 static struct net_device dev_at1700 = {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	"", /* device name is inserted by linux/drivers/net/net_init.c */
 	0, 0, 0, 0,
 	0, 0,
 	0, 0, 0, NULL, at1700_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.3.99-pre6/linux/drivers/net/atp.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/atp.c	Thu May  4 11:33:58 2000
@@ -130,8 +130,6 @@
 
 /* Index to functions, as function prototypes. */
 
-extern int atp_probe(struct net_device *dev);
-
 static int atp_probe1(struct net_device *dev, short ioaddr);
 static void get_node_ID(struct net_device *dev);
 static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
@@ -571,9 +569,7 @@
 		for (i = 0; i < 6; i++)
 			write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
 #ifdef TIMED_CHECKER
-		del_timer(&atp_timer);
-		atp_timer.expires = jiffies + TIMED_CHECKER;
-		add_timer(&atp_timer);
+		mod_timer(&atp_timer, jiffies+TIMED_CHECKER);
 #endif
 	}
 
@@ -605,9 +601,7 @@
 	for (i = 0; i < 6; i++)
 		write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
 	spin_unlock(&lp->lock);
-	del_timer(&atp_timer);
-	atp_timer.expires = jiffies + TIMED_CHECKER;
-	add_timer(&atp_timer);
+	mod_timer(&atp_timer, jiffies+TIMED_CHECKER);
 }
 #endif
 
@@ -754,9 +748,8 @@
 #ifdef MODULE
 
 static int io = 0;
-static char nullname[8] = "";
 static struct net_device atp_dev = {
-	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_probe };
+	"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_init };
 	
 MODULE_PARM(io, "I/O port of the pocket adapter");
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/bonding.c linux/drivers/net/bonding.c
--- v2.3.99-pre6/linux/drivers/net/bonding.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/bonding.c	Tue May  2 12:40:59 2000
@@ -309,10 +309,8 @@
 
 #ifdef MODULE
 
-static char bond_name[16];
-
 static struct net_device dev_bond = {
-		bond_name, 	/* Needs to be writeable */
+		"",
 		0, 0, 0, 0,
 	 	0x0, 0,
 	 	0, 0, 0, NULL, bond_init };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.3.99-pre6/linux/drivers/net/cs89x0.c	Wed Apr 26 16:34:07 2000
+++ linux/drivers/net/cs89x0.c	Tue May  2 12:40:59 2000
@@ -1491,9 +1491,8 @@
 
 #ifdef MODULE
 
-static char namespace[16] = "";
 static struct net_device dev_cs89x0 = {
-        NULL,
+        "",
         0, 0, 0, 0,
         0, 0,
         0, 0, 0, NULL, NULL };
@@ -1560,7 +1559,6 @@
 #if DEBUGGING
 	net_debug = debug;
 #endif
-        dev_cs89x0.name = namespace;
 	dev_cs89x0.irq = irq;
 	dev_cs89x0.base_addr = io;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.99-pre6/linux/drivers/net/de4x5.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/de4x5.c	Wed May 10 16:56:42 2000
@@ -4356,12 +4356,11 @@
 static void
 srom_address(u_int command, u_long addr, u_char offset)
 {
-    int i;
-    char a;
+    int i, a;
     
-    a = (char)(offset << 2);
+    a = offset << 2;
     for (i=0; i<6; i++, a <<= 1) {
-	srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
+	srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr);
     }
     de4x5_us_delay(1);
     
@@ -5904,13 +5903,12 @@
 {
     struct net_device *new;
 
-    new = (struct net_device *)kmalloc(sizeof(struct net_device)+8, GFP_KERNEL);
+    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
     if (new == NULL) {
 	printk("de4x5.c: Device not initialised, insufficient memory\n");
 	return NULL;
     } else {
-	memset((char *)new, 0, sizeof(struct net_device)+8);
-	new->name = (char *)(new + 1);
+	memset((char *)new, 0, sizeof(struct net_device));
 	new->base_addr = iobase;       /* assign the io address */
 	new->init = init;              /* initialisation routine */
     }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.3.99-pre6/linux/drivers/net/de600.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/de600.c	Tue May  2 12:40:59 2000
@@ -819,9 +819,8 @@
 #endif
 
 #ifdef MODULE
-static char nullname[8];
 static struct net_device de600_dev = {
-	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe };
+	"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe };
 
 int
 init_module(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.3.99-pre6/linux/drivers/net/de620.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/de620.c	Tue May  2 12:40:59 2000
@@ -985,9 +985,8 @@
  *
  */
 #ifdef MODULE
-static char nullname[8] = "";
 static struct net_device de620_dev = {
-	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de620_probe };
+	"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de620_probe };
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.3.99-pre6/linux/drivers/net/depca.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/depca.c	Tue May  2 12:40:59 2000
@@ -1524,7 +1524,7 @@
 {
     struct net_device *new;
 
-    new = (struct net_device *)kmalloc(sizeof(struct net_device)+8, GFP_KERNEL);
+    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
     if (new == NULL) {
 	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
 	return NULL;
@@ -1532,7 +1532,6 @@
 	new->next = dev->next;
 	dev->next = new;
 	dev = dev->next;               /* point to the new device */
-	dev->name = (char *)(dev + 1);
 	if (num_eth > 9999) {
 	    sprintf(dev->name,"eth????");/* New device name */
 	} else {
@@ -2002,9 +2001,8 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = {0,};
 static struct net_device thisDepca = {
-  devicename,  /* device name is inserted by /linux/drivers/net/net_init.c */
+  "",  /* device name is inserted by /linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0x200, 7,    /* I/O address, IRQ */
   0, 0, 0, NULL, depca_probe
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.3.99-pre6/linux/drivers/net/dgrs.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/dgrs.c	Wed May  3 01:45:18 2000
@@ -192,7 +192,6 @@
 	/*
 	 *	Stuff for generic ethercard I/F
 	 */
-	char			devname[8];	/* "ethN" string */
 	struct net_device		*next_dev;
 	struct net_device_stats	stats;
 
@@ -1256,7 +1255,6 @@
 	dev->priv = ((void *)dev) + sizeof(struct net_device);
 	priv = (DGRS_PRIV *)dev->priv;
 
-	dev->name = priv->devname; /* An empty string. */
 	dev->base_addr = io;
 	dev->mem_start = mem;
 	dev->mem_end = mem + 2048 * 1024 - 1;
@@ -1294,9 +1292,6 @@
 		memcpy(devN, dev, dev_size);
 		devN->priv = ((void *)devN) + sizeof(struct net_device);
 		privN = (DGRS_PRIV *)devN->priv;
-			/* ... but seset devname to a NULL string */
-		privN->devname[0] = 0;
-		devN->name = privN->devname;
 			/* ... and zero out VM areas */
 		privN->vmem = 0;
 		privN->vplxdma = 0;
@@ -1335,34 +1330,15 @@
 	 */
 	if (pci_present())
 	{
-		int pci_index = 0;
+		struct pci_dev *pdev = NULL;
 
-		for (; pci_index < 8; pci_index++)
+		while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL)
 		{
-			uchar	pci_bus, pci_device_fn;
-#if LINUX_VERSION_CODE < 0x20100
-			uchar	pci_irq;
-#else
-			uint	pci_irq;
-			struct pci_dev *pdev;
-#endif
-			uchar	pci_latency;
-			ushort	pci_command;
-
-			if (pcibios_find_device(SE6_PCI_VENDOR_ID,
-							SE6_PCI_DEVICE_ID,
-							pci_index, &pci_bus,
-							&pci_device_fn))
-					break;
-
-			pdev = pci_find_slot(pci_bus, pci_device_fn);
-			pci_irq = pdev->irq;
-			plxreg = pdev->resource[0].start;
-			io = pdev->resource[1].start;
-			mem = pdev->resource[2].start;
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-					0x30, &plxdma);
-			irq = pci_irq;
+			plxreg = pci_resource_start (pdev, 0);
+			io = pci_resource_start (pdev, 1);
+			mem = pci_resource_start (pdev, 2);
+			pci_read_config_dword(pdev, 0x30, &plxdma);
+			irq = pdev->irq;
 			plxdma &= ~15;
 
 			/*
@@ -1378,10 +1354,8 @@
 			OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
 			if (plxdma == 0)
 				plxdma = mem + (2048L * 1024L);
-			pcibios_write_config_dword(pci_bus, pci_device_fn,
-					0x30, plxdma + 1);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-					0x30, &plxdma);
+			pci_write_config_dword(pdev, 0x30, plxdma + 1);
+			pci_read_config_dword(pdev, 0x30, &plxdma);
 			plxdma &= ~15;
 
 			/*
@@ -1391,26 +1365,9 @@
 			 * value to avoid data corruption that occurs when the
 			 * timer expires during a transfer.  Yes, it's a bug.
 			 */
-			pcibios_read_config_word(pci_bus, pci_device_fn,
-						 PCI_COMMAND, &pci_command);
-			if ( ! (pci_command & PCI_COMMAND_MASTER))
-			{
-				printk("  Setting the PCI Master Bit!\n");
-				pci_command |= PCI_COMMAND_MASTER;
-				pcibios_write_config_word(pci_bus,
-						pci_device_fn,
-						PCI_COMMAND, pci_command);
-			}
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-					 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency != 255)
-			{
-				printk("  Overriding PCI latency timer: "
-					"was %d, now is 255.\n", pci_latency);
-				pcibios_write_config_byte(pci_bus,
-						pci_device_fn,
-						PCI_LATENCY_TIMER, 255);
-			}
+			if (pci_enable_device(pdev))
+				continue;
+			pci_set_master(pdev);
 
 			dgrs_found_device(io, mem, irq, plxreg, plxdma);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.3.99-pre6/linux/drivers/net/dmfe.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/dmfe.c	Fri Apr 28 23:00:05 2000
@@ -367,7 +367,7 @@
 				
 		/* Enable Master/IO access, Disable memory access */
 		
-		pci_enable_device (net_dev);
+		pci_enable_device (net_dev); /* XXX check return val */
 		pci_set_master(net_dev);
 		
 		/* Set Latency Timer 80h */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v2.3.99-pre6/linux/drivers/net/dummy.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/dummy.c	Tue May  2 12:40:59 2000
@@ -133,10 +133,8 @@
 	return 0;
 }
 
-static char dummy_name[16];
-
 static struct net_device dev_dummy = {
-		dummy_name, 	/* Needs to be writeable */
+		"",
 		0, 0, 0, 0,
 	 	0x0, 0,
 	 	0, 0, 0, NULL, dummy_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v2.3.99-pre6/linux/drivers/net/e2100.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/e2100.c	Tue May  2 12:40:59 2000
@@ -384,11 +384,9 @@
 
 #ifdef MODULE
 #define MAX_E21_CARDS	4	/* Max number of E21 cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_E21_CARDS] = { 0, };
 static struct net_device dev_e21[MAX_E21_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -414,7 +412,6 @@
 
 	for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
 		struct net_device *dev = &dev_e21[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.3.99-pre6/linux/drivers/net/eepro.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/eepro.c	Tue May  2 12:40:59 2000
@@ -1572,7 +1572,6 @@
 }
 
 #define MAX_EEPRO 8
-static char devicename[MAX_EEPRO][9];
 static struct net_device dev_eepro[MAX_EEPRO];
 
 static int io[MAX_EEPRO] = {
@@ -1606,7 +1605,6 @@
 
 	while (n_eepro < MAX_EEPRO && io[n_eepro] >= 0) {
 		struct net_device *d = &dev_eepro[n_eepro];
-		d->name		= devicename[n_eepro]; /* inserted by drivers/net/net_init.c */
 		d->mem_end	= mem[n_eepro];
 		d->base_addr	= io[n_eepro];
 		d->irq		= irq[n_eepro];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.99-pre6/linux/drivers/net/eepro100.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/eepro100.c	Fri Apr 28 23:00:05 2000
@@ -651,10 +651,8 @@
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	}
 
-	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR "eepro100: Could not enable PCI device\n");
+	if (pci_enable_device(pdev))
 		goto err_out_free_mmio_region;
-	}
 
 	pci_set_master(pdev);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.3.99-pre6/linux/drivers/net/eexpress.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/eexpress.c	Tue May  2 12:40:59 2000
@@ -1623,13 +1623,10 @@
 #ifdef MODULE
 
 #define EEXP_MAX_CARDS     4    /* max number of cards to support */
-#define NAMELEN            8    /* max length of dev->name (inc null) */
-
-static char namelist[NAMELEN * EEXP_MAX_CARDS] = { 0, };
 
 static struct net_device dev_eexp[EEXP_MAX_CARDS] =
 {
-        { NULL,         /* will allocate dynamically */
+        { "",
 	  0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe },
 };
 
@@ -1649,7 +1646,6 @@
 
 	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
 		struct net_device *dev = &dev_eexp[this_dev];
-		dev->name = namelist + (NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		if (io[this_dev] == 0) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.3.99-pre6/linux/drivers/net/epic100.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/epic100.c	Fri May  5 12:37:52 2000
@@ -1,85 +1,75 @@
 /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
 /*
-	Written/copyright 1997-1998 by Donald Becker.
+	Written/copyright 1997-2000 by Donald Becker.
 
-	This software may be used and distributed according to the terms
-	of the GNU Public License, incorporated herein by reference.
-	All other rights reserved.
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
 
 	This driver is for the SMC83c170/175 "EPIC" series, as used on the
 	SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	USRA Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
 
 	Information and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
-
-
-
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the SMC "EPIC/100", the SMC
-single-chip Ethernet controllers for PCI.  This chip is used on
-the SMC EtherPower II boards.
-
-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 will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-IVb. References
-
-http://www.smsc.com/main/datasheets/83c171.pdf
-http://www.smsc.com/main/datasheets/83c175.pdf
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://www.national.com/pf/DP/DP83840A.html
-
-IVc. Errata
+	http://www.scyld.com/network/epic100.html
+	
+	Linux kernel-specific changes:
+	
+	LK1.1.2 (jgarzik):
+	* Merge becker version 1.09
 
 */
 
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
 
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 32;
 
-static const char *version =
-"epic100.c:v1.04 8/23/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+/* Used to pass the full-duplex flag, etc. */
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+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 few user-configurable values. */
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak = 200;
+
+/* Operational parameters that are set at compile time. */
 
 /* Keep the ring sizes a power of two for efficiency.
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
+#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
 #define RX_RING_SIZE	32
 
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 10;
-
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((2000*HZ)/1000)
+#define TX_TIMEOUT  (2*HZ)
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
 /* Bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256		/* Rounded down to 4 byte units. */
+/* Initial threshold, increased on underflow, rounded down to 4 byte units. */
+#define TX_FIFO_THRESH 256
 #define RX_FIFO_THRESH 1		/* 0-3, 0==32, 64,96, or 3==128 bytes  */
 
+#if !defined(__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/string.h>
@@ -89,150 +79,188 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/delay.h>
-
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
 
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+"epic100.c:v1.09+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>\n";
+static char version2[] __devinitdata =
+"  	http://www.scyld.com/network/epic100.html\n";
 
 #define EPIC100_MODULE_NAME "epic100"
 #define PFX EPIC100_MODULE_NAME ": "
 
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet 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");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
-/* The I/O extent. */
-#define EPIC_TOTAL_SIZE 0x100
+/*
+				Theory of Operation
 
-#define epic_debug debug
-static int epic_debug = 1;
+I. Board Compatibility
+
+This device driver is designed for the SMC "EPIC/100", the SMC
+single-chip Ethernet controllers for PCI.  This chip is used on
+the SMC EtherPower II boards.
 
-/* The rest of these values should never change. */
+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 will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
 
-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,
+III. Driver operation
+
+IIIa. Ring buffers
+
+IVb. References
+
+http://www.smsc.com/main/datasheets/83c171.pdf
+http://www.smsc.com/main/datasheets/83c175.pdf
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840A.html
+
+IVc. Errata
+
+*/
+
+
+enum pci_id_flags_bits {
+        /* Set PCI command register bits before calling probe1(). */
+        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+        /* Read and map the single following PCI BAR. */
+        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
+        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
 };
 
 
+enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
+
+
+#define EPIC_TOTAL_SIZE 0x100
+#ifdef USE_IO_OPS
+#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
+#else
+#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
+#endif
+
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+
 typedef enum {
+	SMSC_83C170_0,
 	SMSC_83C170,
 	SMSC_83C175,
 } chip_t;
 
 
-struct epic100_chip_info {
+struct epic_chip_info {
 	const char *name;
+	enum pci_id_flags_bits pci_flags;
+        int io_size;                            /* Needed for I/O region check or ioremap(). */
+        int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
 
 /* indexed by chip_t */
-static struct epic100_chip_info epic100_chip_info[] __devinitdata = {
-	{ "SMSC EPIC/100 83c170" },
-	{ "SMSC EPIC/C 83c175" },
+static struct epic_chip_info epic_chip_info[] __devinitdata = {
+	{ "SMSC EPIC/100 83c170",
+	 EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
+	{ "SMSC EPIC/100 83c170",
+	 EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR },
+	{ "SMSC EPIC/C 83c175",
+	 EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
 };
 
 
-static struct pci_device_id epic100_pci_tbl[] __devinitdata = {
-	{ 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170, },
-	{ 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175, },
+static struct pci_device_id epic_pci_tbl[] __devinitdata = {
+	{ 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 },
+	{ 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 },
+	{ 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175 },
 	{ 0,},
 };
-MODULE_DEVICE_TABLE (pci, epic100_pci_tbl);
+MODULE_DEVICE_TABLE (pci, epic_pci_tbl);
 
 	
+#ifndef USE_IO_OPS
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
+#define inb readb
+#define inw readw
+#define inl readl
+#define outb writeb
+#define outw writew
+#define outl writel
+#endif
+
 /* Offsets to registers, using the (ugh) SMC names. */
 enum epic_registers {
-	COMMAND = 0,
-	INTSTAT = 4,
-	INTMASK = 8,
-	GENCTL = 0x0C,
-	NVCTL = 0x10,
-	EECTL = 0x14,
-	PCIBurstCnt = 0x18,
-	TEST1 = 0x1C,
-	CRCCNT = 0x20,
-	ALICNT = 0x24,
-	MPCNT = 0x28,		/* Rx error counters. */
-	MIICtrl = 0x30,
-	MIIData = 0x34,
-	MIICfg = 0x38,
-	LAN0 = 64,		/* MAC address. */
-	MC0 = 80,		/* Multicast filter table. */
-	RxCtrl = 96,
-	TxCtrl = 112,
-	TxSTAT = 0x74,
-	PRxCDAR = 0x84,
-	RxSTAT = 0xA4,
-	EarlyRx = 0xB0,
-	PTxCDAR = 0xC4,
-	TxThresh = 0xDC,
+  COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
+  PCIBurstCnt=0x18,
+  TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28,	/* Rx error counters. */
+  MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
+  LAN0=64,						/* MAC address. */
+  MC0=80,						/* Multicast filter table. */
+  RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
+  PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
 };
 
-
 /* Interrupt register bits, using my own meaningful names. */
 enum IntrStatus {
-	TxIdle = 0x40000,
-	RxIdle = 0x20000,
-	IntrSummary = 0x010000,
-	PCIBusErr170 = 0x7000,
-	PCIBusErr175 = 0x1000,
-	PhyEvent175 = 0x8000,
-	RxStarted = 0x0800,
-	RxEarlyWarn = 0x0400,
-	CntFull = 0x0200,
-	TxUnderrun = 0x0100,
-	TxEmpty = 0x0080,
-	TxDone = 0x0020, RxError = 0x0010,
-	RxOverflow = 0x0008,
-	RxFull = 0x0004,
-	RxHeader = 0x0002,
-	RxDone = 0x0001,
+	TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
+	PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
+	RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
+	TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
+	RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
+};
+enum CommandBits {
+	StopRx=1, StartRx=2, TxQueued=4, RxQueued=8,
+	StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
 };
 
+static u16 media2miictl[16] = {
+	0, 0x0C00, 0x0C00, 0x2000,  0x0100, 0x2100, 0, 0,
+	0, 0, 0, 0,  0, 0, 0, 0 };
+
 /* The EPIC100 Rx and Tx buffer descriptors. */
 
 struct epic_tx_desc {
-	s16 status;
-	u16 txlength;
+	u32 txstatus;
 	u32 bufaddr;
-	u16 buflength;
-	u16 control;
+	u32 buflength;
 	u32 next;
 };
 
 struct epic_rx_desc {
-	s16 status;
-	u16 rxlength;
+	u32 rxstatus;
 	u32 bufaddr;
 	u32 buflength;
 	u32 next;
 };
 
-struct epic_private {
-	char devname[8];			/* Used only for kernel debugging. */
-	const char *product_name;
-	struct net_device *next_module;
-	
-	spinlock_t lock;
+enum desc_status_bits {
+	DescOwn=0x8000,
+};
 
-	/* Tx and Rx rings here so that they remain paragraph aligned. */
+
+struct epic_private {
+	/* Tx and Rx rings first so that they remain paragraph aligned. */
 	struct epic_rx_desc rx_ring[RX_RING_SIZE];
 	struct epic_tx_desc tx_ring[TX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -241,16 +269,24 @@
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 
 	/* Ring pointers. */
-	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	spinlock_t lock;				/* Group with Tx control cache line. */
+	unsigned int cur_tx, dirty_tx;
+	struct descriptor  *last_tx_desc;
+
+	unsigned int cur_rx, dirty_rx;
+	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
+	struct descriptor  *last_rx_desc;
+	long last_rx_time;					/* Last Rx, in jiffies. */
 
-	struct pci_dev *pdev;
-	u16 chip_id;
+	struct pci_dev *pci_dev;			/* PCI bus location. */
+	int chip_flags;
 
 	struct net_device_stats stats;
 	struct timer_list timer;			/* Media selection timer. */
+	int tx_threshold;
 	unsigned char mc_filter[8];
 	signed char phys[4];				/* MII device addresses. */
+	int mii_phy_cnt;
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Current duplex setting. */
 	unsigned int force_fd:1;			/* Full-duplex operation requested. */
@@ -258,14 +294,8 @@
 	unsigned int media2:4;				/* Secondary monitored media port. */
 	unsigned int medialock:1;			/* Don't sense media type. */
 	unsigned int mediasense:1;			/* Media sensing in progress. */
-	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
-/* Used to pass the full-duplex flag, etc. */
-#define MAX_UNITS 8
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
 static int epic_open(struct net_device *dev);
 static int read_eeprom(long ioaddr, int location);
 static int mdio_read(long ioaddr, int phy_id, int location);
@@ -282,9 +312,178 @@
 static struct net_device_stats *epic_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 
+
+
+static int __devinit epic_init_one (struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	static int card_idx = -1;
+	static int printed_version = 0;
+	struct net_device *dev;
+	struct epic_private *ep;
+	int i, option = 0, duplex = 0;
+	struct epic_chip_info *ci = &epic_chip_info[ent->driver_data];
+	long ioaddr;
+	int chip_idx = (int) ent->driver_data;
+
+	card_idx++;
+	
+	if (!printed_version++)
+		printk (KERN_INFO "%s" KERN_INFO "%s", version, version2);
+	
+	if ((pci_resource_len(pdev, 0) < ci->io_size) ||
+	    (pci_resource_len(pdev, 1) < ci->io_size)) {
+		printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
+		return -ENODEV;
+	}
+	
+	i = pci_enable_device(pdev);
+	if (i)
+		return i;
+		
+	pci_set_master(pdev);
+
+	dev = init_etherdev(NULL, sizeof (*ep));
+	if (!dev) {
+		printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
+		return -ENOMEM;
+	}
+
+	/* request 100% of both regions 0 and 1, just to make
+	 * sure noone else steals our regions while we are talking
+	 * to them */
+	if (!request_region (pci_resource_start (pdev, 0),
+			     pci_resource_len (pdev, 0), dev->name)) {
+		printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx);
+		goto err_out_free_netdev;
+	}
+	if (!request_mem_region (pci_resource_start (pdev, 1),
+				 pci_resource_len (pdev, 1), dev->name)) {
+		printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx);
+		goto err_out_free_pio;
+	}
 
+#ifdef USE_IO_OPS
+	ioaddr = pci_resource_start (pdev, 0);
+#else
+	ioaddr = pci_resource_start (pdev, 1);
+	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
+	if (!ioaddr) {
+		printk (KERN_ERR PFX "card %d: ioremap failed\n", card_idx);
+		goto err_out_free_mmio;
+	}
+#endif
 
+	if (dev->mem_start) {
+		option = dev->mem_start;
+		duplex = (dev->mem_start & 16) ? 1 : 0;
+	} else if (card_idx >= 0  &&  card_idx < MAX_UNITS) {
+		if (options[card_idx] >= 0)
+			option = options[card_idx];
+		if (full_duplex[card_idx] >= 0)
+			duplex = full_duplex[card_idx];
+	}
+
+	dev->base_addr = ioaddr;
+	dev->irq = pdev->irq;
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
+		   dev->name, ci->name, ioaddr, dev->irq);
+
+	/* Bring the chip out of low-power mode. */
+	outl(0x4200, ioaddr + GENCTL);
+	/* Magic?!  If we don't set this bit the MII interface won't work. */
+	outl(0x0008, ioaddr + TEST1);
+
+	/* Turn on the MII transceiver. */
+	outl(0x12, ioaddr + MIICfg);
+	if (chip_idx == 1)
+		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+	outl(0x0200, ioaddr + GENCTL);
+
+	/* This could also be read from the EEPROM. */
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
+
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x.\n", dev->dev_addr[i]);
+
+	if (debug > 2) {
+		printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
+		for (i = 0; i < 64; i++)
+			printk(" %4.4x%s", read_eeprom(ioaddr, i),
+				   i % 16 == 15 ? "\n" : "");
+	}
+
+	ep = dev->priv;
+	ep->pci_dev = pdev;
+	ep->chip_flags = ci->drv_flags;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	{
+		int phy, phy_idx;
+		for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys);
+			 phy++) {
+			int mii_status = mdio_read(ioaddr, phy, 1);
+			if (mii_status != 0xffff  && mii_status != 0x0000) {
+				ep->phys[phy_idx++] = phy;
+				printk(KERN_INFO "%s: MII transceiver #%d control "
+					   "%4.4x status %4.4x.\n"
+					   KERN_INFO "%s:  Autonegotiation advertising %4.4x "
+					   "link partner %4.4x.\n",
+					   dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status,
+					   dev->name, mdio_read(ioaddr, phy, 4),
+					   mdio_read(ioaddr, phy, 5));
+			}
+		}
+		ep->mii_phy_cnt = phy_idx;
+		if (phy_idx == 0  &&  (ep->chip_flags & NO_MII) == 0) {
+			printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
+				   dev->name);
+			/* Use the known PHY address of the EPII. */
+			ep->phys[0] = 3;
+		}
+	}
+
+	/* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
+	if (ep->chip_flags & MII_PWRDWN)
+		outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
+	outl(0x0008, ioaddr + GENCTL);
 
+	/* The lower four bits are the media type. */
+	ep->force_fd = duplex;
+	dev->if_port = ep->default_port = option;
+	if (ep->default_port)
+		ep->medialock = 1;
+
+	/* The Epic-specific entries in the device structure. */
+	dev->open = &epic_open;
+	dev->hard_start_xmit = &epic_start_xmit;
+	dev->stop = &epic_close;
+	dev->get_stats = &epic_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->tx_timeout = &epic_tx_timeout;
+
+	return 0;
+
+#ifndef USE_IO_OPS
+err_out_free_mmio:
+	release_mem_region (pci_resource_start (pdev, 1),
+			    pci_resource_len (pdev, 1));
+#endif
+err_out_free_pio:
+	release_region (pci_resource_start (pdev, 0),
+			pci_resource_len (pdev, 0));
+err_out_free_netdev:
+	unregister_netdev(dev);
+	kfree(dev);
+	return -ENODEV;
+}
+
 /* Serial EEPROM section. */
 
 /*  EEPROM_Ctrl bits. */
@@ -300,11 +499,7 @@
    No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
  */
 
-#ifdef _LINUX_DELAY_H
-#define eeprom_delay(nanosec)	udelay(1)
-#else
-#define eeprom_delay(nanosec)	do { ; } while (0)
-#endif
+#define eeprom_delay()	inl(ee_addr)
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
@@ -318,7 +513,7 @@
 	int retval = 0;
 	long ee_addr = ioaddr + EECTL;
 	int read_cmd = location |
-		(inl(ee_addr) & 0x40) ? EE_READ64_CMD : EE_READ256_CMD;
+		(inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD);
 
 	outl(EE_ENB & ~EE_CS, ee_addr);
 	outl(EE_ENB, ee_addr);
@@ -327,18 +522,18 @@
 	for (i = 12; i >= 0; i--) {
 		short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0;
 		outl(EE_ENB | dataval, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(150);
+		eeprom_delay();
 	}
 	outl(EE_ENB, ee_addr);
 
 	for (i = 16; i > 0; i--) {
 		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
 		outl(EE_ENB, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 	}
 
 	/* Terminate the EEPROM access. */
@@ -374,23 +569,22 @@
 }
 
 
-static int
-epic_open(struct net_device *dev)
+static int epic_open(struct net_device *dev)
 {
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
-	int mii_reg5;
-	ep->full_duplex = ep->force_fd;
 
-	MOD_INC_USE_COUNT;
+	ep->full_duplex = ep->force_fd;
 
 	/* Soft reset the chip. */
 	outl(0x4001, ioaddr + GENCTL);
 
-	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, EPIC100_MODULE_NAME, dev)) {
+	MOD_INC_USE_COUNT;
+
+	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev)) {
 		MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		return -EAGAIN;
 	}
 
 	epic_init_ring(dev);
@@ -405,30 +599,48 @@
 	   wiring on the Ositech CardBus card.
 	*/
 	outl(0x12, ioaddr + MIICfg);
-	if (ep->chip_id == 6)
+	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
 #if defined(__powerpc__) || defined(__sparc__)		/* Big endian */
+	outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+	inl(ioaddr + GENCTL);
 	outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #else
+	outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+	inl(ioaddr + GENCTL);
 	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #endif
 
 	for (i = 0; i < 3; i++)
-		outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
+		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
 
-	outl(TX_FIFO_THRESH, ioaddr + TxThresh);
+	ep->tx_threshold = TX_FIFO_THRESH;
+	outl(ep->tx_threshold, ioaddr + TxThresh);
 
-	mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
-	if (mii_reg5 != 0xffff) {
-		if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040)
-			ep->full_duplex = 1;
-		else if (! (mii_reg5 & 0x4000))
-			mdio_write(ioaddr, ep->phys[0], 0, 0x1200);
-		if (epic_debug > 1)
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
-				   " register read of %4.4x.\n", dev->name,
-				   ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
+	if (media2miictl[dev->if_port & 15]) {
+		if (ep->mii_phy_cnt)
+			mdio_write(ioaddr, ep->phys[0], 0, media2miictl[dev->if_port&15]);
+		if (dev->if_port == 1) {
+			if (debug > 1)
+				printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
+					   "status %4.4x.\n",
+					   dev->name, mdio_read(ioaddr, ep->phys[0], 1));
+			outl(0x13, ioaddr + MIICfg);
+		}
+	} else {
+		int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
+		if (mii_reg5 != 0xffff) {
+			if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040)
+				ep->full_duplex = 1;
+			else if (! (mii_reg5 & 0x4000))
+				mdio_write(ioaddr, ep->phys[0], 0, 0x1200);
+			if (debug > 1)
+				printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
+					   " register read of %4.4x.\n", dev->name,
+					   ep->full_duplex ? "full" : "half",
+					   ep->phys[0], mii_reg5);
+		}
 	}
 
 	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
@@ -437,26 +649,26 @@
 
 	/* Start the chip's Rx process. */
 	set_rx_mode(dev);
-	outl(0x000A, ioaddr + COMMAND);
+	outl(StartRx | RxQueued, ioaddr + COMMAND);
+
+	netif_start_queue(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone
+	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
+		 | CntFull | TxUnderrun | TxDone | TxEmpty
 		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
 		 ioaddr + INTMASK);
 
-	if (epic_debug > 1)
+	if (debug > 1)
 		printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
 			   "%s-duplex.\n",
 			   dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
 			   ep->full_duplex ? "full" : "half");
 
-	netif_start_queue(dev);
-
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
 	init_timer(&ep->timer);
-	ep->timer.expires = RUN_AT(3*HZ);			/* 3 sec. */
+	ep->timer.expires = jiffies + 3*HZ;
 	ep->timer.data = (unsigned long)dev;
 	ep->timer.function = &epic_timer;				/* timer handler */
 	add_timer(&ep->timer);
@@ -464,7 +676,6 @@
 	return 0;
 }
 
-
 /* Reset the chip to recover from a PCI transaction error.
    This may occur at interrupt time. */
 static void epic_pause(struct net_device *dev)
@@ -477,7 +688,7 @@
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x00000000, ioaddr + INTMASK);
 	/* Stop the chip's Tx and Rx DMA processes. */
-	outw(0x0061, ioaddr + COMMAND);
+	outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND);
 
 	/* Update the error counts. */
 	if (inw(ioaddr + COMMAND) != 0xffff) {
@@ -505,19 +716,20 @@
 	/* Duplicate code from epic_open(). */
 	outl(0x0008, ioaddr + TEST1);
 
-#if defined(__powerpc__)		/* Big endian */
+#if defined(__powerpc__) || defined(__sparc__)		/* Big endian */
 	outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #else
 	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #endif
-	outl(0x12, ioaddr + MIICfg);
-	if (ep->chip_id == 6)
+	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
 	for (i = 0; i < 3; i++)
-		outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
+		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
 
-	outl(TX_FIFO_THRESH, ioaddr + TxThresh);
+	ep->tx_threshold = TX_FIFO_THRESH;
+	outl(ep->tx_threshold, ioaddr + TxThresh);
 	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
 	outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR);
 	outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]),
@@ -525,20 +737,18 @@
 
 	/* Start the chip's Rx process. */
 	set_rx_mode(dev);
-	outl(0x000A, ioaddr + COMMAND);
+	outl(StartRx | RxQueued, ioaddr + COMMAND);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone
+	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
+		 | CntFull | TxUnderrun | TxDone | TxEmpty
 		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
 		 ioaddr + INTMASK);
-
-	netif_start_queue (dev);
-	
 	printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
 		   " interrupt %4.4x.\n",
 			   dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL),
 		   inl(ioaddr + INTSTAT));
+	return;
 }
 
 static void epic_timer(unsigned long data)
@@ -546,17 +756,18 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int next_tick = 0;
-	int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
+	int next_tick = 60*HZ;
+	int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0;
 
-	if (epic_debug > 3) {
-		printk(KERN_DEBUG "%s: Media selection tick, Tx status %8.8x.\n",
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n",
 			   dev->name, inl(ioaddr + TxSTAT));
 		printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x "
 			   "IntStatus %4.4x RxStatus %4.4x.\n",
 			   dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT),
 			   inl(ioaddr + RxSTAT));
 	}
+
 	if (! ep->force_fd  &&  mii_reg5 != 0xffff) {
 		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
 		if (ep->full_duplex != duplex) {
@@ -566,13 +777,10 @@
 				   ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
 			outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
 		}
-		next_tick = 60*HZ;
 	}
 
-	if (next_tick) {
-		ep->timer.expires = RUN_AT(next_tick);
-		add_timer(&ep->timer);
-	}
+	ep->timer.expires = jiffies + next_tick;
+	add_timer(&ep->timer);
 }
 
 static void epic_tx_timeout(struct net_device *dev)
@@ -580,123 +788,122 @@
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (epic_debug > 0) {
+	if (debug > 0) {
 		printk(KERN_WARNING "%s: Transmit timeout using MII device, "
 			   "Tx status %4.4x.\n",
 			   dev->name, inw(ioaddr + TxSTAT));
-		if (epic_debug > 1) {
+		if (debug > 1) {
 			printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
-			 dev->name, ep->dirty_tx, ep->cur_tx);
+				   dev->name, ep->dirty_tx, ep->cur_tx);
 		}
 	}
 	if (inw(ioaddr + TxSTAT) & 0x10) {		/* Tx FIFO underflow. */
 		ep->stats.tx_fifo_errors++;
-		/* Restart the transmit process. */
-		outl(0x0080, ioaddr + COMMAND);
+		outl(RestartTx, ioaddr + COMMAND);
+	} else {
+		epic_restart(dev);
+		outl(TxQueued, dev->base_addr + COMMAND);
 	}
 
-	/* Perhaps stop and restart the chip's Tx processes . */
-	/* Trigger a transmit demand. */
-	outl(0x0004, dev->base_addr + COMMAND);
-
 	dev->trans_start = jiffies;
 	ep->stats.tx_errors++;
-	
-	netif_start_queue (dev);
+	return;
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-epic_init_ring(struct net_device *dev)
+static void epic_init_ring(struct net_device *dev)
 {
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	int i;
 
 	ep->tx_full = 0;
-	ep->cur_rx = ep->cur_tx = 0;
-	ep->dirty_rx = ep->dirty_tx = 0;
+	ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+	ep->dirty_tx = ep->cur_tx = 0;
+	ep->cur_rx = ep->dirty_rx = 0;
+	ep->last_rx_time = jiffies;
+	ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 
+	/* Initialize all Rx descriptors. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		ep->rx_ring[i].status = 0x8000;		/* Owned by Epic chip */
-		ep->rx_ring[i].buflength = PKT_BUF_SZ;
-		{
-			/* Note the receive buffer must be longword aligned.
-			   dev_alloc_skb() provides 16 byte alignment.  But do *not*
-			   use skb_reserve() to align the IP header! */
-			struct sk_buff *skb;
-			skb = dev_alloc_skb(PKT_BUF_SZ);
-			ep->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 */
-			ep->rx_ring[i].bufaddr = virt_to_bus(skb->tail);
-		}
-		ep->rx_ring[i].next = virt_to_bus(&ep->rx_ring[i+1]);
+		ep->rx_ring[i].rxstatus = 0;
+		ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz);
+		ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]);
+		ep->rx_skbuff[i] = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	ep->rx_ring[i-1].next = virt_to_bus(&ep->rx_ring[0]);
+	ep->rx_ring[i-1].next = virt_to_le32desc(&ep->rx_ring[0]);
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz);
+		ep->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
+		ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail);
+		ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
+	}
+	ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	/* The Tx buffer descriptor is filled in as needed, but we
 	   do need to clear the ownership bit. */
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		ep->tx_skbuff[i] = 0;
-		ep->tx_ring[i].status = 0x0000;
-		ep->tx_ring[i].next = virt_to_bus(&ep->tx_ring[i+1]);
+		ep->tx_ring[i].txstatus = 0x0000;
+		ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]);
 	}
-	ep->tx_ring[i-1].next = virt_to_bus(&ep->tx_ring[0]);
+	ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]);
+	return;
 }
 
-static int
-epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct epic_private *ep = (struct epic_private *)dev->priv;
-	int entry;
-	u32 flag;
+	int entry, free_count;
+	u32 ctrl_word;
 
-	netif_stop_queue (dev);
-
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
+	/* Caution: the write order is important here, set the field with the
+	   "ownership" bit last. */
+	spin_lock_irq(&ep->lock);
 
 	/* Calculate the next Tx descriptor entry. */
+	free_count = ep->cur_tx - ep->dirty_tx;
 	entry = ep->cur_tx % TX_RING_SIZE;
 
 	ep->tx_skbuff[entry] = skb;
-	ep->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
-	ep->tx_ring[entry].bufaddr = virt_to_bus(skb->data);
-	ep->tx_ring[entry].buflength = skb->len;
+	ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data);
 
-	/* tx_bytes counting -- Nolan Leake */	
-	ep->stats.tx_bytes += ep->tx_ring[entry].txlength;
-	
-	if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
-	  flag = 0x10; /* No interrupt */
-	} else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) {
-	  flag = 0x14; /* Tx-done intr. */
-	} else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) {
-	  flag = 0x10; /* No Tx-done intr. */
+	if (free_count < TX_RING_SIZE/2) {/* Typical path */
+		ctrl_word = cpu_to_le32(0x100000); /* No interrupt */
+	} else if (free_count == TX_RING_SIZE/2) {
+		ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */
+	} else if (free_count < TX_RING_SIZE - 1) {
+		ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */
 	} else {
-	  /* Leave room for two additional entries. */
-	  flag = 0x14; /* Tx-done intr. */
-	  ep->tx_full = 1;
-	}
+		/* Leave room for an additional entry. */
+		ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */
+		ep->tx_full = 1;
+	}
+	ep->tx_ring[entry].buflength = ctrl_word | cpu_to_le32(skb->len);
+	ep->tx_ring[entry].txstatus =
+		((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16)
+		| cpu_to_le32(DescOwn);
 
-	ep->tx_ring[entry].control = flag;
-	ep->tx_ring[entry].status = 0x8000;	/* Pass ownership to the chip. */
 	ep->cur_tx++;
-	/* Trigger an immediate transmit demand. */
-	outl(0x0004, dev->base_addr + COMMAND);
+	if (ep->tx_full)
+		netif_stop_queue(dev);
 
-	dev->trans_start = jiffies;
+	spin_unlock_irq(&ep->lock);
 
-	if (! ep->tx_full)
-		netif_start_queue (dev);
+	/* Trigger an immediate transmit demand. */
+	outl(TxQueued, dev->base_addr + COMMAND);
 
-	if (epic_debug > 4)
+	dev->trans_start = jiffies;
+	if (debug > 4)
 		printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
 			   "flag %2.2x Tx status %8.8x.\n",
-			   dev->name, (int)skb->len, entry, flag,
+			   dev->name, (int)skb->len, entry, ctrl_word,
 			   inl(dev->base_addr + TxSTAT));
 
 	return 0;
@@ -711,37 +918,43 @@
 	long ioaddr = dev->base_addr;
 	int status, boguscnt = max_interrupt_work;
 
-	spin_lock (&ep->lock);
+	spin_lock(&ep->lock);
 
 	do {
 		status = inl(ioaddr + INTSTAT);
 		/* Acknowledge all of the current interrupt sources ASAP. */
 		outl(status & 0x00007fff, ioaddr + INTSTAT);
 
-		if (epic_debug > 4)
-			printk("%s: interrupt  interrupt=%#8.8x new intstat=%#8.8x.\n",
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: interrupt  interrupt=%#8.8x new "
+				   "intstat=%#8.8x.\n",
 				   dev->name, status, inl(ioaddr + INTSTAT));
 
 		if ((status & IntrSummary) == 0)
 			break;
 
-		if (status & (RxDone | RxStarted | RxEarlyWarn))
+		if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow))
 			epic_rx(dev);
 
 		if (status & (TxEmpty | TxDone)) {
-			int dirty_tx;
+			unsigned int dirty_tx, cur_tx;
 
-			for (dirty_tx = ep->dirty_tx; dirty_tx < ep->cur_tx; dirty_tx++) {
+			/* Note: if this lock becomes a problem we can narrow the locked
+			   region at the cost of occasionally grabbing the lock more
+			   times. */
+			cur_tx = ep->cur_tx;
+			dirty_tx = ep->dirty_tx;
+			for (; cur_tx - dirty_tx > 0; dirty_tx++) {
 				int entry = dirty_tx % TX_RING_SIZE;
-				int txstatus = ep->tx_ring[entry].status;
+				int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
 
-				if (txstatus < 0)
+				if (txstatus & DescOwn)
 					break;			/* It still hasn't been Txed */
 
 				if ( ! (txstatus & 0x0001)) {
 					/* There was an major error, log it. */
 #ifndef final_version
-					if (epic_debug > 1)
+					if (debug > 1)
 						printk("%s: Transmit error, Tx status %8.8x.\n",
 							   dev->name, txstatus);
 #endif
@@ -759,6 +972,7 @@
 #endif
 					ep->stats.collisions += (txstatus >> 8) & 15;
 					ep->stats.tx_packets++;
+					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
 				}
 
 				/* Free the original skb. */
@@ -767,30 +981,23 @@
 			}
 
 #ifndef final_version
-			if (ep->cur_tx - dirty_tx > TX_RING_SIZE) {
+			if (cur_tx - dirty_tx > TX_RING_SIZE) {
 				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, ep->cur_tx, ep->tx_full);
+					   dev->name, dirty_tx, cur_tx, ep->tx_full);
 				dirty_tx += TX_RING_SIZE;
 			}
 #endif
-
-			if (ep->tx_full &&
-			    netif_queue_stopped(dev) &&
-			    dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
+			ep->dirty_tx = dirty_tx;
+			if (ep->tx_full
+				&& cur_tx - dirty_tx < TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				ep->tx_full = 0;
+				netif_wake_queue(dev);
 			}
-			
-			if (ep->tx_full)
-				netif_stop_queue (dev);
-			else
-				netif_wake_queue (dev);
-
-			ep->dirty_tx = dirty_tx;
 		}
 
 		/* Check uncommon events all at once. */
-		if (status & (CntFull | TxUnderrun | RxOverflow |
+		if (status & (CntFull | TxUnderrun | RxOverflow | RxFull |
 					  PCIBusErr170 | PCIBusErr175)) {
 			if (status == 0xffffffff) /* Chip failed or removed (CardBus). */
 				break;
@@ -801,13 +1008,15 @@
 
 			if (status & TxUnderrun) { /* Tx FIFO underflow. */
 				ep->stats.tx_fifo_errors++;
-				outl(1536, ioaddr + TxThresh);
+				outl(ep->tx_threshold += 128, ioaddr + TxThresh);
 				/* Restart the transmit process. */
-				outl(0x0080, ioaddr + COMMAND);
+				outl(RestartTx, ioaddr + COMMAND);
 			}
 			if (status & RxOverflow) {		/* Missed a Rx frame. */
 				ep->stats.rx_errors++;
 			}
+			if (status & (RxOverflow | RxFull))
+				outw(RxQueued, ioaddr + COMMAND);
 			if (status & PCIBusErr170) {
 				printk(KERN_ERR "%s: PCI Bus Error!  EPIC status %4.4x.\n",
 					   dev->name, status);
@@ -827,30 +1036,35 @@
 		}
 	} while (1);
 
-	if (epic_debug > 3)
+	if (debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",
 			   dev->name, inl(ioaddr + INTSTAT));
 
-	spin_unlock (&ep->lock);
+	spin_unlock(&ep->lock);
 }
 
-
 static int epic_rx(struct net_device *dev)
 {
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 	int entry = ep->cur_rx % RX_RING_SIZE;
+	int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
 	int work_done = 0;
 
-	if (epic_debug > 4)
+	if (debug > 4)
 		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
-			   ep->rx_ring[entry].status);
+			   ep->rx_ring[entry].rxstatus);
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (ep->rx_ring[entry].status >= 0  &&  ep->rx_skbuff[entry]) {
-		int status = ep->rx_ring[entry].status;
+	while ( ! le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn) {
+		int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);
 
-		if (epic_debug > 4)
+		if (debug > 4)
 			printk(KERN_DEBUG "  epic_rx() status was %8.8x.\n", status);
+		if (--rx_work_limit < 0)
+			break;
 		if (status & 0x2006) {
+			if (debug > 2)
+				printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n",
+					   dev->name, status);
 			if (status & 0x2000) {
 				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
 					   "multiple buffers, status %4.4x!\n", dev->name, status);
@@ -861,24 +1075,28 @@
 		} else {
 			/* Malloc up new buffer, compatible with net-2e. */
 			/* Omit the four octet CRC from the length. */
-			short pkt_len = ep->rx_ring[entry].rxlength - 4;
+			short pkt_len = (status >> 16) - 4;
 			struct sk_buff *skb;
 
+			if (pkt_len > PKT_BUF_SZ - 4) {
+				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
+					   "%d bytes.\n",
+					   dev->name, pkt_len, status);
+				pkt_len = 1514;
+			}
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if 1 /* USE_IP_COPYSUM */
-				eth_copy_and_sum(skb, bus_to_virt(ep->rx_ring[entry].bufaddr),
-								 pkt_len, 0);
+#if 1 /* HAS_IP_COPYSUM */
+				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);
+				memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,
+					   pkt_len);
 #endif
-				ep->rx_ring[entry].status = 0x8000;
 			} else {
 				skb_put(skb = ep->rx_skbuff[entry], pkt_len);
 				ep->rx_skbuff[entry] = NULL;
@@ -886,7 +1104,6 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			ep->stats.rx_packets++;
-			/* rx_bytes counting -- Nolan Leake */
 			ep->stats.rx_bytes += pkt_len;
 		}
 		work_done++;
@@ -898,20 +1115,19 @@
 		entry = ep->dirty_rx % RX_RING_SIZE;
 		if (ep->rx_skbuff[entry] == NULL) {
 			struct sk_buff *skb;
-			skb = ep->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+			skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);
 			if (skb == NULL)
 				break;
 			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			ep->rx_ring[entry].bufaddr = virt_to_bus(skb->tail);
+			ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail);
 			work_done++;
 		}
-		ep->rx_ring[entry].status = 0x8000;
+		ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);
 	}
 	return work_done;
 }
 
-
 static int epic_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -920,29 +1136,19 @@
 
 	netif_stop_queue(dev);
 
-	if (epic_debug > 1)
+	if (debug > 1)
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 			   dev->name, inl(ioaddr + INTSTAT));
 
-	/* Disable interrupts by clearing the interrupt mask. */
-	outl(0x00000000, ioaddr + INTMASK);
-	/* Stop the chip's Tx and Rx DMA processes. */
-	outw(0x0061, ioaddr + COMMAND);
-
-	/* Update the error counts. */
-	ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-	ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-	ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-
+	epic_pause(dev);
 	del_timer(&ep->timer);
-
 	free_irq(dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb = ep->rx_skbuff[i];
 		ep->rx_skbuff[i] = 0;
-		ep->rx_ring[i].status = 0;		/* Not owned by Epic chip. */
+		ep->rx_ring[i].rxstatus = 0;		/* Not owned by Epic chip. */
 		ep->rx_ring[i].buflength = 0;
 		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
 		if (skb) {
@@ -955,16 +1161,13 @@
 		ep->tx_skbuff[i] = 0;
 	}
 
-
 	/* Green! Leave the chip in low-power mode. */
 	outl(0x0008, ioaddr + GENCTL);
 
 	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
-
 static struct net_device_stats *epic_get_stats(struct net_device *dev)
 {
 	struct epic_private *ep = (struct epic_private *)dev->priv;
@@ -980,7 +1183,6 @@
 	return &ep->stats;
 }
 
-
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
    new frame, not around filling ep->setup_frame.  This is non-deterministic
@@ -1007,7 +1209,6 @@
 	return crc;
 }
 
-
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -1047,7 +1248,6 @@
 	return;
 }
 
-
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	long ioaddr = dev->base_addr;
@@ -1064,7 +1264,7 @@
 		}
 		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
 		if (! netif_running(dev)) {
-#ifdef notdef
+#ifdef notdef					/* Leave on if the ioctl() is used. */
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
 #endif
@@ -1079,7 +1279,7 @@
 		}
 		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 		if (! netif_running(dev)) {
-#ifdef notdef
+#ifdef notdef					/* Leave on if the ioctl() is used. */
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
 #endif
@@ -1091,219 +1291,80 @@
 }
 
 
-static int __devinit epic100_init_one (struct pci_dev *pdev,
-				       const struct pci_device_id *ent)
+static void __devexit epic_remove_one (struct pci_dev *pdev)
 {
-	struct epic_private *ep;
-	int i, option = 0, duplex = 0, irq, chip_idx;
-	struct net_device *dev;
-	long ioaddr;
-	static int card_idx = -1;
-	static int printed_version = 0;
-	
-	if (!printed_version) {
-		printk (KERN_INFO "%s", version);
-		printed_version = 1;
-	}
-	
-	chip_idx = ent->driver_data;
-	
-	ioaddr = pci_resource_start (pdev, 0);
-	if (!ioaddr)
-		return -ENODEV;
-	
-	irq = pdev->irq;
-	if (!irq)
-		return -ENODEV;
-
-	/* We do a request_region() to register /proc/ioports info. */
-	if (!request_region(ioaddr, EPIC_TOTAL_SIZE, EPIC100_MODULE_NAME))
-		return -EBUSY;
-
-	pci_enable_device (pdev);
-
-	/* EPIC-specific code: Soft-reset the chip ere setting as master. */
-	outl(0x0001, ioaddr + GENCTL);
+	struct net_device *dev = pdev->driver_data;
 	
-	pci_set_master (pdev);
-
-// FIXME	if (dev && dev->mem_start) {
-//		option = dev->mem_start;
-//		duplex = (dev->mem_start & 16) ? 1 : 0;
-//	}
-//	else 
-
-	card_idx++;
-	if (card_idx >= 0  &&  card_idx < MAX_UNITS) {
-		if (options[card_idx] >= 0)
-			option = options[card_idx];
-		if (full_duplex[card_idx] >= 0)
-			duplex = full_duplex[card_idx];
-	}
-
-	dev = init_etherdev(NULL, sizeof (*ep));
 	if (!dev)
-		goto err_out_free_region;
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-		   dev->name, epic100_chip_info[chip_idx].name,
-		   ioaddr, dev->irq);
-
-	/* Bring the chip out of low-power mode. */
-	outl(0x4200, ioaddr + GENCTL);
-	/* Magic?!  If we don't set this bit the MII interface won't work. */
-	outl(0x0008, ioaddr + TEST1);
-
-	/* Turn on the MII transceiver. */
-	outl(0x12, ioaddr + MIICfg);
-	if (chip_idx == 1)
-		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-	outl(0x0200, ioaddr + GENCTL);
-
-	/* This could also be read from the EEPROM. */
-	for (i = 0; i < 3; i++)
-		((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
-
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x.\n", dev->dev_addr[i]);
-
-	if (epic_debug > 1) {
-		printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
-		for (i = 0; i < 64; i++)
-			printk(" %4.4x%s", read_eeprom(ioaddr, i),
-				   i % 16 == 15 ? "\n" : "");
-	}
-
-	/* The data structures must be quadword aligned,
-	 * init_etherdev ensures this */
-	ep = dev->priv;
-	memset(ep, 0, sizeof(*ep));
-
-	ep->lock = SPIN_LOCK_UNLOCKED;
-	ep->chip_id = pdev->device;
-	ep->pdev = pdev;
-	pdev->driver_data = dev;
-
-	/* Find the connected MII xcvrs.
-	   Doing this in open() would allow detecting external xcvrs later, but
-	   takes too much time. */
-	{
-		int phy, phy_idx;
-		for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys);
-			 phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
-			if (mii_status != 0xffff  && mii_status != 0x0000) {
-				ep->phys[phy_idx++] = phy;
-				printk(KERN_INFO "%s: MII transceiver #%d control "
-					   "%4.4x status %4.4x.\n"
-					   KERN_INFO "%s:  Autonegotiation advertising %4.4x "
-					   "link partner %4.4x.\n",
-					   dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status,
-					   dev->name, mdio_read(ioaddr, phy, 4),
-					   mdio_read(ioaddr, phy, 5));
-			}
-		}
-		if (phy_idx == 0) {
-			printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
-				   dev->name);
-			/* Use the known PHY address of the EPII. */
-			ep->phys[0] = 3;
-		}
-	}
-
-	/* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
-	if (ep->chip_id == 6)
-		outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
-	outl(0x0008, ioaddr + GENCTL);
-
-	/* The lower four bits are the media type. */
-	ep->force_fd = duplex;
-	ep->default_port = option;
-	if (ep->default_port)
-		ep->medialock = 1;
-
-	/* The Epic-specific entries in the device structure. */
-	dev->open = epic_open;
-	dev->hard_start_xmit = epic_start_xmit;
-	dev->stop = epic_close;
-	dev->get_stats = epic_get_stats;
-	dev->set_multicast_list = set_rx_mode;
-	dev->do_ioctl = mii_ioctl;
-	dev->tx_timeout = epic_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	
-	netif_stop_queue (dev);
-
-	return 0;
-
-err_out_free_region:
-	release_region(ioaddr, EPIC_TOTAL_SIZE);
-	return -ENODEV;
-}
-
-
-static void __devexit epic100_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pdev->driver_data;
+		BUG();
 
 	unregister_netdev(dev);
-	release_region(dev->base_addr, EPIC_TOTAL_SIZE);
+#ifndef USE_IO_OPS
+	iounmap ((void*) dev->base_addr);
+#endif
+	release_mem_region (pci_resource_start (pdev, 1),
+			    pci_resource_len (pdev, 1));
+	release_region (pci_resource_start (pdev, 0),
+			pci_resource_len (pdev, 0));
 	kfree(dev);
 }
 
 
-static void epic100_suspend (struct pci_dev *pdev)
+static void epic_suspend (struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 	long ioaddr = dev->base_addr;
 
+	if (!dev)
+		BUG();
+
 	epic_pause(dev);
 	/* Put the chip into low-power mode. */
 	outl(0x0008, ioaddr + GENCTL);
 }
 
 
-static void epic100_resume (struct pci_dev *pdev)
+static void epic_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 
+	if (!dev)
+		BUG();
+
 	epic_restart (dev);
 }
 
 
-static struct pci_driver epic100_driver = {
+static struct pci_driver epic_driver = {
 	name:		EPIC100_MODULE_NAME,
-	id_table:	epic100_pci_tbl,
-	probe:		epic100_init_one,
-	remove:		epic100_remove_one,
-	suspend:	epic100_suspend,
-	resume:		epic100_resume,
+	id_table:	epic_pci_tbl,
+	probe:		epic_init_one,
+	remove:		epic_remove_one,
+	suspend:	epic_suspend,
+	resume:		epic_resume,
 };
 
 
-static int __init epic100_init (void)
+static int __init epic_init (void)
 {
-	return pci_module_init (&epic100_driver);
+	return pci_module_init (&epic_driver);
 }
 
 
-static void __exit epic100_cleanup (void)
+static void __exit epic_cleanup (void)
 {
-	pci_unregister_driver (&epic100_driver);
+	pci_unregister_driver (&epic_driver);
 }
 
 
-module_init(epic100_init);
-module_exit(epic100_cleanup);
+module_init(epic_init);
+module_exit(epic_cleanup);
 
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c"
+ *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/es3210.c linux/drivers/net/es3210.c
--- v2.3.99-pre6/linux/drivers/net/es3210.c	Thu Nov 11 20:11:40 1999
+++ linux/drivers/net/es3210.c	Thu May  4 11:31:21 2000
@@ -382,10 +382,9 @@
 #ifdef MODULE
 #define MAX_ES_CARDS	4	/* Max number of ES3210 cards per module */
 #define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_ES_CARDS] = { 0, };
 static struct net_device dev_es3210[MAX_ES_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",		/* device name is inserted by net_init.c */
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -407,7 +406,6 @@
 
 	for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
 		struct net_device *dev = &dev_es3210[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];		/* Currently ignored by driver */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.3.99-pre6/linux/drivers/net/eth16i.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/eth16i.c	Tue May  2 12:40:59 2000
@@ -1390,12 +1390,10 @@
 }
 
 #define MAX_ETH16I_CARDS 4  /* Max number of Eth16i cards per module */
-#define NAMELEN          8  /* number of chars for storing dev->name */
 
-static char namelist[NAMELEN * MAX_ETH16I_CARDS] = { 0, };
 static struct net_device dev_eth16i[MAX_ETH16I_CARDS] = {
 	{
-		NULL,
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -1436,7 +1434,6 @@
 	{
 		struct net_device *dev = &dev_eth16i[this_dev];
 	
-		dev->name = namelist + (NAMELEN*this_dev);
 		dev->irq = 0; /* irq[this_dev]; */
 		dev->base_addr = io[this_dev];
 		dev->init = eth16i_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.3.99-pre6/linux/drivers/net/ethertap.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/ethertap.c	Thu May  4 11:31:21 2000
@@ -339,11 +339,9 @@
 static int unit;
 MODULE_PARM(unit,"i");
 
-static char devicename[9] = { 0, };
-
 static struct net_device dev_ethertap =
 {
-	devicename,
+	" ",
 	0, 0, 0, 0,
 	1, 5,
 	0, 0, 0, NULL, ethertap_probe
@@ -352,10 +350,10 @@
 int init_module(void)
 {
 	dev_ethertap.base_addr=unit+NETLINK_TAPBASE;
-	sprintf(devicename,"tap%d",unit);
-	if (dev_get(devicename))
+	sprintf(dev_ethertap.name,"tap%d",unit);
+	if (dev_get(dev_ethertap.name))
 	{
-		printk(KERN_INFO "%s already loaded.\n", devicename);
+		printk(KERN_INFO "%s already loaded.\n", dev_ethertap.name);
 		return -EBUSY;
 	}
 	if (register_netdev(&dev_ethertap) != 0)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.3.99-pre6/linux/drivers/net/ewrk3.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/ewrk3.c	Thu May  4 11:31:21 2000
@@ -1409,7 +1409,6 @@
 		new->next = dev->next;
 		dev->next = new;
 		dev = dev->next;	/* point to the new device */
-		dev->name = (char *) (dev + 1);
 		if (num_eth > 9999) {
 			sprintf(dev->name, "eth????");	/* New device name */
 		} else {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/6pack.c	Sat Feb 26 22:31:47 2000
+++ linux/drivers/net/hamradio/6pack.c	Thu May  4 11:31:21 2000
@@ -51,7 +51,6 @@
 
 
 typedef struct sixpack_ctrl {
-	char		if_name[8];	/* "sp0\0" .. "sp99999\0"	*/
 	struct sixpack	ctrl;		/* 6pack things			*/
 	struct net_device	dev;		/* the device			*/
 } sixpack_ctrl_t;
@@ -107,8 +106,7 @@
 		/* Initialize channel control data */
 		set_bit(SIXPF_INUSE, &spp->ctrl.flags);
 		spp->ctrl.tty         = NULL;
-		sprintf(spp->if_name, "sp%d", i);
-		spp->dev.name         = spp->if_name;
+		sprintf(spp->dev.name, "sp%d", i);
 		spp->dev.base_addr    = i;
 		spp->dev.priv         = (void*)&(spp->ctrl);
 		spp->dev.next         = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/baycom_epp.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/hamradio/baycom_epp.c	Thu May  4 11:31:21 2000
@@ -200,8 +200,6 @@
 	unsigned int bitrate;
 	unsigned char stat;
 
-	char ifname[HDLCDRV_IFNAMELEN];
-
 	struct {
 		unsigned int intclk;
 		unsigned int fclk;
@@ -444,7 +442,7 @@
 {
 
 #ifdef KISS_VERBOSE
-#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", bc->ifname, b)
+#define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b)
 #else /* KISS_VERBOSE */	      
 #define PKP(a,b) 
 #endif /* KISS_VERBOSE */	      
@@ -702,7 +700,7 @@
 		return;
 	pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */
 	if (!(skb = dev_alloc_skb(pktlen))) {
-		printk("%s: memory squeeze, dropping packet\n", bc->ifname);
+		printk("%s: memory squeeze, dropping packet\n", dev->name);
 		bc->stats.rx_dropped++;
 		return;
 	}
@@ -1450,20 +1448,19 @@
 		 */
 		memset(bc, 0, sizeof(struct baycom_state));
 		bc->magic = BAYCOM_MAGIC;
-		sprintf(bc->ifname, "bce%d", i);
+		sprintf(dev->name, "bce%d", i);
 		bc->cfg.fclk = 19666600;
 		bc->cfg.bps = 9600;
 		/*
 		 * initialize part of the device struct
 		 */
-		dev->name = bc->ifname;
 		dev->if_port = 0;
 		dev->init = baycom_probe;
 		dev->base_addr = iobase[i];
 		dev->irq = 0;
 		dev->dma = 0;
 		if (register_netdev(dev)) {
-			printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, bc->ifname);
+			printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name);
 			kfree(dev->priv);
 			return -ENXIO;
 		}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/baycom_par.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/baycom_par.c	Thu May  4 11:31:21 2000
@@ -505,7 +505,6 @@
 	int i, j, found = 0;
 	char set_hw = 1;
 	struct baycom_state *bc;
-	char ifname[HDLCDRV_IFNAMELEN];
 
 	printk(bc_drvinfo);
 	/*
@@ -513,14 +512,14 @@
 	 */
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = baycom_device+i;
-		sprintf(ifname, "bcp%d", i);
+		sprintf(dev->name, "bcp%d", i);
 
 		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
 			iobase[i] = 0;
 		j = hdlcdrv_register_hdlcdrv(dev, &par96_ops, sizeof(struct baycom_state),
-					     ifname, iobase[i], 0, 0);
+					     dev->name, iobase[i], 0, 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
 			if (set_hw && baycom_setmode(bc, mode[i]))
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/baycom_ser_fdx.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/baycom_ser_fdx.c	Thu May  4 11:31:21 2000
@@ -621,8 +621,6 @@
 	int i, j, found = 0;
 	char set_hw = 1;
 	struct baycom_state *bc;
-	char ifname[HDLCDRV_IFNAMELEN];
-
 
 	printk(bc_drvinfo);
 	/*
@@ -630,14 +628,14 @@
 	 */
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = baycom_device+i;
-		sprintf(ifname, "bcsf%d", i);
+		sprintf(dev->name, "bcsf%d", i);
 
 		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
 			iobase[i] = irq[i] = 0;
 		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
-					     ifname, iobase[i], irq[i], 0);
+					     dev->name, iobase[i], irq[i], 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
 			if (set_hw && baycom_setmode(bc, mode[i]))
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/baycom_ser_hdx.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/baycom_ser_hdx.c	Thu May  4 11:31:21 2000
@@ -661,8 +661,6 @@
 	int i, j, found = 0;
 	char set_hw = 1;
 	struct baycom_state *bc;
-	char ifname[HDLCDRV_IFNAMELEN];
-
 
 	printk(bc_drvinfo);
 	/*
@@ -670,14 +668,14 @@
 	 */
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = baycom_device+i;
-		sprintf(ifname, "bcsh%d", i);
+		sprintf(dev->name, "bcsh%d", i);
 
 		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
 			iobase[i] = irq[i] = 0;
 		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
-					     ifname, iobase[i], irq[i], 0);
+					     dev->name, iobase[i], irq[i], 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
 			if (set_hw && baycom_setmode(bc, mode[i]))
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/bpqether.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/bpqether.c	Thu May  4 11:31:21 2000
@@ -496,7 +496,6 @@
 static int bpq_new_device(struct net_device *dev)
 {
 	int k;
-	unsigned char *buf;
 	struct bpqdev *bpq, *bpq2;
 
 	if ((bpq = kmalloc(sizeof(struct bpqdev), GFP_KERNEL)) == NULL)
@@ -513,14 +512,13 @@
 	memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr));
 
 	dev = &bpq->axdev;
-	buf = kmalloc(14, GFP_KERNEL);
 
 	for (k = 0; k < MAXBPQDEV; k++) {
 		struct net_device *odev;
 
-		sprintf(buf, "bpq%d", k);
+		sprintf(dev->name, "bpq%d", k);
 
-		if ((odev = __dev_get_by_name(buf)) == NULL || bpq_check_devices(odev))
+		if ((odev = __dev_get_by_name(dev->name)) == NULL || bpq_check_devices(odev))
 			break;
 	}
 
@@ -530,7 +528,6 @@
 	}
 
 	dev->priv = (void *)bpq;	/* pointer back */
-	dev->name = buf;
 	dev->init = bpq_dev_init;
 
 	/* We should be locked, call register_netdevice() directly. */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/dmascc.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/hamradio/dmascc.c	Thu May  4 11:31:21 2000
@@ -211,7 +211,6 @@
 };
 
 struct scc_priv {
-  char name[10];
   struct enet_statistics stats;
   struct scc_info *info;
   int channel;
@@ -553,7 +552,6 @@
   for (i = 0; i < 2; i++) {
     dev = &info->dev[i];
     priv = &info->priv[i];
-    sprintf(priv->name, "dmascc%i", 2*n+i);
     priv->info = info;
     priv->channel = i;
     priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD);
@@ -571,7 +569,7 @@
     priv->rx_task.routine = rx_bh;
     priv->rx_task.data = dev;
     dev->priv = priv;
-    dev->name = priv->name;
+    sprintf(dev->name, "dmascc%i", 2*n+i);
     dev->base_addr = io;
     dev->irq = irq;
     dev->open = scc_open;
@@ -593,7 +591,6 @@
     dev_init_buffers(dev);
     if (register_netdevice(dev)) {
       printk("dmascc: could not register %s\n", dev->name);
-      dev->name = NULL;
     }
   }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/hdlcdrv.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/hdlcdrv.c	Thu May  4 11:31:21 2000
@@ -217,8 +217,7 @@
 		return;
 	pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */
 	if (!(skb = dev_alloc_skb(pkt_len))) {
-		printk("%s: memory squeeze, dropping packet\n", 
-		       s->ifname);
+		printk("%s: memory squeeze, dropping packet\n", dev->name);
 		s->stats.rx_dropped++;
 		return;
 	}
@@ -293,7 +292,7 @@
 {
 
 #ifdef KISS_VERBOSE
-#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", s->ifname, b)
+#define PKP(a,b) printk(KERN_INFO "hdlcdrv.c: channel params: " a "\n", b)
 #else /* KISS_VERBOSE */	      
 #define PKP(a,b) 
 #endif /* KISS_VERBOSE */	      
@@ -840,12 +839,11 @@
 	 */
 	memset(s, 0, privsize);
 	s->magic = HDLCDRV_MAGIC;
-	strncpy(s->ifname, ifname, sizeof(s->ifname));
+	strncpy(dev->name, ifname, sizeof(dev->name));
 	s->ops = ops;
 	/*
 	 * initialize part of the device struct
 	 */
-	dev->name = s->ifname;
 	dev->if_port = 0;
 	dev->init = hdlcdrv_probe;
 	dev->base_addr = baseaddr;
@@ -853,7 +851,7 @@
 	dev->dma = dma;
 	if (register_netdev(dev)) {
 		printk(KERN_WARNING "hdlcdrv: cannot register net "
-		       "device %s\n", s->ifname);
+		       "device %s\n", dev->name);
 		kfree(dev->priv);
 		return -ENXIO;
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/mkiss.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/hamradio/mkiss.c	Thu May  4 11:31:21 2000
@@ -73,7 +73,6 @@
 };
 
 typedef struct ax25_ctrl {
-	char if_name[8];	/* "ax0\0" .. "ax99999\0"	*/
 	struct ax_disp ctrl;	/* 				*/
 	struct net_device  dev;	/* the device			*/
 } ax25_ctrl_t;
@@ -200,9 +199,8 @@
 
 		/* Initialize channel control data */
 		set_bit(AXF_INUSE, &axp->ctrl.flags);
-		sprintf(axp->if_name, "ax%d", i++);
+		sprintf(axp->dev.name, "ax%d", i++);
 		axp->ctrl.tty      = NULL;
-		axp->dev.name      = axp->if_name;
 		axp->dev.base_addr = i;
 		axp->dev.priv      = (void *)&axp->ctrl;
 		axp->dev.next      = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/scc.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/scc.c	Thu May  4 11:31:21 2000
@@ -1554,7 +1554,6 @@
 
 static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev)
 {
-	unsigned char *buf;
 	struct net_device *dev;
 
 	if (dev_get(name))
@@ -1569,13 +1568,8 @@
 	dev = scc->dev;
 	memset(dev, 0, sizeof(struct net_device));
 
-	if ((buf = (unsigned char *) kmalloc(10, GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-
-	strcpy(buf, name);
-
+	strcpy(dev->name, name);
 	dev->priv = (void *) scc;
-	dev->name = buf;
 	dev->init = scc_net_init;
 
 	if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/soundmodem/sm.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Thu May  4 11:31:21 2000
@@ -278,7 +278,7 @@
 
 /* --------------------------------------------------------------------- */
 
-static void sm_output_open(struct sm_state *sm)
+static void sm_output_open(struct sm_state *sm, const char *ifname)
 {
 	enum uart u = c_uart_unknown;
 	struct parport *pp = NULL;
@@ -306,7 +306,7 @@
 		else if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT))
 			printk(KERN_WARNING "%s: parport at address 0x%x cannot be used\n", sm_drvname, sm->hdrv.ptt_out.pariobase);
 		else {
-			sm->pardev = parport_register_device(pp, sm->hdrv.ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+			sm->pardev = parport_register_device(pp, ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 			if (!sm->pardev) {
 				pp = NULL;
 				printk(KERN_WARNING "%s: cannot register parport device (address 0x%x)\n", sm_drvname, sm->hdrv.ptt_out.pariobase);
@@ -393,7 +393,7 @@
 	err = sm->hwdrv->open(dev, sm);
 	if (err)
 		return err;
-	sm_output_open(sm);
+	sm_output_open(sm, dev->name);
 	MOD_INC_USE_COUNT;
 	printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n",
 	       sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name,
@@ -641,7 +641,6 @@
 	int i, j, found = 0;
 	char set_hw = 1;
 	struct sm_state *sm;
-	char ifname[HDLCDRV_IFNAMELEN];
 
 	printk(sm_drvinfo);
 	/*
@@ -649,7 +648,7 @@
 	 */
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = sm_device+i;
-		sprintf(ifname, "sm%d", i);
+		sprintf(dev->name, "sm%d", i);
 
 		if (!mode[i])
 			set_hw = 0;
@@ -672,7 +671,7 @@
 		}
 		if (!set_hw)
 			iobase[i] = irq[i] = 0;
-		j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), ifname, iobase[i], irq[i], dma[i]);
+		j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), dev->name, iobase[i], irq[i], dma[i]);
 		if (!j) {
 			sm = (struct sm_state *)dev->priv;
 			sm->hdrv.ptt_out.dma2 = dma2[i];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.3.99-pre6/linux/drivers/net/hamradio/yam.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/yam.c	Thu May  4 11:31:21 2000
@@ -116,7 +116,6 @@
 	int iobase;
 	int irq;
 	int dupmode;
-	char name[16];
 
 	struct net_device dev;
 
@@ -793,7 +792,7 @@
 	for (i = 0; i < NR_PORTS; i++) {
 		if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
 			continue;
-		len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
+		len += sprintf(buffer + len, "Device yam%d\n", i);
 		len += sprintf(buffer + len, "  Up       %d\n", netif_running(&yam_ports[i].dev));
 		len += sprintf(buffer + len, "  Speed    %u\n", yam_ports[i].bitrate);
 		len += sprintf(buffer + len, "  IoBase   0x%x\n", yam_ports[i].iobase);
@@ -1148,7 +1147,7 @@
 	memset(yam_ports, 0, sizeof(yam_ports));
 
 	for (i = 0; i < NR_PORTS; i++) {
-		sprintf(yam_ports[i].name, "yam%d", i);
+		sprintf(yam_ports[i].dev.name, "yam%d", i);
 		yam_ports[i].magic = YAM_MAGIC;
 		yam_ports[i].bitrate = DEFAULT_BITRATE;
 		yam_ports[i].baudrate = DEFAULT_BITRATE * 2;
@@ -1164,7 +1163,6 @@
 		dev = &yam_ports[i].dev;
 
 		dev->priv = &yam_ports[i];
-		dev->name = yam_ports[i].name;
 		dev->base_addr = yam_ports[i].iobase;
 		dev->irq = yam_ports[i].irq;
 		dev->init = yam_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v2.3.99-pre6/linux/drivers/net/hp-plus.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/hp-plus.c	Tue May  2 12:40:59 2000
@@ -414,11 +414,9 @@
 
 #ifdef MODULE
 #define MAX_HPP_CARDS	4	/* Max number of HPP cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_HPP_CARDS] = { 0, };
 static struct net_device dev_hpp[MAX_HPP_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -440,7 +438,6 @@
 
 	for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
 		struct net_device *dev = &dev_hpp[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = hp_plus_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v2.3.99-pre6/linux/drivers/net/hp.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/hp.c	Tue May  2 12:40:59 2000
@@ -385,11 +385,9 @@
 
 #ifdef MODULE
 #define MAX_HP_CARDS	4	/* Max number of HP cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_HP_CARDS] = { 0, };
 static struct net_device dev_hp[MAX_HP_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -411,7 +409,6 @@
 
 	for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
 		struct net_device *dev = &dev_hp[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = hp_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.3.99-pre6/linux/drivers/net/hp100.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/hp100.c	Tue May  2 12:40:59 2000
@@ -3123,10 +3123,7 @@
 MODULE_PARM(hp100_port, "1-5i");
 #endif
 
-#ifdef LINUX_2_1
-char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
-MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
-#else
+#ifndef LINUX_2_1
 static char devname[5][IFNAMSIZ] = { "", "", "", "", "" };
 static char *hp100_name[5] = { devname[0], devname[1],
                                devname[2], devname[3],
@@ -3162,7 +3159,9 @@
       /* Create device and set basics args */
       hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL);
       memset(hp100_devlist[i], 0x00, sizeof(struct net_device));
+#ifndef LINUX_2_1
       hp100_devlist[i]->name = hp100_name[i];
+#endif
       hp100_devlist[i]->base_addr = hp100_port[i];
       hp100_devlist[i]->init = &hp100_probe;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.3.99-pre6/linux/drivers/net/lance.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/lance.c	Wed May  3 01:45:18 2000
@@ -290,7 +290,6 @@
 
 #ifdef MODULE
 #define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
-#define IF_NAMELEN		8	/* # of chars for storing dev->name */
 
 static int io[MAX_CARDS] = { 0, };
 static int dma[MAX_CARDS] = { 0, };
@@ -300,10 +299,9 @@
 MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
 
-static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
 static struct net_device dev_lance[MAX_CARDS] =
 {{
-    0, /* device name is inserted by linux/drivers/net/net_init.c */
+    "", /* device name is inserted by linux/drivers/net/net_init.c */
 	0, 0, 0, 0,
 	0, 0,
 	0, 0, 0, NULL, NULL}};
@@ -314,7 +312,6 @@
 
 	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
 		struct net_device *dev = &dev_lance[this_dev];
-		dev->name = ifnames[this_dev];
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->dma = dma[this_dev];
@@ -1160,7 +1157,6 @@
 {
 	int ioaddr = dev->base_addr;
 	struct lance_private *lp = (struct lance_private *)dev->priv;
-	int i;
 
 	netif_stop_queue (dev);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/lne390.c linux/drivers/net/lne390.c
--- v2.3.99-pre6/linux/drivers/net/lne390.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/lne390.c	Tue May  2 12:40:59 2000
@@ -372,11 +372,9 @@
 
 #ifdef MODULE
 #define MAX_LNE_CARDS	4	/* Max number of LNE390 cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_LNE_CARDS] = { 0, };
 static struct net_device dev_lne[MAX_LNE_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -397,7 +395,6 @@
 
 	for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
 		struct net_device *dev = &dev_lne[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.3.99-pre6/linux/drivers/net/ne.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/ne.c	Tue May  2 12:40:59 2000
@@ -807,10 +807,9 @@
 #ifdef MODULE
 #define MAX_NE_CARDS	4	/* Max number of NE cards per module */
 #define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_NE_CARDS] = { 0, };
 static struct net_device dev_ne[MAX_NE_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -840,7 +839,6 @@
 
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ne[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->mem_end = bad[this_dev];
 		dev->base_addr = io[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.3.99-pre6/linux/drivers/net/ne2.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/ne2.c	Tue May  2 12:40:59 2000
@@ -619,11 +619,9 @@
 
 #ifdef MODULE
 #define MAX_NE_CARDS	4	/* Max number of NE cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_NE_CARDS] = { 0, };
 static struct net_device dev_ne[MAX_NE_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -648,7 +646,6 @@
 
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ne[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->mem_end = bad[this_dev];
 		dev->base_addr = io[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.3.99-pre6/linux/drivers/net/ne2k-pci.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/ne2k-pci.c	Fri Apr 28 23:00:05 2000
@@ -189,10 +189,8 @@
 	}
 	
 	i = pci_enable_device (pdev);
-	if (i) {
-		printk (KERN_ERR "ne2k-pci: cannot enable device\n");
+	if (i)
 		return i;
-	}
 	
 	if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
 		printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
@@ -567,7 +565,6 @@
 {
 	int rc;
 	
-	MOD_INC_USE_COUNT;
 	lock_8390_module();
 	
 	rc = pci_module_init (&ne2k_driver);
@@ -576,8 +573,6 @@
 	if (rc <= 0)
 		unlock_8390_module();
 
-	MOD_DEC_USE_COUNT;
-	
 	return rc;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ne3210.c linux/drivers/net/ne3210.c
--- v2.3.99-pre6/linux/drivers/net/ne3210.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/ne3210.c	Tue May  2 12:40:59 2000
@@ -363,11 +363,9 @@
 
 #ifdef MODULE
 #define MAX_NE3210_CARDS	4	/* Max number of NE3210 cards per module */
-#define NAMELEN			8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_NE3210_CARDS] = { 0, };
 static struct net_device dev_ne3210[MAX_NE3210_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -388,7 +386,6 @@
 
 	for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ne3210[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.3.99-pre6/linux/drivers/net/net_init.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/net_init.c	Wed May  3 01:45:19 2000
@@ -74,7 +74,7 @@
 	int alloc_size;
 
 	/* ensure 32-byte alignment of the private area */
-	alloc_size = sizeof (*dev) + IFNAMSIZ + sizeof_priv + 31;
+	alloc_size = sizeof (*dev) + sizeof_priv + 31;
 
 	dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
 	if (dev == NULL)
@@ -88,7 +88,6 @@
 	if (sizeof_priv)
 		dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
 
-	dev->name = sizeof_priv + 31 + (char *)(dev + 1);
 	return dev;
 }
 
@@ -116,7 +115,7 @@
 	 *	Allocate a name
 	 */
 	 
-	if (dev->name && (dev->name[0] == '\0' || dev->name[0] == ' '))
+	if (dev->name[0] == '\0' || dev->name[0] == ' ')
 	{
 		if(dev_alloc_name(dev, mask)<0)
 		{
@@ -155,8 +154,7 @@
  * alignment is enforced for this private data area.
  *
  * If an empty string area is passed as dev->name, or a new structure is made,
- * a new name string is constructed.  The passed string area should be 8 bytes
- * long.
+ * a new name string is constructed.
  */
 
 struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv)
@@ -413,7 +411,7 @@
 	 *	do a name allocation
 	 */
 	 
-	if (dev->name && strchr(dev->name, '%'))
+	if (strchr(dev->name, '%'))
 	{
 		err = -EBUSY;
 		if(dev_alloc_name(dev, dev->name)<0)
@@ -424,7 +422,7 @@
 	 *	Back compatibility hook. Kill this one in 2.5
 	 */
 	
-	if (dev->name && (dev->name[0]==0 || dev->name[0]==' '))
+	if (dev->name[0]==0 || dev->name[0]==' ')
 	{
 		err = -EBUSY;
 		if(dev_alloc_name(dev, "eth%d")<0)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c
--- v2.3.99-pre6/linux/drivers/net/ni5010.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/ni5010.c	Tue May  2 12:40:59 2000
@@ -741,9 +741,8 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
 static struct net_device dev_ni5010 = {
-        devicename,
+        "",
         0, 0, 0, 0,
         0, 0,
         0, 0, 0, NULL, ni5010_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.3.99-pre6/linux/drivers/net/ni52.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/ni52.c	Tue May  2 12:40:59 2000
@@ -1277,9 +1277,8 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
 static struct net_device dev_ni52 = {
-	devicename,	/* "ni5210": device name inserted by net_init.c */
+	"",	/* device name inserted by net_init.c */
 	0, 0, 0, 0,
 	0x300, 9,	 /* I/O address, IRQ */
 	0, 0, 0, NULL, ni52_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.3.99-pre6/linux/drivers/net/ni65.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/ni65.c	Tue May  2 12:40:59 2000
@@ -1173,10 +1173,8 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
-
 static struct net_device dev_ni65 = {
-	devicename,	/* "ni6510": device name inserted by net_init.c */
+	"",	/* "ni6510": device name inserted by net_init.c */
 	0, 0, 0, 0,
 	0x360, 9,	 /* I/O address, IRQ */
 	0, 0, 0, NULL, ni65_probe };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/3c574_cs.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/pcmcia/3c574_cs.c	Mon May  8 21:26:05 2000
@@ -205,7 +205,6 @@
 	u_short media_status;
 	u_short fast_poll;
 	u_long last_irq;
-	spinlock_t lock;
 };
 
 /* Set iff a MII transceiver on any interface requires mdio preamble.
@@ -245,9 +244,9 @@
 static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev, int worklimit);
 static int el3_close(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
-static void el3_tx_timeout(struct net_device *dev);
 
 static dev_info_t dev_info = "3c574_cs";
 
@@ -277,16 +276,6 @@
 }
 
 /*
-   We never need to do anything when a tc574 device is "initialized"
-   by the net software, because we only register already-found cards.
-*/
-
-static int tc574_init(struct net_device *dev)
-{
-	return 0;
-}
-
-/*
 	tc574_attach() creates an "instance" of the driver, allocating
 	local data structures for one device.  The device is registered
 	with Card Services.
@@ -307,8 +296,6 @@
 	lp = kmalloc(sizeof(*lp), GFP_KERNEL);
 	if (!lp) return NULL;
 	memset(lp, 0, sizeof(*lp));
-	
-	lp->lock = SPIN_LOCK_UNLOCKED;
 	link = &lp->link; dev = &lp->dev;
 	link->priv = dev->priv = link->irq.Instance = lp;
 	
@@ -336,15 +323,11 @@
 	dev->do_ioctl = &el3_ioctl;
 	dev->set_multicast_list = &set_rx_mode;
 	ether_setup(dev);
-	dev->name = lp->node.dev_name;
-	dev->init = &tc574_init;
 	dev->open = &el3_open;
 	dev->stop = &el3_close;
 	dev->tx_timeout = el3_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	
-	netif_start_queue (dev);
-
 	/* Register with Card Services */
 	link->next = dev_list;
 	dev_list = link;
@@ -380,7 +363,6 @@
 {
 	struct el3_private *lp = link->priv;
 	dev_link_t **linkp;
-	long flags;
 
 	DEBUG(0, "3c574_detach(0x%p)\n", link);
 
@@ -390,13 +372,7 @@
 	if (*linkp == NULL)
 	return;
 
-	spin_lock_irqsave(&lp->lock, flags);
-	if (link->state & DEV_RELEASE_PENDING) {
-		del_timer(&link->release);
-		link->state &= ~DEV_RELEASE_PENDING;
-	}
-	spin_unlock_irqrestore(&lp->lock, flags);
-
+	del_timer(&link->release);
 	if (link->state & DEV_CONFIG) {
 		tc574_release((u_long)link);
 		if (link->state & DEV_STALE_CONFIG) {
@@ -472,16 +448,15 @@
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
 
-	netif_start_queue (dev);
 	if (register_netdev(dev) != 0) {
 		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
 		goto failed;
 	}
 
-	link->state &= ~DEV_CONFIG_PENDING;
-
 	ioaddr = dev->base_addr;
+	strcpy(lp->node.dev_name, dev->name);
 	link->dev = &lp->node;
+	link->state &= ~DEV_CONFIG_PENDING;
 
 	/* The 3c574 normally uses an EEPROM for configuration info, including
 	   the hardware address.  The future products may include a modem chip
@@ -603,7 +578,7 @@
 	CardServices(ReleaseIO, link->handle, &link->io);
 	CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-	link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+	link->state &= ~DEV_CONFIG;
 
 } /* tc574_release */
 
@@ -628,8 +603,7 @@
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
 			netif_device_detach(dev);
-			link->release.expires = jiffies + HZ/20;
-			add_timer(&link->release);
+			mod_timer(&link->release, jiffies + HZ/20);
 		}
 		break;
 	case CS_EVENT_CARD_INSERTION:
@@ -643,7 +617,6 @@
 		if (link->state & DEV_CONFIG) {
 			if (link->open)
 				netif_device_detach(dev);
-
 			CardServices(ReleaseConfiguration, link->handle);
 		}
 		break;
@@ -860,7 +833,7 @@
 	
 	link->open++;
 	MOD_INC_USE_COUNT;
-	netif_start_queue (dev);
+	netif_start_queue(dev);
 	
 	tc574_reset(dev);
 	lp->media.function = &media_check;
@@ -886,7 +859,7 @@
 	/* Issue TX_RESET and TX_START commands. */
 	wait_for_completion(dev, TxReset);
 	outw(TxEnable, ioaddr + EL3_CMD);
-	netif_start_queue (dev);
+	netif_start_queue(dev);
 }
 
 static void pop_tx_status(struct net_device *dev)
@@ -928,12 +901,12 @@
 
 	/* TxFree appears only in Window 1, not offset 0x1c. */
 	if (inw(ioaddr + TxFree) <= 1536) {
-		netif_stop_queue (dev);
+		netif_stop_queue(dev);
 		/* Interrupt us when the FIFO has room for max-sized packet. 
 		   The threshold is in units of dwords. */
 		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
 	}
-	
+
 	dev_kfree_skb (skb);
 	pop_tx_status(dev);
 
@@ -948,11 +921,8 @@
 	ioaddr_t ioaddr, status;
 	int work_budget = max_interrupt_work;
 
-    if (!netif_device_present(dev))
+	if (!netif_device_present(dev))
 		return;
-
-	spin_lock (&lp->lock);
-
 	ioaddr = dev->base_addr;
 
 	DEBUG(3, "%s: interrupt, status %4.4x.\n",
@@ -960,8 +930,8 @@
 
 	while ((status = inw(ioaddr + EL3_STATUS)) &
 		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
-
-		if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) {
+		if (!netif_device_present(dev) ||
+			((status & 0xe000) != 0x2000)) {
 			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
 			break;
 		}
@@ -973,7 +943,7 @@
 			DEBUG(3, "  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 & TxComplete)
@@ -1022,8 +992,7 @@
 
 	DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
 		  dev->name, inw(ioaddr + EL3_STATUS));
-
-	spin_unlock (&lp->lock);
+	return;
 }
 
 /*
@@ -1038,8 +1007,8 @@
     ioaddr_t ioaddr = dev->base_addr;
     u_long flags;
 	u_short /* cable, */ media, partner;
-	
-    if (!netif_device_present(dev))
+
+	if (!netif_device_present(dev))
 		goto reschedule;
 	
     /* Check for pending interrupt with expired latency timer: with
@@ -1123,7 +1092,7 @@
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	ioaddr_t ioaddr = dev->base_addr;
-	u8 upper_cnt;
+	u8 rx, tx, up;
 
 	DEBUG(2, "%s: updating the statistics.\n", dev->name);
 
@@ -1140,22 +1109,19 @@
 	lp->stats.tx_window_errors		+= inb(ioaddr + 4);
 	lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
 	lp->stats.tx_packets			+= inb(ioaddr + 6);
-	upper_cnt 						 = inb(ioaddr + 9);
-	lp->stats.tx_packets			+= (upper_cnt&0x30) << 4;
-	/* Rx packets   */				inb(ioaddr + 7);
-	/* Tx deferrals */				inb(ioaddr + 8);
-	lp->stats.rx_bytes 				+= inw(ioaddr + 10);
-	lp->stats.tx_bytes				+= inw(ioaddr + 12);
+	up		 						 = inb(ioaddr + 9);
+	lp->stats.tx_packets			+= (up&0x30) << 4;
+	/* Rx packets   */				   inb(ioaddr + 7);
+	/* Tx deferrals */				   inb(ioaddr + 8);
+	rx		 						 = inw(ioaddr + 10);
+	tx								 = inw(ioaddr + 12);
 
-	/* With Vortex and later we must also clear the BadSSD counter. */
 	EL3WINDOW(4);
-	inb(ioaddr + 12);
+	/* BadSSD */					   inb(ioaddr + 12);
+	up								 = inb(ioaddr + 13);
 
-	{
-		u8 up = inb(ioaddr + 13);
-		lp->stats.rx_bytes += (up & 0x0f) << 16;
-		lp->stats.tx_bytes += (up & 0xf0) << 12;
-	}
+	lp->stats.rx_bytes += rx + ((up & 0x0f) << 16);
+	lp->stats.tx_bytes += tx + ((up & 0xf0) << 12);
 
 	EL3WINDOW(1);
 }
@@ -1290,8 +1256,6 @@
 
 	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
 	
-	netif_stop_queue (dev);
-	
 	if (DEV_OK(link)) {
 		/* Turn off statistics ASAP.  We update lp->stats below. */
 		outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1307,12 +1271,10 @@
 	}
 
 	link->open--;
+	netif_stop_queue(dev);
 	del_timer(&lp->media);
-	if (link->state & DEV_STALE_CONFIG) {
-		link->release.expires = jiffies + HZ/20;
-		link->state |= DEV_RELEASE_PENDING;
-		add_timer(&link->release);
-	}
+	if (link->state & DEV_STALE_CONFIG)
+		mod_timer(&link->release, jiffies + HZ/20);
 
 	MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/3c589_cs.c	Sat Feb 26 22:31:47 2000
+++ linux/drivers/net/pcmcia/3c589_cs.c	Mon May  8 21:26:05 2000
@@ -4,7 +4,7 @@
     
     Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
 
-    3c589_cs.c 1.145 2000/02/11 03:11:51
+    3c589_cs.c 1.151 2000/05/08 22:03:18
 
     The network driver code is based on Donald Becker's 3c589 code:
     
@@ -117,7 +117,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"3c589_cs.c 1.145 2000/02/11 03:11:51 (David Hinds)";
+"3c589_cs.c 1.151 2000/05/08 22:03:18 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -156,7 +156,6 @@
 static int el3_rx(struct net_device *dev);
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
-
 static void set_multicast_list(struct net_device *dev);
 
 static dev_info_t dev_info = "3c589_cs";
@@ -194,18 +193,6 @@
 
 /*======================================================================
 
-    We never need to do anything when a tc589 device is "initialized"
-    by the net software, because we only register already-found cards.
-    
-======================================================================*/
-
-static int tc589_init(struct net_device *dev)
-{
-    return 0;
-}
-
-/*======================================================================
-
     tc589_attach() creates an "instance" of the driver, allocating
     local data structures for one device.  The device is registered
     with Card Services.
@@ -254,15 +241,11 @@
     dev->get_stats = &el3_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     ether_setup(dev);
-    dev->name = lp->node.dev_name;
-    dev->init = &tc589_init;
     dev->open = &el3_open;
     dev->stop = &el3_close;
     dev->tx_timeout = el3_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
     
-    netif_start_queue (dev);
-    
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -298,7 +281,6 @@
 {
     struct el3_private *lp = link->priv;
     dev_link_t **linkp;
-    long flags;
     
     DEBUG(0, "3c589_detach(0x%p)\n", link);
     
@@ -308,14 +290,7 @@
     if (*linkp == NULL)
 	return;
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-    
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	tc589_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -403,13 +378,11 @@
 	
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n");
 	goto failed;
     }
     
-    link->state &= ~DEV_CONFIG_PENDING;
     ioaddr = dev->base_addr;
     EL3WINDOW(0);
 
@@ -429,8 +402,10 @@
 	    goto failed;
 	}
     }
-    
+
+    strcpy(lp->node.dev_name, dev->name);
     link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
     
     /* The address and resource configuration register aren't loaded from
        the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
@@ -486,7 +461,7 @@
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
     
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
     
 } /* tc589_release */
 
@@ -513,8 +488,7 @@
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
 	    netif_device_detach(dev);
-	    link->release.expires = jiffies + HZ/20;
-	    add_timer(&link->release);
+	    mod_timer(&link->release, jiffies + HZ/20);
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
@@ -528,7 +502,6 @@
 	if (link->state & DEV_CONFIG) {
 	    if (link->open)
 		netif_device_detach(dev);
-
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -687,7 +660,7 @@
 
     link->open++;
     MOD_INC_USE_COUNT;
-    netif_start_queue (dev);
+    netif_start_queue(dev);
     
     tc589_reset(dev);
     lp->media.function = &media_check;
@@ -713,7 +686,7 @@
     /* Issue TX_RESET and TX_START commands. */
     wait_for_completion(dev, TxReset);
     outw(TxEnable, ioaddr + EL3_CMD);
-    netif_start_queue (dev);
+    netif_start_queue(dev);
 }
 
 static void pop_tx_status(struct net_device *dev)
@@ -747,11 +720,8 @@
 	  "status %4.4x.\n", dev->name, (long)skb->len,
 	  inw(ioaddr + EL3_STATUS));
 
-    netif_stop_queue (dev);
-    {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
-	lp->stats.tx_bytes += skb->len;
-    }
+    ((struct el3_private *)dev->priv)->stats.tx_bytes += skb->len;
+
     /* Put out the doubleword header... */
     outw(skb->len, ioaddr + TX_FIFO);
     outw(0x00, ioaddr + TX_FIFO);
@@ -759,11 +729,11 @@
     outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
     dev->trans_start = jiffies;
-    if (inw(ioaddr + TX_FREE) > 1536) {
-	netif_start_queue (dev);
-    } else
+    if (inw(ioaddr + TX_FREE) <= 1536) {
+	netif_stop_queue(dev);
 	/* Interrupt us when the FIFO has room for max-sized packet. */
 	outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+    }
 
     dev_kfree_skb(skb);
     pop_tx_status(dev);
@@ -788,7 +758,8 @@
     
     while ((status = inw(ioaddr + EL3_STATUS)) &
 	(IntLatch | RxComplete | StatsFull)) {
-	if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) {
+	if (!netif_device_present(dev) ||
+	    ((status & 0xe000) != 0x2000)) {
 	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
 	    break;
 	}
@@ -800,7 +771,7 @@
 	    DEBUG(3, "    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 & TxComplete)
@@ -861,8 +832,7 @@
     u_short media, errs;
     u_long flags;
 
-    if (!netif_device_present(dev))
-	goto reschedule;
+    if (!netif_device_present(dev)) goto reschedule;
 
     EL3WINDOW(1);
     /* Check for pending interrupt with expired latency timer: with
@@ -1076,8 +1046,6 @@
     ioaddr_t ioaddr = dev->base_addr;
     
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
-    
-    netif_stop_queue (dev);
 
     if (DEV_OK(link)) {
 	/* Turn off statistics ASAP.  We update lp->stats below. */
@@ -1107,12 +1075,10 @@
     }
 
     link->open--;
+    netif_stop_queue(dev);
     del_timer(&lp->media);
-    if (link->state & DEV_STALE_CONFIG) {
-	link->release.expires = jiffies + HZ/20;
-	link->state |= DEV_RELEASE_PENDING;
-	add_timer(&link->release);
-    }
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
     
     MOD_DEC_USE_COUNT;
     
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.3.99-pre6/linux/drivers/net/pcmcia/Config.in	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/pcmcia/Config.in	Tue May  2 12:47:16 2000
@@ -18,7 +18,6 @@
    dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
 
    if [ "$CONFIG_CARDBUS" = "y" ]; then
-      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-pre6/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/aironet4500_cs.c	Fri Mar 10 16:40:42 2000
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Thu May  4 11:31:21 2000
@@ -223,9 +223,9 @@
 	dev->get_stats = 		&awc_get_stats;
 //	dev->set_multicast_list = 	&awc_set_multicast_list;
 
-	ether_setup(dev);
+	strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name);
 
-	dev->name = ((struct awc_private *)dev->priv)->node.dev_name;
+	ether_setup(dev);
 
 	dev->init = &awc_pcmcia_init;
 	dev->open = &awc_pcmcia_open;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/com20020_cs.c linux/drivers/net/pcmcia/com20020_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/com20020_cs.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/pcmcia/com20020_cs.c	Tue May  2 12:36:09 2000
@@ -102,12 +102,14 @@
 static int node = 0;
 static int timeout = 3;
 static int backplane = 0;
-static int clock = 0;
+static int clockp = 0;
+static int clockm = 0;
 
 MODULE_PARM(node, "i");
 MODULE_PARM(timeout, "i");
 MODULE_PARM(backplane, "i");
-MODULE_PARM(clock, "i");
+MODULE_PARM(clockp, "i");
+MODULE_PARM(clockm, "i");
 
 /* Bit map of interrupts to choose from */
 static u_int irq_mask = 0xdeb8;
@@ -231,7 +233,8 @@
     dev->dev_addr[0] = node;
     lp->timeout = timeout;
     lp->backplane = backplane;
-    lp->clock = clock;
+    lp->clockp = clockp;
+    lp->clockm = clockm & 3;
     lp->hw.open_close_ll = com20020cs_open_close;
 
     link->irq.Instance = info->dev = dev;
@@ -350,6 +353,7 @@
 
 static void com20020_config(dev_link_t *link)
 {
+    struct arcnet_local *lp;
     client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
@@ -426,6 +430,11 @@
     }
     
     MOD_INC_USE_COUNT;
+
+    lp = dev->priv;
+    lp->card_name = "PCMCIA COM20020";
+    lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
+
     i = com20020_found(dev, 0);
     
     if (i != 0) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/fmvj18x_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Mon May  8 21:26:05 2000
@@ -99,7 +99,6 @@
 static void fmvj18x_release(u_long arg);
 static int fmvj18x_event(event_t event, int priority,
 			  event_callback_args_t *args);
-static int fmvj18x_init(struct net_device *dev);
 static dev_link_t *fmvj18x_attach(void);
 static void fmvj18x_detach(dev_link_t *);
 
@@ -115,7 +114,7 @@
 static void fjn_reset(struct net_device *dev);
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
-static void fjn_tx_timeout (struct net_device *dev);
+static void fjn_tx_timeout(struct net_device *dev);
 
 static dev_info_t dev_info = "fmvj18x_cs";
 static dev_link_t *dev_list = NULL;
@@ -140,7 +139,6 @@
     cardtype_t cardtype;
     u_short sent;
     u_char mc_filter[8];
-    spinlock_t lock;
 } local_info_t;
 
 #define MC_FILTERBREAK 64
@@ -237,7 +235,7 @@
 #define INTR_OFF             0x0d /* LAN controler ignores interrupts */
 #define INTR_ON              0x1d /* LAN controler will catch interrupts */
 
-#define TX_TIMEOUT	     10
+#define TX_TIMEOUT		((400*HZ)/1000)
 
 /*======================================================================
 
@@ -282,8 +280,6 @@
     lp = kmalloc(sizeof(*lp), GFP_KERNEL);
     if (!lp) return NULL;
     memset(lp, 0, sizeof(*lp));
-    
-    lp->lock = SPIN_LOCK_UNLOCKED;
     link = &lp->link; dev = &lp->dev;
     link->priv = dev->priv = link->irq.Instance = lp;
 
@@ -316,13 +312,10 @@
     dev->get_stats = &fjn_get_stats;
     dev->set_multicast_list = &set_rx_mode;
     ether_setup(dev);
-    dev->name = lp->node.dev_name;
-    dev->init = &fmvj18x_init;
     dev->open = &fjn_open;
     dev->stop = &fjn_close;
     dev->tx_timeout = fjn_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
-    netif_start_queue (dev);
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -352,7 +345,6 @@
 {
     local_info_t *lp = link->priv;
     dev_link_t **linkp;
-    long flags;
     
     DEBUG(0, "fmvj18x_detach(0x%p)\n", link);
     
@@ -362,14 +354,7 @@
     if (*linkp == NULL)
 	return;
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-    
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	fmvj18x_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -470,7 +455,6 @@
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
 	goto failed;
@@ -528,6 +512,7 @@
 	break;
     }
 
+    strcpy(lp->node.dev_name, dev->name);
     link->dev = &lp->node;
     link->state &= ~DEV_CONFIG_PENDING;
 
@@ -574,7 +559,7 @@
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
     
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
     
 } /* fmvj18x_release */
 
@@ -594,8 +579,7 @@
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
 	    netif_device_detach(dev);
-	    link->release.expires = jiffies + HZ/20;
-	    add_timer(&link->release);
+	    mod_timer(&link->release, jiffies + HZ/20);
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
@@ -608,8 +592,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open)
-	    	netif_device_detach(dev);
-
+		netif_device_detach(dev);
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -629,11 +612,6 @@
     return 0;
 } /* fmvj18x_event */
 
-static int fmvj18x_init(struct net_device *dev)
-{
-    return 0;
-} /* fmvj18x_init */
-
 /*====================================================================*/
 
 static int __init init_fmvj18x_cs(void)
@@ -675,9 +653,6 @@
 	       "unknown device.\n", irq);
         return;
     }
-    
-    spin_lock (&lp->lock);
-    
     ioaddr = dev->base_addr;
 
     /* avoid multiple interrupts */
@@ -710,11 +685,10 @@
 	    lp->tx_queue = 0;
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
-	    netif_wake_queue (dev);
 	} else {
 	    lp->tx_started = 0;
-	    netif_stop_queue (dev);
 	}
+	netif_wake_queue(dev);
     }
     DEBUG(4, "%s: exiting interrupt,\n", dev->name);
     DEBUG(4, "    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
@@ -722,53 +696,49 @@
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
-    spin_unlock (&lp->lock);
-    
 } /* fjn_interrupt */
 
 /*====================================================================*/
-static void fjn_tx_timeout (struct net_device *dev)
+
+static void fjn_tx_timeout(struct net_device *dev)
 {
-	struct local_info_t *lp = (struct local_info_t *) dev->priv;
-	ioaddr_t ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
-		dev->name, htons (inw (ioaddr + TX_STATUS)),
-		inb (ioaddr + TX_STATUS) & F_TMT_RDY
-		? "IRQ conflict" : "network cable problem");
-	printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
-		"%04x %04x %04x %04x %04x.\n",
-		dev->name, htons (inw (ioaddr + 0)),
-		htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)),
-		htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)),
-		htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)),
-		htons (inw (ioaddr + 14)));
-	lp->stats.tx_errors++;
-
-	/* ToDo: We should try to restart the adaptor... */
-	spin_lock_irqsave (&lp->lock, flags);
-
-	fjn_reset (dev);
-
-	lp->tx_started = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-	lp->sent = 0;
-	lp->open_time = jiffies;
-	netif_start_queue (dev);
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
 
-	spin_unlock_irqrestore (&lp->lock, flags);
-}
+    printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+	   dev->name, htons(inw(ioaddr + TX_STATUS)),
+	   inb(ioaddr + TX_STATUS) & F_TMT_RDY
+	   ? "IRQ conflict" : "network cable problem");
+    printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+	   "%04x %04x %04x %04x %04x.\n",
+	   dev->name, htons(inw(ioaddr + 0)),
+	   htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+	   htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+	   htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+	   htons(inw(ioaddr +14)));
+    lp->stats.tx_errors++;
+    /* ToDo: We should try to restart the adaptor... */
+    cli();
 
+    fjn_reset(dev);
+
+    lp->tx_started = 0;
+    lp->tx_queue = 0;
+    lp->tx_queue_len = 0;
+    lp->sent = 0;
+    lp->open_time = jiffies;
+    sti();
+    netif_start_queue(dev);
+}
 
 static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
 
-    netif_stop_queue (dev);
-    if (1) {
+    netif_stop_queue(dev);
+
+    {
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
 
@@ -802,17 +772,17 @@
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
 	    lp->tx_started = 1;
-	    netif_start_queue (dev);
+	    netif_start_queue(dev);
 	} else {
 	    if( sram_config == 0 ) {
 		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
 		    /* Yes, there is room for one more packet. */
-		    netif_start_queue (dev);
+		    netif_start_queue(dev);
 	    } else {
 		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
 						lp->tx_queue < 127 )
 		    /* Yes, there is room for one more packet. */
-		    netif_start_queue (dev);
+		    netif_start_queue(dev);
 	    }
 	}
 
@@ -976,7 +946,7 @@
     }
 
     /* If any worth-while packets have been received, dev_rint()
-	   has done a mark_bh(NET_BH) for us and will work on them
+	   has done a netif_wake_queue() for us and will work on them
 	   when we get to the bottom-half routine. */
 /*
     if( lp->cardtype != TDK ) {
@@ -1021,7 +991,7 @@
     lp->tx_queue = 0;
     lp->tx_queue_len = 0;
     lp->open_time = jiffies;
-    netif_start_queue (dev);    
+    netif_start_queue(dev);
     
     MOD_INC_USE_COUNT;
 
@@ -1039,7 +1009,7 @@
     DEBUG(4, "fjn_close('%s').\n", dev->name);
 
     lp->open_time = 0;
-    netif_stop_queue (dev);
+    netif_stop_queue(dev);
 
     /* Set configuration register 0 to disable Tx and Rx. */
     if( sram_config == 0 ) 
@@ -1057,11 +1027,8 @@
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
-    if (link->state & DEV_STALE_CONFIG) {
-	link->release.expires = jiffies + HZ/20;
-	link->state |= DEV_RELEASE_PENDING;
-	add_timer(&link->release);
-    }
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
     MOD_DEC_USE_COUNT;
 
     return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/ibmtr_cs.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Wed May 10 16:56:42 2000
@@ -49,10 +49,8 @@
     Updated to version 2.2.7 to match the first version of the kernel
     that the modification to ibmtr.c were incorporated into.
     
-	
 ======================================================================*/
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -61,6 +59,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -74,7 +73,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-#define PCMCIA_DEBUG 10
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
@@ -226,10 +224,6 @@
 
     dev->init = &ibmtr_probe;
 
-#if 0
-    dev->tbusy = 1; 
-#endif
-
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -266,8 +260,6 @@
     struct ibmtr_dev_t *info = link->priv;
     dev_link_t **linkp;
     struct net_device *dev; 
-    long flags;
-
 
     DEBUG(0, "ibmtr_detach(0x%p)\n", link);
 
@@ -278,19 +270,11 @@
         return;
 
     dev = info->dev;
-    
-    save_flags(flags);
-    cli();
     {
 	struct tok_info *ti = (struct tok_info *)dev->priv;
-	if (ti->tr_timer.next) del_timer(&(ti->tr_timer));
+	del_timer(&(ti->tr_timer));
     }
-    if (link->state & DEV_RELEASE_PENDING) {
-        del_timer(&link->release);
-        link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
         ibmtr_release((u_long)link);
         if (link->state & DEV_STALE_CONFIG) {
@@ -378,8 +362,9 @@
     req.Base = mmiobase;
     req.Size = 0x2000;
     req.AccessSpeed = 250;
-    link->win = (window_handle_t) link->handle;
+    link->win = (window_handle_t)link->handle;
     CS_CHECK(RequestWindow, &link->win, &req);
+
     mem.CardOffset = req.Base;
     mem.Page = 0;
     CS_CHECK(MapMemPage, link->win, &mem);
@@ -409,10 +394,6 @@
         Adapters Technical Reference"  SC30-3585 for this info.  */
     ibmtr_hw_setup(dev);
 
-#if 0
-    dev->tbusy = 0;
-#endif
-
     i = register_trdev(dev);
     
     if (i != 0) {
@@ -452,7 +433,6 @@
     dev_link_t *link = (dev_link_t *)arg;
     ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
-    struct tok_info *ti=(struct tok_info *) dev->priv;
 
     DEBUG(0, "ibmtr_release(0x%p)\n", link);
 
@@ -463,8 +443,6 @@
         return;
     }
 
-    ti->open_status=CLOSED;
-
     CardServices(ReleaseConfiguration, link->handle);
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
@@ -475,7 +453,7 @@
 	CardServices(ReleaseWindow, info->sram_win_handle);
     }
 
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
 
 } /* ibmtr_release */
 
@@ -501,12 +479,8 @@
     case CS_EVENT_CARD_REMOVAL:
         link->state &= ~DEV_PRESENT;
         if (link->state & DEV_CONFIG) {
-#if 0
-            dev->tbusy = 1; dev->start = 0;
-#endif
-            link->release.expires = jiffies + HZ/20;
-            link->state |= DEV_RELEASE_PENDING;
-            add_timer(&link->release);
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
         }
         break;
     case CS_EVENT_CARD_INSERTION:
@@ -518,11 +492,8 @@
         /* Fall through... */
     case CS_EVENT_RESET_PHYSICAL:
         if (link->state & DEV_CONFIG) {
-#if 0
-            if (link->open) {
-                dev->tbusy = 1; dev->start = 0;
-            }
-#endif
+            if (link->open)
+		netif_device_detach(dev);
             CardServices(ReleaseConfiguration, link->handle);
         }
         break;
@@ -534,9 +505,7 @@
             CardServices(RequestConfiguration, link->handle, &link->conf);
             if (link->open) {
 		(dev->init)(dev);
-#if 0
-                dev->tbusy = 0; dev->start = 1;
-#endif
+		netif_device_attach(dev);
             }
         }
         break;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/netwave_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/netwave_cs.c	Fri May  5 12:37:52 2000
@@ -502,7 +502,7 @@
     dev->do_ioctl = &netwave_ioctl;
 
     ether_setup(dev);
-    dev->name = priv->node.dev_name;
+    strcpy(dev->name, priv->node.dev_name);
     dev->init = &netwave_init;
     dev->open = &netwave_open;
     dev->stop = &netwave_close;
@@ -1224,8 +1224,7 @@
     writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
 	
     /* If watchdog not already active, activate it... */
-    if(priv->watchdog.prev == (struct timer_list *) NULL) {
-
+    if (!timer_pending(&priv->watchdog)) {
 	/* set timer to expire in WATCHDOG_JIFFIES */
 	priv->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
 	add_timer(&priv->watchdog);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/nmclan_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Mon May  8 21:26:05 2000
@@ -111,7 +111,6 @@
 ---------------------------------------------------------------------------- */
 
 #define MULTI_TX			0
-#define TIMEOUT_TX			1
 #define RESET_ON_TIMEOUT		1
 #define TX_INTERRUPTABLE		1
 #define RESET_XILINX			0
@@ -157,11 +156,6 @@
 #define MACE_LADRF_LEN			8
 					/* 8 bytes in Logical Address Filter */
 
-/* Transmitter Busy Bit Index Defines */
-#define TBUSY_UNSPECIFIED		0
-#define TBUSY_PARTIAL_TX_FRAME		0
-#define TBUSY_NO_FREE_TX_FRAMES		1
-
 /* Loop Control Defines */
 #define MACE_MAX_IR_ITERATIONS		10
 #define MACE_MAX_RX_ITERATIONS		12
@@ -307,9 +301,7 @@
 #undef MACE_IMR_DEFAULT
 #define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
 
-#define TX_TIMEOUT (5*HZ)
-
-
+#define TX_TIMEOUT		((400*HZ)/1000)
 
 /* ----------------------------------------------------------------------------
 Type Definitions
@@ -364,7 +356,6 @@
     dev_link_t link;
     struct net_device dev;
     dev_node_t node;
-    spinlock_t lock;
     struct net_device_stats linux_stats; /* Linux statistics counters */
     mace_statistics mace_stats; /* MACE chip statistics counters */
 
@@ -433,11 +424,11 @@
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void mace_tx_timeout(struct net_device *dev);
 static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
-static void mace_tx_timeout (struct net_device *dev);
 
 static void set_multicast_list(struct net_device *dev);
 
@@ -471,17 +462,6 @@
 }
 
 /* ----------------------------------------------------------------------------
-nmclan_init
-	We never need to do anything when a nmclan device is "initialized"
-	by the net software, because we only register already-found cards.
----------------------------------------------------------------------------- */
-
-static int nmclan_init(struct net_device *dev)
-{
-    return 0;
-}
-
-/* ----------------------------------------------------------------------------
 nmclan_attach
 	Creates an "instance" of the driver, allocating local data
 	structures for one device.  The device is registered with Card
@@ -504,8 +484,6 @@
     lp = kmalloc(sizeof(*lp), GFP_KERNEL);
     if (!lp) return NULL;
     memset(lp, 0, sizeof(*lp));
-    
-    lp->lock = SPIN_LOCK_UNLOCKED;
     link = &lp->link; dev = &lp->dev;
     link->priv = dev->priv = link->irq.Instance = lp;
 
@@ -535,15 +513,11 @@
     dev->get_stats = &mace_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     ether_setup(dev);
-    dev->name = lp->node.dev_name;
-    dev->init = &nmclan_init;
     dev->open = &mace_open;
     dev->stop = &mace_close;
     dev->tx_timeout = mace_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 
-    netif_start_queue (dev);
-
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -587,6 +561,7 @@
     if (*linkp == NULL)
 	return;
 
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	nmclan_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -763,7 +738,6 @@
   CS_CHECK(RequestConfiguration, handle, &link->conf);
   dev->irq = link->irq.AssignedIRQ;
   dev->base_addr = link->io.BasePort1;
-  netif_start_queue (dev);
   i = register_netdev(dev);
   if (i != 0) {
     printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
@@ -806,6 +780,7 @@
   else
     printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
 
+  strcpy(lp->node.dev_name, dev->name);
   link->dev = &lp->node;
   link->state &= ~DEV_CONFIG_PENDING;
 
@@ -846,7 +821,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+  link->state &= ~DEV_CONFIG;
 
 } /* nmclan_release */
 
@@ -871,8 +846,7 @@
       link->state &= ~DEV_PRESENT;
       if (link->state & DEV_CONFIG) {
 	netif_device_detach(dev);
-	link->release.expires = jiffies + HZ/20;
-	add_timer(&link->release);
+	mod_timer(&link->release, jiffies + HZ/20);
       }
       break;
     case CS_EVENT_CARD_INSERTION:
@@ -886,7 +860,6 @@
       if (link->state & DEV_CONFIG) {
 	if (link->open)
 	  netif_device_detach(dev);
-
 	CardServices(ReleaseConfiguration, link->handle);
       }
       break;
@@ -909,8 +882,6 @@
   return 0;
 } /* nmclan_event */
 
-/* ------------------------------------------------------------------------- */
-
 /* ----------------------------------------------------------------------------
 nmclan_reset
 	Reset and restore all of the Xilinx and MACE registers.
@@ -997,7 +968,7 @@
 
   MACEBANK(0);
 
-  netif_start_queue (dev);
+  netif_start_queue(dev);
   nmclan_reset(dev);
 
   return 0; /* Always succeed */
@@ -1014,42 +985,20 @@
   dev_link_t *link = &lp->link;
 
   DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
-  
-  netif_stop_queue (dev);
 
   /* Mask off all interrupts from the MACE chip. */
   outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
 
   link->open--;
-  if (link->state & DEV_STALE_CONFIG) {
-    link->release.expires = jiffies + HZ/20;
-    link->state |= DEV_RELEASE_PENDING;
-    add_timer(&link->release);
-  }
+  netif_stop_queue(dev);
+  if (link->state & DEV_STALE_CONFIG)
+    mod_timer(&link->release, jiffies + HZ/20);
 
   MOD_DEC_USE_COUNT;
 
   return 0;
 } /* mace_close */
 
-
-static void mace_tx_timeout (struct net_device *dev)
-{
-	mace_private *lp = (mace_private *)dev->priv;
-	dev_link_t *link = &lp->link;
-
-	printk (KERN_NOTICE "%s: transmit timed out -- ", dev->name);
-#if RESET_ON_TIMEOUT
-	printk ("resetting card\n");
-	CardServices (ResetCard, link->handle);
-#else				/* #if RESET_ON_TIMEOUT */
-	printk ("NOT resetting card\n");
-#endif				/* #if RESET_ON_TIMEOUT */
-	dev->trans_start = jiffies;
-	netif_start_queue (dev);
-}
-
-
 /* ----------------------------------------------------------------------------
 mace_start_xmit
 	This routine begins the packet transmit function.  When completed,
@@ -1060,16 +1009,33 @@
 	driver."  If _start_xmit returns non-zero, the "transmission
 	failed, put skb back into a list."
 ---------------------------------------------------------------------------- */
+
+static void mace_tx_timeout(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  dev_link_t *link = &lp->link;
+
+  printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+#if RESET_ON_TIMEOUT
+  printk("resetting card\n");
+  CardServices(ResetCard, link->handle);
+#else /* #if RESET_ON_TIMEOUT */
+  printk("NOT resetting card\n");
+#endif /* #if RESET_ON_TIMEOUT */
+  dev->trans_start = jiffies;
+  netif_start_queue(dev);
+}
+
 static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
   mace_private *lp = (mace_private *)dev->priv;
   ioaddr_t ioaddr = dev->base_addr;
 
+  netif_stop_queue(dev);
+
   DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
 	dev->name, (long)skb->len);
 
-  netif_stop_queue (dev);
-
 #if (!TX_INTERRUPTABLE)
   /* Disable MACE TX interrupts. */
   outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT,
@@ -1079,7 +1045,7 @@
 
   {
     /* This block must not be interrupted by another transmit request!
-       dev->tbusy will take care of timer-based retransmissions from
+       mace_tx_timeout will take care of timer-based retransmissions from
        the upper layers.  The interrupt handler is guaranteed never to
        service a transmit interrupt while we are in here.
     */
@@ -1099,12 +1065,10 @@
 
     dev->trans_start = jiffies;
 
-    if (lp->tx_free_frames > 0) {
 #if MULTI_TX
-      netif_start_queue (dev);
+    if (lp->tx_free_frames > 0)
+      netif_start_queue(dev);
 #endif /* #if MULTI_TX */
-    }
-
   }
 
 #if (!TX_INTERRUPTABLE)
@@ -1135,8 +1099,6 @@
 	  irq);
     return;
   }
-  
-  spin_lock (&lp->lock);
 
   if (lp->tx_irq_disabled) {
     printk(
@@ -1226,7 +1188,7 @@
 
       lp->linux_stats.tx_packets++;
       lp->tx_free_frames++;
-      netif_wake_queue (dev);
+      netif_wake_queue(dev);
     } /* if (status & MACE_IR_XMTINT) */
 
     if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
@@ -1261,7 +1223,7 @@
   } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
 
 exception:
-  spin_unlock (&lp->lock);
+  return;
 } /* mace_interrupt */
 
 /* ----------------------------------------------------------------------------
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/pcnet_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Mon May  8 21:26:05 2000
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
 
-    pcnet_cs.c 1.112 2000/02/11 01:24:44
+    pcnet_cs.c 1.117 2000/05/04 01:29:47
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -28,9 +28,9 @@
 
 ======================================================================*/
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
@@ -72,7 +72,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.112 2000/02/11 01:24:44 (David Hinds)";
+"pcnet_cs.c 1.117 2000/05/04 01:29:47 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -124,6 +124,7 @@
 		       event_callback_args_t *args);
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
@@ -142,16 +143,17 @@
 /*====================================================================*/
 
 typedef struct hw_info_t {
-    u_long	offset;
+    u_int	offset;
     u_char	a0, a1, a2;
-    u_long	flags;
+    u_int	flags;
 } hw_info_t;
 
 #define DELAY_OUTPUT	0x01
 #define HAS_MISC_REG	0x02
 #define USE_BIG_BUF	0x04
 #define HAS_IBM_MISC	0x08
-#define IS_DL10019A	0x10
+#define IS_DL10019	0x10
+#define IS_AX88190	0x20
 #define USE_SHMEM	0x80	/* autodetected */
 
 static hw_info_t hw_info[] = {
@@ -212,25 +214,25 @@
     { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
     { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
     { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
-    { /* PCMCIA Technology OEM */ 0x01c8, 0xa0, 0x0c, 0 }
+    { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
 };
 
 #define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
 
 static hw_info_t default_info =
 { /* Unknown NE2000 Clone */ 0x00, 0x00, 0x00, 0x00, 0 };
-static hw_info_t dl_fast_info =
-{ /* D-Link EtherFast */ 0x00, 0x00, 0x00, 0x00, IS_DL10019A };
+static hw_info_t dl10019_info =
+{ /* D-Link DL10019 chipset */ 0x00, 0x00, 0x00, 0x00, IS_DL10019 };
 
 typedef struct pcnet_dev_t {
-    struct net_device	dev; /* so &dev == &pcnet_dev_t */
+    struct net_device	dev;	/* so &dev == &pcnet_dev_t */
     dev_link_t		link;
     dev_node_t		node;
-    u_long		flags;
+    u_int		flags;
     caddr_t		base;
     struct timer_list	watchdog;
-    int			stale, state;
-    u_short		fast_poll;
+    int			stale, fast_poll;
+    u_char		link_status;
 } pcnet_dev_t;
 
 /*======================================================================
@@ -310,14 +312,11 @@
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     ethdev_init(dev);
-    dev->name = info->node.dev_name;
     dev->init = &pcnet_init;
     dev->open = &pcnet_open;
     dev->stop = &pcnet_close;
     dev->set_config = &set_config;
 
-    netif_stop_queue(dev);
-
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -353,7 +352,6 @@
 {
     pcnet_dev_t *info = link->priv;
     dev_link_t **linkp;
-    long flags;
 
     DEBUG(0, "pcnet_detach(0x%p)\n", link);
 
@@ -363,14 +361,7 @@
     if (*linkp == NULL)
 	return;
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	pcnet_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -392,27 +383,6 @@
 
 /*======================================================================
 
-    For the Linksys EtherFast 10/100 card
-
-======================================================================*/
-
-static hw_info_t *get_dl_fast(dev_link_t *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-    u_char sum;
-
-    for (sum = 0, i = 0x14; i < 0x1c; i++)
-	sum += inb_p(dev->base_addr + i);
-    if (sum != 0xff)
-	return NULL;
-    for (i = 0; i < 6; i++)
-	dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
-    return &dl_fast_info;
-}
-
-/*======================================================================
-
     This probes for a card's hardware address, for card types that
     encode this information in their CIS.
 
@@ -471,13 +441,13 @@
 static hw_info_t *get_prom(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
-    unsigned char prom[32];
-    ioaddr_t ioaddr;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_char prom[32];
     int i, j;
 
     /* This is lifted straight from drivers/net/ne.c */
     struct {
-	unsigned char value, offset;
+	u_char value, offset;
     } program_seq[] = {
 	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
 	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
@@ -494,8 +464,6 @@
 	{E8390_RREAD+E8390_START, E8390_CMD},
     };
 
-    ioaddr = dev->base_addr;
-
     pcnet_reset_8390(dev);
     udelay(10000);
 
@@ -520,6 +488,58 @@
 
 /*======================================================================
 
+    For DL10019 based cards, like the Linksys EtherFast
+
+======================================================================*/
+
+static hw_info_t *get_dl10019(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+    u_char sum;
+
+    for (sum = 0, i = 0x14; i < 0x1c; i++)
+	sum += inb_p(dev->base_addr + i);
+    if (sum != 0xff)
+	return NULL;
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
+    return &dl10019_info;
+}
+
+/*======================================================================
+
+    For Asix AX88190 based cards
+
+======================================================================*/
+
+static hw_info_t *get_ax88190(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i, j;
+
+    /* Not much of a test, but the alternatives are messy */
+    if (link->conf.ConfigBase != 0x03c0)
+	return NULL;
+
+    outb_p(0x01, EN0_DCFG);	/* Set word-wide access. */
+    outb_p(0x00, EN0_RSARLO);	/* DMA starting at 0x0400. */
+    outb_p(0x04, EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, E8390_CMD);
+
+    for (i = 0; i < 6; i += 2) {
+	j = inw(ioaddr + PCNET_DATAPORT);
+	dev->dev_addr[i] = j & 0xff;
+	dev->dev_addr[i+1] = j >> 8;
+    }
+    printk(KERN_INFO "pcnet_cs: sorry, the AX88190 chipset is not "
+	   "supported.\n");
+    return NULL;
+}
+
+/*======================================================================
+
     This should be totally unnecessary... but when we can't figure
     out the hardware address any other way, we'll let the user hard
     wire it when the module is initialized.
@@ -687,7 +707,6 @@
     } else {
 	dev->if_port = 0;
     }
-    netif_start_queue(dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
 	goto failed;
@@ -697,7 +716,9 @@
     if (hw_info == NULL)
 	hw_info = get_prom(link);
     if (hw_info == NULL)
-	hw_info = get_dl_fast(link);
+	hw_info = get_dl10019(link);
+    if (hw_info == NULL)
+	hw_info = get_ax88190(link);
     if (hw_info == NULL)
 	hw_info = get_hwired(link);
     
@@ -733,11 +754,19 @@
     ei_status.word16 = 1;
     ei_status.reset_8390 = &pcnet_reset_8390;
 
+    strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
     link->state &= ~DEV_CONFIG_PENDING;
 
-    printk(KERN_INFO "%s: NE2000 Compatible: io %#3lx, irq %d,",
-	   dev->name, dev->base_addr, dev->irq);
+    if (info->flags & IS_DL10019) {
+	dev->do_ioctl = &do_ioctl;
+	printk(KERN_INFO "%s: NE2000 (DL10019 rev %02x): ",
+	       dev->name, inb(dev->base_addr + 0x1a));
+    } else if (info->flags & IS_AX88190) {
+	printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name);
+    } else
+	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+    printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
     if (info->flags & USE_SHMEM)
 	printk (" mem %#5lx,", dev->mem_start);
     if (info->flags & HAS_MISC_REG)
@@ -787,7 +816,7 @@
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
 
 } /* pcnet_release */
 
@@ -813,9 +842,7 @@
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
 	    netif_device_detach(&info->dev);
-	    link->release.expires = jiffies + HZ/20;
-	    link->state |= DEV_RELEASE_PENDING;
-	    add_timer(&link->release);
+	    mod_timer(&link->release, jiffies + HZ/20);
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
@@ -829,7 +856,6 @@
 	if (link->state & DEV_CONFIG) {
 	    if (link->open)
 		netif_device_detach(&info->dev);
-
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -889,7 +915,7 @@
     request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
 
     /* Start by assuming the link is bad */
-    info->state = 1;
+    info->link_status = 1;
     info->watchdog.function = &ei_watchdog;
     info->watchdog.data = (u_long)info;
     info->watchdog.expires = jiffies + HZ;
@@ -910,12 +936,10 @@
     free_irq(dev->irq, dev);
     
     link->open--;
+    netif_stop_queue(dev);
     del_timer(&info->watchdog);
-    if (link->state & DEV_STALE_CONFIG) {
-	link->release.expires = jiffies + HZ/20;
-	link->state |= DEV_RELEASE_PENDING;
-	add_timer(&link->release);
-    }
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
 
     MOD_DEC_USE_COUNT;
 
@@ -952,7 +976,7 @@
     
 } /* pcnet_reset_8390 */
 
-/* ======================================================================= */
+/*====================================================================*/
 
 static int set_config(struct net_device *dev, struct ifmap *map)
 {
@@ -970,7 +994,7 @@
     return 0;
 }
 
-/* ======================================================================= */
+/*====================================================================*/
 
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -985,8 +1009,7 @@
     struct net_device *dev = &info->dev;
     ioaddr_t nic_base = dev->base_addr;
 
-    if (!netif_device_present(dev))
-	    goto reschedule;
+    if (!netif_device_present(dev)) goto reschedule;
 
     /* Check for pending interrupt with expired latency timer: with
        this, we can limp along even if the interrupt is blocked */
@@ -1004,14 +1027,14 @@
 	return;
     }
 
-    if (info->flags & IS_DL10019A) {
-	int state = inb(dev->base_addr+0x1c) & 0x01;
-	if (state != info->state) {
+    if (info->flags & IS_DL10019) {
+	u_char link = inb(dev->base_addr+0x1c) & 0x01;
+	if (link != info->link_status) {
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
-		   (state) ? "lost" : "found");
-	    if (!state)
+		   (link) ? "lost" : "found");
+	    if (!link)
 		NS8390_init(dev, 1);
-	    info->state = state;
+	    info->link_status = link;
 	}
     }
 
@@ -1020,7 +1043,89 @@
     add_timer(&info->watchdog);
 }
 
-/* ======================================================================= */
+/*======================================================================
+
+    MII interface support for DL10019 based cards
+
+    There are two types of DL10019 based cards.  Some have the MII IO
+    direction bit as 0x10, others as 0x20; setting both bits seems to
+    work on all cards.
+
+======================================================================*/
+
+#define MDIO_SHIFT_CLK		0x80
+#define MDIO_DATA_OUT		0x40
+#define MDIO_DIR_WRITE		0x30
+#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
+#define MDIO_DATA_READ		0x10
+#define MDIO_MASK		0x0f
+
+static void mdio_sync(ioaddr_t addr)
+{
+    int bits, mask = inb(addr) & MDIO_MASK;
+    for (bits = 0; bits < 32; bits++) {
+	outb(mask | MDIO_DATA_WRITE1, addr);
+	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+{
+    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
+    int i, retval = 0, mask = inb(addr) & MDIO_MASK;
+
+    mdio_sync(addr);
+    for (i = 13; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb(mask | dat, addr);
+	outb(mask | dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 19; i > 0; i--) {
+	outb(mask, addr);
+	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
+	outb(mask | MDIO_SHIFT_CLK, addr);
+    }
+    return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+{
+    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
+    int i, mask = inb(addr) & MDIO_MASK;
+
+    mdio_sync(addr);
+    for (i = 31; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb(mask | dat, addr);
+	outb(mask | dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 1; i >= 0; i--) {
+	outb(mask, addr);
+	outb(mask | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    u16 *data = (u16 *)&rq->ifr_data;
+    ioaddr_t addr = dev->base_addr + 0x1c;
+    switch (cmd) {
+    case SIOCDEVPRIVATE:
+	data[0] = 0;
+    case SIOCDEVPRIVATE+1:
+	data[3] = mdio_read(addr, 0, data[1] & 0x1f);
+	return 0;
+    case SIOCDEVPRIVATE+2:
+	if (!capable(CAP_NET_ADMIN))
+	    return -EPERM;
+	mdio_write(addr, 0, data[1] & 0x1f, data[2]);
+	return 0;
+    }
+    return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
 
 static void dma_get_8390_hdr(struct net_device *dev,
 			     struct e8390_pkt_hdr *hdr,
@@ -1052,7 +1157,7 @@
     ei_status.dmaing &= ~0x01;
 }
 
-/* ======================================================================= */
+/*====================================================================*/
 
 static void dma_block_input(struct net_device *dev, int count,
 			    struct sk_buff *skb, int ring_offset)
@@ -1110,8 +1215,7 @@
 /*====================================================================*/
 
 static void dma_block_output(struct net_device *dev, int count,
-			     const unsigned char *buf,
-			     const int start_page)
+			     const u_char *buf, const int start_page)
 {
     ioaddr_t nic_base = dev->base_addr;
     pcnet_dev_t *info = (pcnet_dev_t *)dev;
@@ -1215,33 +1319,31 @@
 
 /*====================================================================*/
 
-static void copyin(unsigned char *dest, unsigned char *src, int c)
+static void copyin(u_char *dest, u_char *src, int c)
 {
-    unsigned short *d = (unsigned short *) dest;
-    unsigned short *s = (unsigned short *) src;
+    u_short *d = (u_short *)dest, *s = (u_short *)src;
     int odd;
 
     if (c <= 0)
 	return;
-    odd = (c & 01); c >>= 1;
+    odd = (c & 1); c >>= 1;
 
     if (c) {
 	do { *d++ = __raw_readw(s++); } while (--c);
     }
     /* get last byte by fetching a word and masking */
     if (odd)
-	*((unsigned char *)d) = readw(s) & 0xff;
+	*((u_char *)d) = readw(s) & 0xff;
 }
 
-static void copyout(unsigned char *dest, const unsigned char *src, int c)
+static void copyout(u_char *dest, const u_char *src, int c)
 {
-    volatile unsigned short *d = (unsigned short *) dest;
-    unsigned short *s = (unsigned short *) src;
+    u_short *d = (u_short *)dest, *s = (u_short *)src;
     int odd;
 
     if (c <= 0)
 	return;
-    odd = (c & 01); c >>= 1;
+    odd = (c & 1); c >>= 1;
 
     if (c) {
 	do { __raw_writew(*s++, d++); } while (--c);
@@ -1289,15 +1391,10 @@
 /*====================================================================*/
 
 static void shmem_block_output(struct net_device *dev, int count,
-			       const unsigned char *buf,
-			       const int start_page)
+			       const u_char *buf, const int start_page)
 {
     void *shmem = (void *)dev->mem_start + (start_page << 8);
     shmem -= ei_status.tx_start_page << 8;
-
-    if (ei_debug > 4)
-	printk(KERN_DEBUG "[bo=%d @ %x]\n", count, start_page);
-
     copyout(shmem, buf, count);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/ray_cs.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/pcmcia/ray_cs.c	Tue May  2 15:10:52 2000
@@ -385,7 +385,7 @@
 
     DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
     ether_setup(dev);
-    dev->name = local->node.dev_name;
+    strcpy(dev->name, local->node.dev_name);
     dev->init = &ray_dev_init;
     dev->open = &ray_open;
     dev->stop = &ray_dev_close;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/smc91c92_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Mon May  8 21:26:05 2000
@@ -8,7 +8,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
 
-    smc91c92_cs.c 1.85 2000/01/15 02:03:14
+    smc91c92_cs.c 1.96 2000/05/09 02:35:58
     
     This driver contains code written by Donald Becker
     (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au),
@@ -88,10 +88,6 @@
 
 /* Operational parameter that usually are not changed. */
 
-/* Do you want to use 32 bit xfers?  This should work on all chips,
-   but could cause trouble with some PCMCIA controllers... */
-#define USE_32_BIT		1
-
 /* Time in jiffies before concluding Tx hung */
 #define TX_TIMEOUT		((400*HZ)/1000)
 
@@ -102,9 +98,6 @@
    currently have room for another Tx packet. */
 #define MEMORY_WAIT_TIME       	8
 
-/* Values that should be specific lengths */
-typedef unsigned short uint16;
-
 static dev_info_t dev_info = "smc91c92_cs";
 
 static dev_link_t *dev_list = NULL;
@@ -125,8 +118,6 @@
     u_short			media_status;
     u_short			fast_poll;
     u_long			last_rx;
-    
-    spinlock_t			lock;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -156,7 +147,7 @@
 
 /* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
 #define	BANK_SELECT		14		/* Window select register. */
-#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT); }
+#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }
 
 /* Bank 0 registers. */
 #define	TCR 		0	/* transmit control register */
@@ -283,9 +274,9 @@
 static int smc91c92_event(event_t event, int priority,
 			  event_callback_args_t *args);
 
-static void smc91c92_tx_timeout (struct net_device *dev);
 static int smc91c92_open(struct net_device *dev);
 static int smc91c92_close(struct net_device *dev);
+static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void smc_rx(struct net_device *dev);
@@ -322,14 +313,6 @@
     CardServices(ReportError, handle, &err);
 }
 
-/*====================================================================*/
-
-static int smc91c92_init(struct net_device *dev)
-{
-    DEBUG(0, "%s: smc91c92_init called!\n", dev->name);
-    return 0;
-}
-
 /*======================================================================
 
   smc91c92_attach() creates an "instance" of the driver, allocating
@@ -378,16 +361,12 @@
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
     ether_setup(dev);
-    dev->name = smc->node.dev_name;
-    dev->init = &smc91c92_init;
     dev->open = &smc91c92_open;
     dev->stop = &smc91c92_close;
-    dev->tx_timeout = smc91c92_tx_timeout;
+    dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
     dev->priv = link->priv = link->irq.Instance = smc;
     
-    netif_start_queue (dev);
-    
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -422,7 +401,6 @@
 {
     struct smc_private *smc = link->priv;
     dev_link_t **linkp;
-    long flags;
 
     DEBUG(0, "smc91c92_detach(0x%p)\n", link);
     
@@ -432,14 +410,7 @@
     if (*linkp == NULL)
 	return;
     
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-    
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	smc91c92_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -574,14 +545,13 @@
     
     /* Allocate a memory window, for accessing the ISR */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    req.Base = 0;
-    req.Size = 0x1000;
+    req.Base = req.Size = 0;
     req.AccessSpeed = 0;
     link->win = (window_handle_t)link->handle;
     i = CardServices(RequestWindow, &link->win, &req);
     if (i != CS_SUCCESS)
 	return i;
-    smc->base = ioremap(req.Base, 0x1000);
+    smc->base = ioremap(req.Base, req.Size);
     mem.CardOffset = mem.Page = 0;
     if (smc->manfid == MANFID_MOTOROLA)
 	mem.CardOffset = link->conf.ConfigBase;
@@ -670,14 +640,14 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     int i, wait=0, loop;
-    unsigned int addr;
+    u_int addr;
 
     /* Read Ethernet address from Serial EEPROM */
     
     for (i = 0; i < 3; i++) {
-	SMC_SELECT_BANK( 2 );
+	SMC_SELECT_BANK(2);
 	outw(MOT_EEPROM + i, ioaddr + POINTER);
-	SMC_SELECT_BANK( 1 );
+	SMC_SELECT_BANK(1);
 	outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
 
 	for (loop = 0; loop < 200; loop++) {
@@ -959,10 +929,10 @@
 
     if (smc->manfid == MANFID_OSITECH) {
 	i = osi_config(link);
-    } else if (smc->manfid == MANFID_MOTOROLA
-	     || ((smc->manfid == MANFID_MEGAHERTZ)
-		 && ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS)
-		     || (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
+    } else if ((smc->manfid == MANFID_MOTOROLA) ||
+	       ((smc->manfid == MANFID_MEGAHERTZ) &&
+		((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
+		 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
 	i = mhz_mfc_config(link);
     } else {
 	i = smc_config(link);
@@ -983,7 +953,6 @@
 	dev->if_port = if_port;
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
-    netif_start_queue (dev);
     
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
@@ -1011,6 +980,7 @@
 	goto config_undo;
     }
 
+    strcpy(smc->node.dev_name, dev->name);
     link->dev = &smc->node;
     link->state &= ~DEV_CONFIG_PENDING;
 
@@ -1023,6 +993,7 @@
 	case 5: name = "95"; break;
 	case 7: name = "100"; break;
 	case 8: name = "100-FD"; break;
+	case 9: name = "110"; break;
 	}
     printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
 	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
@@ -1086,7 +1057,7 @@
 	CardServices(ReleaseWindow, link->win);
     }
     
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
 
 } /* smc91c92_release */
 
@@ -1113,9 +1084,7 @@
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
 	    netif_device_detach(dev);
-	    link->release.expires = jiffies + HZ/20;
-	    link->state |= DEV_RELEASE_PENDING;
-	    add_timer(&link->release);
+	    mod_timer(&link->release, jiffies + HZ/20);
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
@@ -1129,7 +1098,6 @@
 	if (link->state & DEV_CONFIG) {
 	    if (link->open)
 		netif_device_detach(dev);
-
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
 	break;
@@ -1205,8 +1173,8 @@
     }
     link->open++;
     MOD_INC_USE_COUNT;
-    
-    netif_start_queue (dev);
+
+    netif_start_queue(dev);
     smc->saved_skb = 0;
     smc->packets_waiting = 0;
     
@@ -1229,28 +1197,25 @@
 
     DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
 	  dev->name, inw(ioaddr + BANK_SELECT));
-    
-    netif_stop_queue (dev);
-    
+
+    netif_stop_queue(dev);
+
     /* Shut off all interrupts, and turn off the Tx and Rx sections.
        Don't bother to check for chip present. */
-    SMC_SELECT_BANK( 2 );	/* Nominally paranoia, but do no assume... */
+    SMC_SELECT_BANK(2);	/* Nominally paranoia, but do no assume... */
     outw(0, ioaddr + INTERRUPT);
-    SMC_SELECT_BANK( 0 );
+    SMC_SELECT_BANK(0);
     mask_bits(0xff00, ioaddr + RCR);
     mask_bits(0xff00, ioaddr + TCR);
     
     /* Put the chip into power-down mode. */
-    SMC_SELECT_BANK( 1 );
-    outw(CTL_POWERDOWN, ioaddr + CONTROL  );
+    SMC_SELECT_BANK(1);
+    outw(CTL_POWERDOWN, ioaddr + CONTROL );
     
     link->open--;
     del_timer(&smc->media);
-    if (link->state & DEV_STALE_CONFIG) {
-	link->release.expires = jiffies + HZ/20;
-	link->state |= DEV_RELEASE_PENDING;
-	add_timer(&link->release);
-    }
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
     
     MOD_DEC_USE_COUNT;
     
@@ -1265,61 +1230,52 @@
    
 ======================================================================*/
 
-static void smc_hardware_send_packet( struct net_device * dev )
+static void smc_hardware_send_packet(struct net_device * dev)
 {
     struct smc_private *smc = dev->priv;
     struct sk_buff *skb = smc->saved_skb;
     ioaddr_t ioaddr = dev->base_addr;
-    unsigned char packet_no;
+    u_char packet_no;
     
-    if ( !skb ) {
+    if (!skb) {
 	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
 	return;
     }
     
     /* There should be a packet slot waiting. */
     packet_no = inw(ioaddr + PNR_ARR) >> 8;
-    if ( packet_no & 0x80 ) {
+    if (packet_no & 0x80) {
 	/* If not, there is a hardware problem!  Likely an ejected card. */
 	printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
 	       " failed, status %#2.2x.\n", dev->name, packet_no);
-	dev_kfree_skb (skb);
+	dev_kfree_skb_irq(skb);
 	smc->saved_skb = NULL;
-	netif_start_queue (dev);
+	netif_start_queue(dev);
 	return;
     }
-    
+
     smc->stats.tx_bytes += skb->len;
     /* The card should use the just-allocated buffer. */
-    outw( packet_no, ioaddr + PNR_ARR );
+    outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
-    outw( PTR_AUTOINC , ioaddr + POINTER );
+    outw(PTR_AUTOINC , ioaddr + POINTER);
     
-    /* Send the packet length ( +6 for status, length and ctl byte )
-       and the status word ( set to zeros ). */
+    /* Send the packet length (+6 for status, length and ctl byte)
+       and the status word (set to zeros). */
     {
-	unsigned char *buf = skb->data;
-	int length = skb->len;	/* The chip will pad to ethernet min length. */
+	u_char *buf = skb->data;
+	u_int length = skb->len; /* The chip will pad to ethernet min. */
 
 	DEBUG(2, "%s: Trying to xmit packet of length %d.\n",
 	      dev->name, length);
 	
-#ifdef USE_32_BIT
-	outl((length+6) << 16, ioaddr + DATA_1);
-	if (length & 0x2) {
-	    outsl(ioaddr + DATA_1, buf,  length >> 2 );
-	    outw( *((uint16 *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
-	} else
-	    outsl(ioaddr + DATA_1, buf,  length >> 2 );
-#else
-	/* send the packet length: +6 for status words, length, and ctl */
-	outw( 0, ioaddr + DATA_1 );
-	outw(length + 6, ioaddr + DATA_1 );
-	outsw(ioaddr + DATA_1 , buf, length >> 1);
-#endif
+	/* send the packet length: +6 for status word, length, and ctl */
+	outw(0, ioaddr + DATA_1);
+	outw(length + 6, ioaddr + DATA_1);
+	outsw(ioaddr + DATA_1, buf, length >> 1);
 	
 	/* The odd last byte, if there is one, goes in the control word. */
-	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1 );
+	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
     }
     
     /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
@@ -1328,48 +1284,45 @@
 	 ioaddr + INTERRUPT);
     
     /* The chip does the rest of the work. */
-    outw( MC_ENQUEUE , ioaddr + MMU_CMD );
+    outw(MC_ENQUEUE , ioaddr + MMU_CMD);
     
     smc->saved_skb = NULL;
-    dev_kfree_skb (skb);
+    dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
-    netif_start_queue (dev);
+    netif_start_queue(dev);
     return;
 }
 
 /*====================================================================*/
 
-static void smc91c92_tx_timeout (struct net_device *dev)
+static void smc_tx_timeout(struct net_device *dev)
 {
-	struct smc_private *smc = dev->priv;
-	ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
 
-	printk (KERN_NOTICE "%s: SMC91c92 transmit timed out, "
-		"Tx_status %2.2x status %4.4x.\n",
-		dev->name, inw (ioaddr) & 0xff, inw (ioaddr + 2));
-	smc->stats.tx_errors++;
-	smc_reset (dev);
-	dev->trans_start = jiffies;
-	smc->saved_skb = NULL;
-	netif_start_queue (dev);
+    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
+	   "Tx_status %2.2x status %4.4x.\n",
+	   dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
+    smc->stats.tx_errors++;
+    smc_reset(dev);
+    dev->trans_start = jiffies;
+    smc->saved_skb = NULL;
+    netif_start_queue(dev);
 }
 
-
-/*====================================================================*/
-
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
-    unsigned short num_pages;
+    u_short num_pages;
     short time_out, ir;
-    
+
+    netif_stop_queue(dev);
+
     DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
 	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
 
-    netif_stop_queue (dev);
-    
-    if ( smc->saved_skb) {
+    if (smc->saved_skb) {
 	/* THIS SHOULD NEVER HAPPEN. */
 	smc->stats.tx_aborted_errors++;
 	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
@@ -1390,10 +1343,10 @@
     /* A packet is now waiting. */
     smc->packets_waiting++;
     
-    SMC_SELECT_BANK( 2 );	/* Paranoia, we should always be in window 2 */
+    SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
     
     /* Allocate the memory; send the packet now if we win. */
-    outw( MC_ALLOC | num_pages, ioaddr + MMU_CMD );
+    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
     for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
 	ir = inw(ioaddr+INTERRUPT);
 	if (ir & IM_ALLOC_INT) {
@@ -1417,7 +1370,7 @@
     
 ======================================================================*/
 
-static void smc_tx_err( struct net_device * dev )
+static void smc_tx_err(struct net_device * dev)
 {
     struct smc_private *smc = (struct smc_private *)dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
@@ -1426,10 +1379,10 @@
     int tx_status;
     
     /* select this as the packet to read from */
-    outw( packet_no, ioaddr + PNR_ARR );
+    outw(packet_no, ioaddr + PNR_ARR);
     
     /* read the first word from this packet */
-    outw( PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER );
+    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
     
     tx_status = inw(ioaddr + DATA_1);
 
@@ -1441,21 +1394,21 @@
 	smc->tx_err++;
     }
     
-    if ( tx_status & TS_SUCCESS ) {
+    if (tx_status & TS_SUCCESS) {
 	printk(KERN_NOTICE "%s: Successful packet caused error "
 	       "interrupt?\n", dev->name);
     }
     /* re-enable transmit */
-    SMC_SELECT_BANK( 0 );
-    outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
-    SMC_SELECT_BANK( 2 );
+    SMC_SELECT_BANK(0);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    SMC_SELECT_BANK(2);
     
-    outw( MC_FREEPKT, ioaddr + MMU_CMD ); 	/* Free the packet memory. */
+    outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
     
     /* one less packet waiting for me */
     smc->packets_waiting--;
     
-    outw( saved_packet, ioaddr + PNR_ARR );
+    outw(saved_packet, ioaddr + PNR_ARR);
     return;
 }
 
@@ -1465,14 +1418,14 @@
 {
     struct smc_private *smc = dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
-    unsigned short card_stats, ephs;
+    u_short card_stats, ephs;
     
     SMC_SELECT_BANK(0);
     ephs = inw(ioaddr + EPH);
     DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
 	  " %4.4x.\n", dev->name, ephs);
     /* Could be a counter roll-over warning: update stats. */
-    card_stats = inw( ioaddr + COUNTER );
+    card_stats = inw(ioaddr + COUNTER);
     /* single collisions */
     smc->stats.collisions += card_stats & 0xF;
     card_stats >>= 4;
@@ -1483,7 +1436,7 @@
     card_stats >>= 4;			/* excess deferred */
 #endif
     /* If we had a transmit error we must re-enable the transmitter. */
-    outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
 
     /* Clear a link error interrupt. */
     SMC_SELECT_BANK(1);
@@ -1503,12 +1456,10 @@
     u_short saved_bank, saved_pointer, mask, status;
     char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
 
-    if ((smc == NULL) || !netif_device_present(dev))
+    if (!netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
     
-    spin_lock (&smc->lock);
-
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
     
@@ -1517,11 +1468,8 @@
     if ((saved_bank & 0xff00) != 0x3300) {
 	/* The device does not exist -- the card could be off-line, or
 	   maybe it has been ejected. */
-#ifdef PCMCIA_DEBUG
-	if (dev->start)
-	    DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
-		  "/ejected device.\n", dev->name, irq);
-#endif
+	DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
+	      "/ejected device.\n", dev->name, irq);
 	goto irq_done;
     }
     
@@ -1529,7 +1477,7 @@
     saved_pointer = inw(ioaddr + POINTER);
     mask = inw(ioaddr + INTERRUPT) >> 8;
     /* clear all interrupts */
-    outw( 0, ioaddr + INTERRUPT );
+    outw(0, ioaddr + INTERRUPT);
     
     do { /* read the status flag, and mask it */
 	status = inw(ioaddr + INTERRUPT) & 0xff;
@@ -1561,10 +1509,10 @@
 	    smc_hardware_send_packet(dev);
 	    
 	    /* enable xmit interrupts based on this */
-	    mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
+	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
 	    
 	    /* and let the card send more packets to me */
-	    netif_wake_queue (dev);
+	    netif_wake_queue(dev);
 	}
 	if (status & IM_RX_OVRN_INT) {
 	    smc->stats.rx_errors++;
@@ -1573,7 +1521,7 @@
 	}
 	if (status & IM_EPH_INT)
 	    smc_eph_irq(dev);
-    } while ( --bogus_cnt);
+    } while (--bogus_cnt);
 
     DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
 	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
@@ -1581,9 +1529,7 @@
     /* restore state register */
     outw((mask<<8), ioaddr + INTERRUPT);
     outw(saved_pointer, ioaddr + POINTER);
-    SMC_SELECT_BANK( saved_bank );
-
-    spin_unlock (&smc->lock);
+    SMC_SELECT_BANK(saved_bank);
 
     DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 
@@ -1631,24 +1577,24 @@
     }
     
     /*  Reset the read pointer, and read the status and packet length. */
-    outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
+    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
     rx_status = inw(ioaddr + DATA_1);
     packet_length = inw(ioaddr + DATA_1) & 0x07ff;
 
     DEBUG(2, "%s: Receive status %4.4x length %d.\n",
 	  dev->name, rx_status, packet_length);
     
-    if ( !(rx_status & RS_ERRORS )) {		
+    if (!(rx_status & RS_ERRORS)) {		
 	/* do stuff to make a new packet */
 	struct sk_buff *skb;
 	
 	/* Note: packet_length adds 5 or 6 extra bytes here! */
 	skb = dev_alloc_skb(packet_length+2);
 	
-	if ( skb == NULL ) {
+	if (skb == NULL) {
 	    DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
 	    smc->stats.rx_dropped++;
-	    outw( MC_RELEASE, ioaddr + MMU_CMD );
+	    outw(MC_RELEASE, ioaddr + MMU_CMD);
 	    return;
 	}
 	
@@ -1694,14 +1640,14 @@
 
 ======================================================================*/
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
+static const u_int ethernet_polynomial = 0x04c11db7U;
 
-static unsigned ether_crc(int length, unsigned char *data)
+static u_int ether_crc(int length, u_char *data)
 {
     int crc = 0xffffffff;	/* Initial value. */
     
     while (--length >= 0) {
-	unsigned char current_octet = *data++;
+	u_char current_octet = *data++;
 	int bit;
 	for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
 	    crc = (crc << 1) ^
@@ -1721,14 +1667,14 @@
 ======================================================================*/
 
 static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
-			       unsigned char *multicast_table)
+			       u_char *multicast_table)
 {
     struct dev_mc_list	*mc_addr;
     
     for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
-	unsigned int position = ether_crc(6, mc_addr->dmi_addr);
+	u_int position = ether_crc(6, mc_addr->dmi_addr);
 #ifndef final_version		/* Verify multicast address. */
-	if ( (mc_addr->dmi_addr[0] & 1) == 0)
+	if ((mc_addr->dmi_addr[0] & 1) == 0)
 	    continue;
 #endif
 	multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
@@ -1749,9 +1695,9 @@
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
-    unsigned int multicast_table[ 2 ] = { 0, };
+    u_int multicast_table[ 2 ] = { 0, };
     long flags;
-    uint16 rx_cfg_setting;
+    u_short rx_cfg_setting;
     
     if (dev->flags & IFF_PROMISC) {
 	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
@@ -1761,7 +1707,7 @@
     else {
 	if (dev->mc_count)  {
 	    fill_multicast_tbl(dev->mc_count, dev->mc_list,
-			       (unsigned char *)multicast_table);
+			       (u_char *)multicast_table);
 	}
 	rx_cfg_setting = RxStripCRC | RxEnable;
     }
@@ -1769,7 +1715,7 @@
     /* Load MC table and Rx setting into the chip without interrupts. */
     save_flags(flags);
     cli();
-    SMC_SELECT_BANK( 3 );
+    SMC_SELECT_BANK(3);
     outl(multicast_table[0], ioaddr + MULTICAST0);
     outl(multicast_table[1], ioaddr + MULTICAST4);
     SMC_SELECT_BANK(0);
@@ -1846,14 +1792,14 @@
     
     /* The first interaction must be a write to bring the chip out
        of sleep mode. */
-    SMC_SELECT_BANK( 0 );
+    SMC_SELECT_BANK(0);
     /* Reset the chip. */
-    outw( RCR_SOFTRESET, ioaddr + RCR );
+    outw(RCR_SOFTRESET, ioaddr + RCR);
     udelay(10);
     
     /* Clear the transmit and receive configuration registers. */
-    outw( RCR_CLEAR, ioaddr + RCR );
-    outw( TCR_CLEAR, ioaddr + TCR );
+    outw(RCR_CLEAR, ioaddr + RCR);
+    outw(TCR_CLEAR, ioaddr + TCR);
     
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
@@ -1879,8 +1825,8 @@
     
     /* Reset the MMU */
     SMC_SELECT_BANK(2);
-    outw(MC_RESET, ioaddr + MMU_CMD );
-    outw(0, ioaddr + INTERRUPT );
+    outw(MC_RESET, ioaddr + MMU_CMD);
+    outw(0, ioaddr + INTERRUPT);
     
     /* Re-enable the chip. */
     SMC_SELECT_BANK(0);
@@ -1889,9 +1835,9 @@
     set_rx_mode(dev);
 
     /* Enable interrupts. */
-    SMC_SELECT_BANK( 2 );
-    outw( (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
-	  ioaddr + INTERRUPT );
+    SMC_SELECT_BANK(2);
+    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
+	 ioaddr + INTERRUPT);
 }
 
 /*======================================================================
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/wavelan_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Thu May  4 11:24:42 2000
@@ -2926,7 +2926,7 @@
   lp->stats.tx_bytes += length;
 
   /* If watchdog not already active, activate it... */
-  if(lp->watchdog.prev == (timer_list *) NULL)
+  if (!timer_pending(&lp->watchdog))
     {
       /* set timer to expire in WATCHDOG_JIFFIES */
       lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
@@ -3655,7 +3655,7 @@
 #endif
 
   /* If watchdog was activated, kill it ! */
-  if(lp->watchdog.prev != (timer_list *) NULL)
+  if (timer_pending(&lp->watchdog))
     del_timer(&lp->watchdog);
 
   lp->nresets++;
@@ -4061,7 +4061,7 @@
 #endif
 
 	  /* If watchdog was activated, kill it ! */
-	  if(lp->watchdog.prev != (timer_list *) NULL)
+	  if(timer_pending(&lp->watchdog))
 	    del_timer(&lp->watchdog);
 
 	  /* Get transmission status */
@@ -4353,7 +4353,7 @@
 #endif	/* WAVELAN_ROAMING */
 
   /* If watchdog was activated, kill it ! */
-  if(lp->watchdog.prev != (timer_list *) NULL)
+  if(timer_pending(&lp->watchdog))
     del_timer(&lp->watchdog);
 
   link->open--;
@@ -4498,8 +4498,7 @@
 #endif
 
   /* Other specific data */
-  /* Provide storage area for device name */
-  dev->name = ((net_local *)dev->priv)->node.dev_name;
+  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
   netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/xirc2ps_cs.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Mon May  8 21:26:05 2000
@@ -407,20 +407,18 @@
     int new_mii; /* has full 10baseT/100baseT MII */
     int modem;	 /* is a multi function card (i.e with a modem) */
     caddr_t dingo_ccr; /* only used for CEM56 cards */
-    int suspended;
     unsigned last_ptr_value; /* last packets transmitted value */
     const char *manf_str;
-    spinlock_t lock;
 } local_info_t;
 
 /****************
  * Some more prototypes
  */
 static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void do_tx_timeout(struct net_device *dev);
 static struct enet_statistics *do_get_stats(struct net_device *dev);
 static void set_addresses(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static int do_init(struct net_device *dev);
 static int set_card_type(dev_link_t *link, const void *s);
 static int do_config(struct net_device *dev, struct ifmap *map);
 static int do_open(struct net_device *dev);
@@ -430,7 +428,6 @@
 static int init_mii(struct net_device *dev);
 static void do_powerdown(struct net_device *dev);
 static int do_stop(struct net_device *dev);
-static void xirc_tx_timeout (struct net_device *dev);
 
 /*=============== Helper functions =========================*/
 static void
@@ -693,8 +690,6 @@
     local = kmalloc(sizeof(*local), GFP_KERNEL);
     if (!local) return NULL;
     memset(local, 0, sizeof(*local));
-    
-    local->lock = SPIN_LOCK_UNLOCKED;
     link = &local->link; dev = &local->dev;
     link->priv = dev->priv = local;
 
@@ -717,13 +712,10 @@
     dev->do_ioctl = &do_ioctl;
     dev->set_multicast_list = &set_multicast_list;
     ether_setup(dev);
-    dev->name = local->node.dev_name;
-    dev->init = &do_init;
     dev->open = &do_open;
     dev->stop = &do_stop;
-    dev->tx_timeout = xirc_tx_timeout;
+    dev->tx_timeout = do_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
-    netif_start_queue(dev);
 
     /* Register with Card Services */
     link->next = dev_list;
@@ -758,7 +750,6 @@
 {
     local_info_t *local = link->priv;
     dev_link_t **linkp;
-    long flags;
 
     DEBUG(0, "detach(0x%p)\n", link);
 
@@ -771,20 +762,13 @@
 	return;
     }
 
-    save_flags(flags);
-    cli();
-    if (link->state & DEV_RELEASE_PENDING) {
-	del_timer(&link->release);
-	link->state &= ~DEV_RELEASE_PENDING;
-    }
-    restore_flags(flags);
-
     /*
      * If the device is currently configured and active, we won't
      * actually delete it yet.	Instead, it is marked so that when
      * the release() function is called, that will trigger a proper
      * detach().
      */
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	DEBUG(0, "detach postponed, '%s' still locked\n",
 	      link->dev->dev_name);
@@ -1171,8 +1155,7 @@
 	 * memory and write direct to the CIS registers
 	 */
 	req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-	req.Base = 0;
-	req.Size = 0x1000; /* 4k window */
+	req.Base = req.Size = 0;
 	req.AccessSpeed = 0;
 	link->win = (window_handle_t)link->handle;
 	if ((err = CardServices(RequestWindow, &link->win, &req))) {
@@ -1239,13 +1222,13 @@
     /* we can now register the device with the net subsystem */
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    netif_start_queue(dev);
     if ((err=register_netdev(dev))) {
 	printk(KNOT_XIRC "register_netdev() failed\n");
 	goto config_error;
     }
 
     link->state &= ~DEV_CONFIG_PENDING;
+    strcpy(local->node.dev_name, dev->name);
     link->dev = &local->node;
 
     if (local->dingo)
@@ -1305,7 +1288,7 @@
     CardServices(ReleaseConfiguration, link->handle);
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    link->state &= ~DEV_CONFIG;
 
 } /* xirc2ps_release */
 
@@ -1334,47 +1317,44 @@
     DEBUG(0, "event(%d)\n", (int)event);
 
     switch (event) {
-      case CS_EVENT_REGISTRATION_COMPLETE:
-	  DEBUG(0, "registration complete\n");
-	  break;
-      case CS_EVENT_CARD_REMOVAL:
-	  link->state &= ~DEV_PRESENT;
-	  if (link->state & DEV_CONFIG) {
-	      netif_device_detach(dev);
-	      link->release.expires = jiffies + HZ / 20;
-	      add_timer(&link->release);
-	  }
-	  break;
-      case CS_EVENT_CARD_INSERTION:
-	  link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	  xirc2ps_config(link);
-	  break;
-      case CS_EVENT_PM_SUSPEND:
-	  link->state |= DEV_SUSPEND;
-	  /* Fall through... */
-      case CS_EVENT_RESET_PHYSICAL:
-	  if (link->state & DEV_CONFIG) {
-	      if (link->open) {
-		  netif_device_detach(dev);
-		  lp->suspended=1;
-		  do_powerdown(dev);
-	      }
-	      CardServices(ReleaseConfiguration, link->handle);
-	  }
-	  break;
-      case CS_EVENT_PM_RESUME:
-	  link->state &= ~DEV_SUSPEND;
-	  /* Fall through... */
-      case CS_EVENT_CARD_RESET:
-	  if (link->state & DEV_CONFIG) {
-	     CardServices(RequestConfiguration, link->handle, &link->conf);
-	     if (link->open) {
-		 do_reset(dev,1);
-		 lp->suspended=0;
-		 netif_device_attach(dev);
-	     }
-	  }
-	  break;
+    case CS_EVENT_REGISTRATION_COMPLETE:
+	DEBUG(0, "registration complete\n");
+	break;
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	xirc2ps_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		netif_device_detach(dev);
+		do_powerdown(dev);
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		do_reset(dev,1);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
     }
     return 0;
 } /* xirc2ps_event */
@@ -1399,7 +1379,6 @@
 				  * -- on a laptop?
 				  */
 
-    spin_lock (&lp->lock);
     if (!netif_device_present(dev))
 	return;
 
@@ -1596,9 +1575,6 @@
 	    goto loop_entry;
     }
     SelectPage(saved_page);
-
-    spin_unlock (&lp->lock);
-
     PutByte(XIRCREG_CR, EnableIntr);  /* re-enable interrupts */
     /* Instead of dropping packets during a receive, we could
      * force an interrupt with this command:
@@ -1608,26 +1584,18 @@
 
 /*====================================================================*/
 
-static void xirc_tx_timeout (struct net_device *dev)
+static void
+do_tx_timeout(struct net_device *dev)
 {
-	local_info_t *lp = dev->priv;
-
-	if (lp->suspended) {
-	    dev->trans_start = jiffies;
-	    lp->stats.tx_dropped++;
-	    netif_start_queue(dev);
-	    return;
-	}
-
-	printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
-	lp->stats.tx_errors++;
-	/* reset the card */
-	do_reset(dev,1);
-	dev->trans_start = jiffies;
-	netif_start_queue(dev);
+    local_info_t *lp = dev->priv;
+    printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+    lp->stats.tx_errors++;
+    /* reset the card */
+    do_reset(dev,1);
+    dev->trans_start = jiffies;
+    netif_start_queue(dev);
 }
 
-
 static int
 do_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -1675,8 +1643,8 @@
 
     dev_kfree_skb (skb);
     dev->trans_start = jiffies;
-    netif_start_queue(dev);
     lp->stats.tx_bytes += pktlen;
+    netif_start_queue(dev);
     return 0;
 }
 
@@ -1760,17 +1728,6 @@
     SelectPage(0);
 }
 
-/****************
- * We never need to do anything when a IIps device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-do_init(struct net_device *dev)
-{
-    DEBUG(0, "do_init(%p)\n", dev);
-    return 0;
-}
-
 static int
 do_config(struct net_device *dev, struct ifmap *map)
 {
@@ -1821,7 +1778,6 @@
     MOD_INC_USE_COUNT;
 
     netif_start_queue(dev);
-    lp->suspended = 0;
     do_reset(dev,1);
 
     return 0;
@@ -2149,11 +2105,8 @@
     SelectPage(0);
 
     link->open--;
-    if (link->state & DEV_STALE_CONFIG) {
-	link->release.expires = jiffies + HZ/20;
-	link->state |= DEV_RELEASE_PENDING;
-	add_timer(&link->release);
-    }
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
 
     MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- v2.3.99-pre6/linux/drivers/net/pcmcia/xircom_tulip_cb.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Apr 28 23:00:05 2000
@@ -3078,7 +3078,8 @@
 
 	printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
 
-	pci_enable_device (pdev);
+	if (pci_enable_device (pdev))
+		return -ENODEV;
 	pci_set_master (pdev);
 	dev = tulip_probe1(pdev, NULL,
 			   pci_resource_start (pdev, 0), pdev->irq,
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.3.99-pre6/linux/drivers/net/pcnet32.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/pcnet32.c	Wed May  3 09:38:15 2000
@@ -1,21 +1,20 @@
 /* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
 /*
- *      Copyright 1996-1999 Thomas Bogendoerfer
+ *	Copyright 1996-1999 Thomas Bogendoerfer
  * 
- * 	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ *	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
  * 
- * 	Copyright 1993 United States Government as represented by the
- * 	Director, National Security Agency.
+ *	Copyright 1993 United States Government as represented by the
+ *	Director, National Security Agency.
  * 
- * 	This software may be used and distributed according to the terms
- * 	of the GNU Public License, incorporated herein by reference.
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
  *
- * 	This driver is for PCnet32 and PCnetPCI based ethercards
+ *	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
 static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -56,30 +55,31 @@
 #define PORT_PORTSEL  0x03
 #define PORT_ASEL     0x04
 #define PORT_100      0x40
-#define PORT_FD       0x80
+#define PORT_FD	      0x80
 
+#define PCNET32_DMA_MASK 0xffffffff
 
 /*
  * table to translate option values from tulip
  * to internal options
  */
 static unsigned char options_mapping[] = {
-    PORT_ASEL,			   /*  0 Auto-select      */
-    PORT_AUI,			   /*  1 BNC/AUI          */
-    PORT_AUI,			   /*  2 AUI/BNC          */ 
-    PORT_ASEL,			   /*  3 not supported    */
-    PORT_10BT | PORT_FD,	   /*  4 10baseT-FD       */
-    PORT_ASEL,			   /*  5 not supported    */
-    PORT_ASEL,			   /*  6 not supported    */
-    PORT_ASEL,			   /*  7 not supported    */
-    PORT_ASEL,			   /*  8 not supported    */
-    PORT_MII,		           /*  9 MII 10baseT      */
-    PORT_MII | PORT_FD,            /* 10 MII 10baseT-FD   */
-    PORT_MII,			   /* 11 MII (autosel)    */
+    PORT_ASEL,			   /*  0 Auto-select	  */
+    PORT_AUI,			   /*  1 BNC/AUI	  */
+    PORT_AUI,			   /*  2 AUI/BNC	  */ 
+    PORT_ASEL,			   /*  3 not supported	  */
+    PORT_10BT | PORT_FD,	   /*  4 10baseT-FD	  */
+    PORT_ASEL,			   /*  5 not supported	  */
+    PORT_ASEL,			   /*  6 not supported	  */
+    PORT_ASEL,			   /*  7 not supported	  */
+    PORT_ASEL,			   /*  8 not supported	  */
+    PORT_MII,			   /*  9 MII 10baseT	  */
+    PORT_MII | PORT_FD,		   /* 10 MII 10baseT-FD	  */
+    PORT_MII,			   /* 11 MII (autosel)	  */
     PORT_10BT,			   /* 12 10BaseT	  */
-    PORT_MII | PORT_100,	   /* 13 MII 100BaseTx    */
+    PORT_MII | PORT_100,	   /* 13 MII 100BaseTx	  */
     PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */
-    PORT_ASEL			   /* 15 not supported    */
+    PORT_ASEL			   /* 15 not supported	  */
 };
 
 #define MAX_UNITS 8
@@ -87,7 +87,7 @@
 static int full_duplex[MAX_UNITS] = {0, };
 
 /*
- * 				Theory of Operation
+ *				Theory of Operation
  * 
  * This driver uses the same software structure as the normal lance
  * driver. So look for a verbose description in lance.c. The differences
@@ -99,21 +99,21 @@
 /*
  * History:
  * v0.01:  Initial version
- *         only tested on Alpha Noname Board
+ *	   only tested on Alpha Noname Board
  * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
- *         tested on a ASUS SP3G
+ *	   tested on a ASUS SP3G
  * v0.10:  fixed an odd problem with the 79C974 in a Compaq Deskpro XL
- *         looks like the 974 doesn't like stopping and restarting in a
- *         short period of time; now we do a reinit of the lance; the
- *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
- *         and hangs the machine (thanks to Klaus Liedl for debugging)
+ *	   looks like the 974 doesn't like stopping and restarting in a
+ *	   short period of time; now we do a reinit of the lance; the
+ *	   bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ *	   and hangs the machine (thanks to Klaus Liedl for debugging)
  * v0.12:  by suggestion from Donald Becker: Renamed driver to pcnet32,
- *         made it standalone (no need for lance.c)
+ *	   made it standalone (no need for lance.c)
  * v0.13:  added additional PCI detecting for special PCI devices (Compaq)
  * v0.14:  stripped down additional PCI probe (thanks to David C Niemi
- *         and sveneric@xs4all.nl for testing this on their Compaq boxes)
+ *	   and sveneric@xs4all.nl for testing this on their Compaq boxes)
  * v0.15:  added 79C965 (VLB) probe
- *         added interrupt sharing for PCI chips
+ *	   added interrupt sharing for PCI chips
  * v0.16:  fixed set_multicast_list on Alpha machines
  * v0.17:  removed hack from dev.c; now pcnet32 uses ethif_probe in Space.c
  * v0.19:  changed setting of autoselect bit
@@ -123,42 +123,44 @@
  * v0.22:  added printing of status to ring dump
  * v0.23:  changed enet_statistics to net_devive_stats
  * v0.90:  added multicast filter
- *         added module support
- *         changed irq probe to new style
- *         added PCnetFast chip id
- *         added fix for receive stalls with Intel saturn chipsets
- *         added in-place rx skbs like in the tulip driver
- *         minor cleanups
+ *	   added module support
+ *	   changed irq probe to new style
+ *	   added PCnetFast chip id
+ *	   added fix for receive stalls with Intel saturn chipsets
+ *	   added in-place rx skbs like in the tulip driver
+ *	   minor cleanups
  * v0.91:  added PCnetFast+ chip id
- *         back port to 2.0.x
+ *	   back port to 2.0.x
  * v1.00:  added some stuff from Donald Becker's 2.0.34 version
- *         added support for byte counters in net_dev_stats
+ *	   added support for byte counters in net_dev_stats
  * v1.01:  do ring dumps, only when debugging the driver
- *         increased the transmit timeout
+ *	   increased the transmit timeout
  * v1.02:  fixed memory leak in pcnet32_init_ring()
  * v1.10:  workaround for stopped transmitter
- *         added port selection for modules
- *         detect special T1/E1 WAN card and setup port selection
+ *	   added port selection for modules
+ *	   detect special T1/E1 WAN card and setup port selection
  * v1.11:  fixed wrong checking of Tx errors
  * v1.20:  added check of return value kmalloc (cpeterso@cs.washington.edu)
- *         added save original kmalloc addr for freeing (mcr@solidum.com)
- *         added support for PCnetHome chip (joe@MIT.EDU)
- *         rewritten PCI card detection
- *         added dwio mode to get driver working on some PPC machines
+ *	   added save original kmalloc addr for freeing (mcr@solidum.com)
+ *	   added support for PCnetHome chip (joe@MIT.EDU)
+ *	   rewritten PCI card detection
+ *	   added dwio mode to get driver working on some PPC machines
  * v1.21:  added mii selection and mii ioctl
  * v1.22:  changed pci scanning code to make PPC people happy
- *         fixed switching to 32bit mode in pcnet32_open() (thanks
- *         to Michael Richard <mcr@solidum.com> for noticing this one)
+ *	   fixed switching to 32bit mode in pcnet32_open() (thanks
+ *	   to Michael Richard <mcr@solidum.com> for noticing this one)
  *	   added sub vendor/device id matching (thanks again to 
  *	   Michael Richard <mcr@solidum.com>)
- *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
+ *	   added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
  * v1.24   Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
- *         underflows.  Added tx_start_pt module parameter. Increased
- *         TX_RING_SIZE from 16 to 32.  Added #ifdef'd code to use DXSUFLO
- *         for FAST[+] chipsets. <kaf@fc.hp.com>
+ *	   underflows.	Added tx_start_pt module parameter. Increased
+ *	   TX_RING_SIZE from 16 to 32.	Added #ifdef'd code to use DXSUFLO
+ *	   for FAST[+] chipsets. <kaf@fc.hp.com>
  * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
  * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
+ * v1.26   Converted to pci_alloc_consistent, Jamey Hicks / George France
+ *                                           <jamey@crl.dec.com>
  */
 
 
@@ -205,13 +207,13 @@
 #endif
 
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
     u32 base;
     s16 buf_length;
-    s16 status;    
+    s16 status;	   
     u32 msg_length;
     u32 reserved;
 };
@@ -228,7 +230,7 @@
 struct pcnet32_init_block {
     u16 mode;
     u16 tlen_rlen;
-    u8  phys_addr[6];
+    u8	phys_addr[6];
     u16 reserved;
     u32 filter[2];
     /* Receive and transmit ring base, along with extra bits. */    
@@ -247,35 +249,43 @@
     void (*reset)(unsigned long);
 };
 
+/*
+ * The first three fields of pcnet32_private are read by the ethernet device 
+ * so we allocate the structure should be allocated by pci_alloc_consistent().
+ */
 struct pcnet32_private {
     /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
     struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
     struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
     struct pcnet32_init_block	init_block;
+    dma_addr_t dma_addr;		/* DMA address of beginning of this object, returned by pci_alloc_consistent */
+    struct pci_dev *pci_dev;		/* Pointer to the associated pci device structure */
     const char *name;
     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
     struct sk_buff *tx_skbuff[TX_RING_SIZE];
     struct sk_buff *rx_skbuff[RX_RING_SIZE];
+    dma_addr_t tx_dma_addr[TX_RING_SIZE];
+    dma_addr_t rx_dma_addr[RX_RING_SIZE];
     struct pcnet32_access a;
-    void *origmem;
-    spinlock_t lock;				/* Guard lock */
+    spinlock_t lock;					/* Guard lock */
     unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-    unsigned int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
+    unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
     struct net_device_stats stats;
     char tx_full;
-    int  options;
-    int  shared_irq:1,                      	/* shared irq possible */
-	 ltint:1,
+    int	 options;
+    int	 shared_irq:1,			/* shared irq possible */
+	ltint:1,
 #ifdef DO_DXSUFLO
-	 dxsuflo:1,			    /* disable transmit stop on uflo */
+	      dxsuflo:1,						    /* disable transmit stop on uflo */
 #endif
-         full_duplex:1,                     	/* full duplex possible */
-         mii:1;                             	/* mii port available */
+	full_duplex:1,				/* full duplex possible */
+	mii:1;					/* mii port available */
     struct net_device *next;
 };
 
-static int  pcnet32_probe(void);
-static int  pcnet32_probe1(unsigned long, unsigned char, int, int);
+static int  pcnet32_probe_vlbus(int cards_found);
+static int  pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
+static int  pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *);
 static int  pcnet32_open(struct net_device *);
 static int  pcnet32_init_ring(struct net_device *);
 static int  pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -298,25 +308,35 @@
     const char *name;
     u16 vendor_id, device_id, svid, sdid, flags;
     int io_size;
-    int (*probe1) (unsigned long, unsigned char, int, int);
+    int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
 };
 
 static struct pcnet32_pci_id_info pcnet32_tbl[] = {
     { "AMD PCnetPCI series",
-	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
-	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
-	pcnet32_probe1},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
+      PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+      pcnet32_probe1},
     { "AMD PCnetPCI series (IBM)",
-	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
-	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
-	pcnet32_probe1},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+      PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+      pcnet32_probe1},
     { "AMD PCnetHome series",
-	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
-	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
-	pcnet32_probe1},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
+      PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+      pcnet32_probe1},
     {0,}
 };
 
+/*
+ * PCI device identifiers for "new style" Linux PCI Device Drivers
+ */
+static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = {
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 },
+    { 0, 0, 0, 0, 0, 0, 0 },
+};
+
 static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
 {
     outw (index, addr+PCNET32_WIO_RAP);
@@ -430,96 +450,83 @@
 
 
 
-static int __init pcnet32_probe(void)
+/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/
+static int __init pcnet32_probe_vlbus(int cards_found)
 {
     unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0;
     unsigned int  irq_line = 0; // FIXME dev ? dev->irq : 0;
     int *port;
-    int cards_found = 0;
-    
     
+    printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);
 #ifndef __powerpc__
     if (ioaddr > 0x1ff) {
 	if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
-	    return pcnet32_probe1(ioaddr, irq_line, 0, 0);
+	    return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL);
 	else
-	    return ENODEV;
+	    return -ENODEV;
     } else
 #endif
-	if(ioaddr != 0)
-	    return ENXIO;
-    
-#if defined(CONFIG_PCI)
-    if (pci_present()) {
-	struct pci_dev *pdev = NULL;
-	
-	printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-	while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
-	    u16 pci_command;
-	    int chip_idx;
-	    u16 sdid,svid;
-
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
-	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
-		if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
-		    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
-		    (pcnet32_tbl[chip_idx].svid == 0 || 
-		     (svid == pcnet32_tbl[chip_idx].svid)) &&
-		    (pcnet32_tbl[chip_idx].sdid == 0 || 
-		     (sdid == pcnet32_tbl[chip_idx].sdid)))
-		    break;
-	    if (pcnet32_tbl[chip_idx].vendor_id == 0)
-		continue;
-	    
-	    ioaddr = pdev->resource[0].start;
-	    irq_line = pdev->irq;
-	    
-	    /* Avoid already found cards from previous pcnet32_probe() calls */
-	    if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) &&
-		check_region(ioaddr, pcnet32_tbl[chip_idx].io_size))
-		continue;
-
-	    /* PCI Spec 2.1 states that it is either the driver or PCI card's
-	     * responsibility to set the PCI Master Enable Bit if needed.
-	     *	(From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
-	     */
-	    pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	    if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-		printk("PCI Master Bit has not been set. Setting...\n");
-		pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-	    }
-	    printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line);
-	    
-	    if (pcnet32_tbl[chip_idx].probe1(ioaddr, irq_line, 1, cards_found) == 0) {
-		cards_found++;
-	    }
-	}
-    } else 
-#endif  /* defined(CONFIG_PCI) */
+	if (ioaddr != 0)
+	    return -ENXIO;
     
     /* now look for PCnet32 VLB cards */
     for (port = pcnet32_portlist; *port; port++) {
 	unsigned long ioaddr = *port;
 	
 	if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
-    	    /* check if there is really a pcnet chip on that ioaddr */
-    	    if ((inb(ioaddr + 14) == 0x57) &&
+	    /* check if there is really a pcnet chip on that ioaddr */
+	    if ((inb(ioaddr + 14) == 0x57) &&
 		(inb(ioaddr + 15) == 0x57) &&
-	        (pcnet32_probe1(ioaddr, 0, 0, 0) == 0))
+		(pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0))
 		cards_found++;
 	}
     }
-    return cards_found ? 0: ENODEV;
+    return cards_found ? 0: -ENODEV;
 }
 
 
-/* pcnet32_probe1 */
+
 static int __init
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx)
+pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+    static int card_idx = 0;
+    long ioaddr;
+    int err = 0;
+
+    printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
+
+    ioaddr = pci_resource_start (pdev, 0);
+    printk(KERN_INFO "  ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
+    if (!ioaddr) {
+        printk (KERN_ERR "no PCI IO resources, aborting\n");
+        return -ENODEV;
+    }
+	
+    if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
+	printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n");
+	return -ENODEV;
+    }
+
+    if ((err = pci_enable_device(pdev)) < 0) {
+	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
+	return err;
+    }
+    
+    pci_set_master(pdev);
+    
+    return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);
+}
+
+
+/* pcnet32_probe1 
+ *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.  
+ *  pdev will be NULL when called from pcnet32_probe_vlbus.
+ */
+static int __init
+pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
+    dma_addr_t lp_dma_addr;
     int i,media,fdx = 0, mii = 0, fset = 0;
 #ifdef DO_DXSUFLO
     int dxsuflo = 0;
@@ -527,9 +534,8 @@
     int ltint = 0;
     int chip_version;
     char *chipname;
-    char *priv;
     struct net_device *dev;
-    struct pcnet32_access *a;
+    struct pcnet32_access *a = NULL;
 
     /* reset the chip */
     pcnet32_dwio_reset(ioaddr);
@@ -541,44 +547,44 @@
 	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
-	    return ENODEV;
+	    return -ENODEV;
     }
 
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
-	printk("  PCnet chip version is %#x.\n", chip_version);
+	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
-	return ENODEV;
+	return -ENODEV;
     chip_version = (chip_version >> 12) & 0xffff;
     switch (chip_version) {
-     case 0x2420:
-	chipname = "PCnet/PCI 79C970";
+    case 0x2420:
+	chipname = "PCnet/PCI 79C970"; /* PCI */
 	break;
-     case 0x2430:
+    case 0x2430:
 	if (shared)
 	    chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
 	else
-	    chipname = "PCnet/32 79C965";
+	    chipname = "PCnet/32 79C965"; /* 486/VL bus */
 	break;
-     case 0x2621:
-	chipname = "PCnet/PCI II 79C970A";
+    case 0x2621:
+	chipname = "PCnet/PCI II 79C970A"; /* PCI */
 	fdx = 1;
 	break;
-     case 0x2623:
-	chipname = "PCnet/FAST 79C971";
+    case 0x2623:
+	chipname = "PCnet/FAST 79C971"; /* PCI */
 	fdx = 1; mii = 1; fset = 1;
 	ltint = 1;
 	break;
-     case 0x2624:
-	chipname = "PCnet/FAST+ 79C972";
+    case 0x2624:
+	chipname = "PCnet/FAST+ 79C972"; /* PCI */
 	fdx = 1; mii = 1; fset = 1;
 	break;
-     case 0x2625:
-	chipname = "PCnet/FAST III 79C973";
+    case 0x2625:
+	chipname = "PCnet/FAST III 79C973"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
-     case 0x2626:
-	chipname = "PCnet/Home 79C978";
+    case 0x2626:
+	chipname = "PCnet/Home 79C978"; /* PCI */
 	fdx = 1;
 	/* 
 	 * This is based on specs published at www.amd.com.  This section
@@ -589,33 +595,35 @@
 	 */
 	/* switch to home wiring mode */
 	media = a->read_bcr (ioaddr, 49);
+#if 0
 	if (pcnet32_debug > 2)
-	    printk("pcnet32: pcnet32 media value %#x.\n",  media);
+	    printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n",  media);
 	media &= ~3;
 	media |= 1;
+#endif
 	if (pcnet32_debug > 2)
-	    printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
+	    printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n",  media);
 	a->write_bcr (ioaddr, 49, media);
 	break;
-     case 0x2627:
-	chipname = "PCnet/FAST III 79C975";
+    case 0x2627:
+	chipname = "PCnet/FAST III 79C975"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
-     default:
-	printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-	return ENODEV;
+    default:
+	printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+	return -ENODEV;
     }
 
     /*
      *	On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
-     *  starting until the packet is loaded. Strike one for reliability, lose
-     *  one for latency - although on PCI this isnt a big loss. Older chips 
-     *  have FIFO's smaller than a packet, so you can't do this.
+     *	starting until the packet is loaded. Strike one for reliability, lose
+     *	one for latency - although on PCI this isnt a big loss. Older chips 
+     *	have FIFO's smaller than a packet, so you can't do this.
      */
-         
+	 
     if(fset)
     {
-    	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
 	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
 #ifdef DO_DXSUFLO
 	dxsuflo = 1;
@@ -625,52 +633,50 @@
     
     dev = init_etherdev(NULL, 0);
     if(dev==NULL)
-    	return ENOMEM;
+	return -ENOMEM;
 
     printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
     /* There is a 16 byte station address PROM at the base address.
-     The first six bytes are the station address. */
+       The first six bytes are the station address. */
     for (i = 0; i < 6; i++)
-      printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+	printk( KERN_INFO " %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
     if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
-        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
-	printk("\n    tx_start_pt(0x%04x):",i);
+	i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+	printk(KERN_INFO"\n    tx_start_pt(0x%04x):",i);
 	switch(i>>10) {
-	    case 0: printk("  20 bytes,"); break;
-	    case 1: printk("  64 bytes,"); break;
-	    case 2: printk(" 128 bytes,"); break;
-	    case 3: printk("~220 bytes,"); break;
+	    case 0: printk(KERN_INFO "  20 bytes,"); break;
+	    case 1: printk(KERN_INFO "  64 bytes,"); break;
+	    case 2: printk(KERN_INFO " 128 bytes,"); break;
+	    case 3: printk(KERN_INFO "~220 bytes,"); break;
 	}
-        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
-        printk(" BCR18(%x):",i&0xffff);
-	if (i & (1<<5)) printk("BurstWrEn ");
-	if (i & (1<<6)) printk("BurstRdEn ");
-	if (i & (1<<7)) printk("DWordIO ");
-	if (i & (1<<11)) printk("NoUFlow ");
-        i = a->read_bcr(ioaddr, 25);
-        printk("\n    SRAMSIZE=0x%04x,",i<<8);
-        i = a->read_bcr(ioaddr, 26);
-        printk(" SRAM_BND=0x%04x,",i<<8);
-        i = a->read_bcr(ioaddr, 27);
-	if (i & (1<<14)) printk("LowLatRx,");
+	i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+	printk(KERN_INFO" BCR18(%x):",i&0xffff);
+	if (i & (1<<5)) printk(KERN_INFO "BurstWrEn ");
+	if (i & (1<<6)) printk(KERN_INFO "BurstRdEn ");
+	if (i & (1<<7)) printk(KERN_INFO "DWordIO ");
+	if (i & (1<<11)) printk(KERN_INFO"NoUFlow ");
+	i = a->read_bcr(ioaddr, 25);
+	printk(KERN_INFO "\n    SRAMSIZE=0x%04x,",i<<8);
+	i = a->read_bcr(ioaddr, 26);
+	printk(KERN_INFO " SRAM_BND=0x%04x,",i<<8);
+	i = a->read_bcr(ioaddr, 27);
+	if (i & (1<<14)) printk(KERN_INFO "LowLatRx,");
     }
 
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
-    if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL)
-	return ENOMEM;
+    /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
+    if ((lp = (struct pcnet32_private *)pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL)
+	return -ENOMEM;
 
-    /*
-     * Make certain the data structures used by
-     * the PCnet32 are 16byte aligned
-      */
-    lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
-      
     memset(lp, 0, sizeof(*lp));
-    
+    lp->dma_addr = lp_dma_addr;
+    lp->pci_dev = pdev;
+    printk(KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x\n", lp, lp_dma_addr);
+
     spin_lock_init(&lp->lock);
     
     dev->priv = lp;
@@ -690,34 +696,37 @@
     if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx])
 	lp->options |= PORT_FD;
     
-    lp->origmem = priv;
     lp->a = *a;
+    if (a == NULL) {
+      printk(KERN_ERR "pcnet32: No access methods\n");
+      return -ENODEV;
+    }
     
     /* detect special T1/E1 WAN card by checking for MAC address */
     if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75)
 	lp->options = PORT_FD | PORT_GPSI;
 
-    lp->init_block.mode = le16_to_cpu(0x0003); 	/* Disable Rx and Tx. */
+    lp->init_block.mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
     for (i = 0; i < 6; i++)
-      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.filter[0] = 0x00000000;
     lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
     
     /* switch pcnet32 to 32bit mode */
     a->write_bcr (ioaddr, 20, 2);
 
-    a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff);
-    a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+    a->write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff);
+    a->write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
     
     if (irq_line) {
 	dev->irq = irq_line;
     }
     
     if (dev->irq >= 2)
-	printk(" assigned IRQ %d.\n", dev->irq);
+	printk(KERN_INFO " assigned IRQ %d.\n", dev->irq);
     else {
 	unsigned long irq_mask = probe_irq_on();
 	
@@ -732,15 +741,15 @@
 	
 	dev->irq = probe_irq_off (irq_mask);
 	if (dev->irq)
-	  printk(", probed IRQ %d.\n", dev->irq);
+	    printk(KERN_INFO ", probed IRQ %d.\n", dev->irq);
 	else {
-	    printk(", failed to detect IRQ line.\n");
-	    return ENODEV;
+	    printk(KERN_ERR ", failed to detect IRQ line.\n");
+	    return -ENODEV;
 	}
     }
 
     if (pcnet32_debug > 0)
-	printk(version);
+	printk(KERN_INFO, version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -784,11 +793,11 @@
     lp->a.write_bcr (ioaddr, 20, 2);
 
     if (pcnet32_debug > 1)
-	printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
+	printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
 	       dev->name, dev->irq,
-	       (u32) virt_to_bus(lp->tx_ring),
-	       (u32) virt_to_bus(lp->rx_ring),
-	       (u32) virt_to_bus(&lp->init_block));
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)),
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)),
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)));
     
     /* set/reset autoselect bit */
     val = lp->a.read_bcr (ioaddr, 2) & ~2;
@@ -824,15 +833,15 @@
 
 #ifdef DO_DXSUFLO 
     if (lp->dxsuflo) { /* Disable transmit stop on underflow */
-        val = lp->a.read_csr (ioaddr, 3);
+	val = lp->a.read_csr (ioaddr, 3);
 	val |= 0x40;
-        lp->a.write_csr (ioaddr, 3, val);
+	lp->a.write_csr (ioaddr, 3, val);
     }
 #endif
     if (lp->ltint) { /* Enable TxDone-intr inhibitor */
-        val = lp->a.read_csr (ioaddr, 5);
+	val = lp->a.read_csr (ioaddr, 5);
 	val |= (1<<14);
-        lp->a.write_csr (ioaddr, 5, val);
+	lp->a.write_csr (ioaddr, 5, val);
     }
    
     lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
@@ -842,8 +851,8 @@
 	return -ENOMEM;
     
     /* Re-initialize the PCNET32, and start it when done. */
-    lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff);
-    lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+    lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff);
+    lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
 
     lp->a.write_csr (ioaddr, 4, 0x0915);
     lp->a.write_csr (ioaddr, 0, 0x0001);
@@ -861,10 +870,11 @@
     lp->a.write_csr (ioaddr, 0, 0x0042);
 
     if (pcnet32_debug > 2)
-	printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-	       dev->name, i, (u32) virt_to_bus(&lp->init_block),
+	printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+	       dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)),
 	       lp->a.read_csr (ioaddr, 0));
 
+
     MOD_INC_USE_COUNT;
     
     return 0;	/* Always succeed */
@@ -891,8 +901,10 @@
 
     for (i = 0; i < TX_RING_SIZE; i++) {
 	if (lp->tx_skbuff[i]) {
-	    dev_kfree_skb(lp->tx_skbuff[i]);
+            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+	    dev_kfree_skb(lp->tx_skbuff[i]); 
 	    lp->tx_skbuff[i] = NULL;
+            lp->tx_dma_addr[i] = 0;
 	}
     }
 }
@@ -910,30 +922,33 @@
     lp->dirty_rx = lp->dirty_tx = 0;
 
     for (i = 0; i < RX_RING_SIZE; i++) {
-	if (lp->rx_skbuff[i] == NULL) {
-	    if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
+        struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
+	if (rx_skbuff == NULL) {
+	    if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
 		/* there is not much, we can do at this point */
-		printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+		printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
 		return -1;
 	    }
-	    skb_reserve (lp->rx_skbuff[i], 2);
+	    skb_reserve (rx_skbuff, 2);
 	}
-	lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
+        lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
+	lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
 	lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
 	lp->rx_ring[i].status = le16_to_cpu(0x8000);
     }
     /* The Tx buffer address is filled in as needed, but we do need to clear
-     the upper ownership bit. */
+       the upper ownership bit. */
     for (i = 0; i < TX_RING_SIZE; i++) {
 	lp->tx_ring[i].base = 0;
 	lp->tx_ring[i].status = 0;
+        lp->tx_dma_addr[i] = 0;
     }
 
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
     for (i = 0; i < 6; i++)
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
-    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
     return 0;
 }
 
@@ -966,24 +981,24 @@
     unsigned int ioaddr = dev->base_addr;
 
     /* Transmitter timeout, serious problems. */
-	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 	lp->a.write_csr (ioaddr, 0, 0x0004);
 	lp->stats.tx_errors++;
 	if (pcnet32_debug > 2) {
 	    int i;
-	    printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-		   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-		   lp->cur_rx);
+	    printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+	       lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+	       lp->cur_rx);
 	    for (i = 0 ; i < RX_RING_SIZE; i++)
-		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-		       lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+	    printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+		   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
 	    for (i = 0 ; i < TX_RING_SIZE; i++)
-		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		       lp->tx_ring[i].base, -lp->tx_ring[i].length,
-		       lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-	    printk("\n");
+	    printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		   lp->tx_ring[i].base, -lp->tx_ring[i].length,
+		   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+	    printk(KERN_DEBUG "\n");
 	}
 	pcnet32_restart(dev, 0x0042);
 
@@ -1002,7 +1017,7 @@
     unsigned long flags;
 
     if (pcnet32_debug > 3) {
-	printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
+	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
     }
 
@@ -1037,7 +1052,8 @@
     lp->tx_ring[entry].misc = 0x00000000;
 
     lp->tx_skbuff[entry] = skb;
-    lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+    lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+    lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]);
     lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
@@ -1070,7 +1086,7 @@
     int must_restart;
 
     if (dev == NULL) {
-	printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+	printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq);
 	return;
     }
 
@@ -1087,7 +1103,7 @@
 	must_restart = 0;
 
 	if (pcnet32_debug > 5)
-	    printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+	    printk(KERN_DEBUG "%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
 		   dev->name, csr0, lp->a.read_csr (ioaddr, 0));
 
 	if (csr0 & 0x0400)		/* Rx interrupt */
@@ -1113,13 +1129,13 @@
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
 #ifndef DO_DXSUFLO
- 		    if (err_status & 0x40000000) {
- 			lp->stats.tx_fifo_errors++;
+		    if (err_status & 0x40000000) {
+			lp->stats.tx_fifo_errors++;
 			/* Ackk!  On FIFO errors the Tx unit is turned off! */
- 			/* Remove this verbosity later! */
-			printk("%s: Tx FIFO error! CSR0=%4.4x\n",
-					    dev->name, csr0);
- 			must_restart = 1;
+			/* Remove this verbosity later! */
+			printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+			       dev->name, csr0);
+			must_restart = 1;
 		    }
 #else
 		    if (err_status & 0x40000000) {
@@ -1127,8 +1143,8 @@
 			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
 			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
 			    /* Remove this verbosity later! */
-			    printk("%s: Tx FIFO error! CSR0=%4.4x\n",
-					   	dev->name, csr0);
+			    printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+				   dev->name, csr0);
 			    must_restart = 1;
 			}
 		    }
@@ -1141,22 +1157,24 @@
 
 		/* We must free the original skb */
 		if (lp->tx_skbuff[entry]) {
+                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 		    dev_kfree_skb_irq(lp->tx_skbuff[entry]);
 		    lp->tx_skbuff[entry] = 0;
+                    lp->tx_dma_addr[entry] = 0;
 		}
 		dirty_tx++;
 	    }
 
 #ifndef final_version
 	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-		printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
 		       dirty_tx, lp->cur_tx, lp->tx_full);
 		dirty_tx += TX_RING_SIZE;
 	    }
 #endif
 	    if (lp->tx_full &&
-	        netif_queue_stopped(dev) &&
-			dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+		netif_queue_stopped(dev) &&
+		dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
 		/* The ring is no longer full, clear tbusy. */
 		lp->tx_full = 0;
 		netif_wake_queue (dev);
@@ -1180,7 +1198,7 @@
 	    lp->stats.rx_errors++; /* Missed a Rx frame. */
 	}
 	if (csr0 & 0x0800) {
-	    printk("%s: Bus master arbitration failure, status %4.4x.\n",
+	    printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n",
 		   dev->name, csr0);
 	    /* unlike for the lance, there is no restart needed */
 	}
@@ -1197,7 +1215,7 @@
     lp->a.write_rap(ioaddr,rap);
     
     if (pcnet32_debug > 4)
-	printk("%s: exiting interrupt, csr0=%#4.4x.\n",
+	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     spin_unlock(&lp->lock);
@@ -1208,7 +1226,6 @@
 {
     struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
     int entry = lp->cur_rx & RX_RING_MOD_MASK;
-    int i;
 
     /* If we own the next entry, it's a new packet. Send it up. */
     while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
@@ -1234,10 +1251,11 @@
 	    struct sk_buff *skb;
 			
 	    if(pkt_len < 60) {
-		printk("%s: Runt packet!\n",dev->name);
+		printk(KERN_ERR "%s: Runt packet!\n",dev->name);
 		lp->stats.rx_errors++;
 	    } else {
 		int rx_in_place = 0;
+                dma_addr_t rx_dma_addr = lp->rx_dma_addr[entry];
 			    
 		if (pkt_len > rx_copybreak) {
 		    struct sk_buff *newskb;
@@ -1248,16 +1266,19 @@
 			skb_put (skb, pkt_len);
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
-			lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
+                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);
+			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
 			skb = NULL;
-		} else
+		} else {
 		    skb = dev_alloc_skb(pkt_len+2);
+                }
 			    
 		if (skb == NULL) {
-		    printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-		    for (i=0; i < RX_RING_SIZE; i++)
+                    int i;
+		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
+		    for (i = 0; i < RX_RING_SIZE; i++)
 			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
 			    break;
 
@@ -1270,10 +1291,10 @@
 		}
 		skb->dev = dev;
 		if (!rx_in_place) {
-		    skb_reserve(skb,2);	/* 16 byte align */
+		    skb_reserve(skb,2); /* 16 byte align */
 		    skb_put(skb,pkt_len);	/* Make room */
 		    eth_copy_and_sum(skb,
-				     (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+				     (unsigned char *)(lp->rx_skbuff[entry]->tail),
 				     pkt_len,0);
 		}
 		lp->stats.rx_bytes += skb->len;
@@ -1306,7 +1327,7 @@
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
 
     if (pcnet32_debug > 1)
-	printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
@@ -1322,16 +1343,22 @@
     
     /* free all allocated skbuffs */
     for (i = 0; i < RX_RING_SIZE; i++) {
-	lp->rx_ring[i].status = 0;	    	    	    
-	if (lp->rx_skbuff[i])
+	lp->rx_ring[i].status = 0;			    
+	if (lp->rx_skbuff[i]) {
+            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);
 	    dev_kfree_skb(lp->rx_skbuff[i]);
+        }
 	lp->rx_skbuff[i] = NULL;
+        lp->rx_dma_addr[i] = 0;
     }
     
     for (i = 0; i < TX_RING_SIZE; i++) {
-	if (lp->tx_skbuff[i])
+	if (lp->tx_skbuff[i]) {
+            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
 	    dev_kfree_skb(lp->tx_skbuff[i]);
-	lp->rx_skbuff[i] = NULL;
+        }
+	lp->tx_skbuff[i] = NULL;
+        lp->tx_dma_addr[i] = 0;
     }
     
     MOD_DEC_USE_COUNT;
@@ -1412,11 +1439,11 @@
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
     unsigned long ioaddr = dev->base_addr;
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	 
 
     if (dev->flags&IFF_PROMISC) {
 	/* Log any net taps. */
-	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
 	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
     } else {
 	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
@@ -1432,35 +1459,42 @@
 static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     unsigned long ioaddr = dev->base_addr;
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	 
     u16 *data = (u16 *)&rq->ifr_data;
     int phyaddr = lp->a.read_bcr (ioaddr, 33);
 
     if (lp->mii) {
 	switch(cmd) {
-	 case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 	    data[0] = (phyaddr >> 5) & 0x1f;
 	    /* Fall Through */
-	 case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
 	    data[3] = lp->a.read_bcr (ioaddr, 34);
 	    lp->a.write_bcr (ioaddr, 33, phyaddr);
 	    return 0;
-	 case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 	    if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
 	    lp->a.write_bcr (ioaddr, 34, data[2]);
 	    lp->a.write_bcr (ioaddr, 33, phyaddr);
 	    return 0;
-	 default:
+	default:
 	    return -EOPNOTSUPP;
 	}
     }
     return -EOPNOTSUPP;
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
+#endif	/* HAVE_PRIVATE_IOCTL */
 					    
+static struct pci_driver pcnet32_driver = {
+    name:  "pcnet32",
+    probe: pcnet32_probe_pci,
+    remove: NULL,
+    id_table: pcnet32_pci_tbl,
+};
+
 MODULE_PARM(debug, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
@@ -1476,13 +1510,36 @@
 
 static int __init pcnet32_init_module(void)
 {
+    int cards_found = 0;
+    int err;
+
     if (debug > 0)
 	pcnet32_debug = debug;
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
     
     pcnet32_dev = NULL;
-    return pcnet32_probe();
+    /* find the PCI devices */
+#define USE_PCI_REGISTER_DRIVER
+#ifdef USE_PCI_REGISTER_DRIVER
+    if (err = pci_module_init(&pcnet32_driver) < 0 )
+       return err;
+#else
+    {
+        struct pci_device_id *devid = pcnet32_pci_tbl;
+        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {
+            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);
+            if (pdev != NULL) {
+                if (pcnet32_probe_pci(pdev, devid) >= 0) {
+                    cards_found++;
+                }
+            }
+        }
+    }
+#endif
+    return 0;
+    /* find any remaining VLbus devices */
+    return pcnet32_probe_vlbus(cards_found);
 }
 
 static void __exit pcnet32_cleanup_module(void)
@@ -1491,10 +1548,11 @@
 
     /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
     while (pcnet32_dev) {
-	next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
+        struct pcnet32_private *lp = (struct pcnet32_private *) pcnet32_dev->priv;
+	next_dev = lp->next;
 	unregister_netdev(pcnet32_dev);
 	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-	kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem);
+        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	kfree(pcnet32_dev);
 	pcnet32_dev = next_dev;
     }
@@ -1507,6 +1565,6 @@
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c"
  *  c-indent-level: 4
- *  tab-width: 4
+ *  tab-width: 8
  * End:
  */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.99-pre6/linux/drivers/net/plip.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/plip.c	Tue May  2 12:40:59 2000
@@ -1395,14 +1395,6 @@
 				break;
 			}
 			memset(dev_plip[i], 0, sizeof(struct net_device));
-			dev_plip[i]->name = 
-				kmalloc(strlen("plipXXX"), GFP_KERNEL);
-			if (!dev_plip[i]->name) {
-				printk(KERN_ERR "plip: memory squeeze.\n");
-				kfree(dev_plip[i]);
-				dev_plip[i] = NULL;
-				break;
-			}
 			sprintf(dev_plip[i]->name, "plip%d", i);
 			dev_plip[i]->priv = pb;
 			if (plip_init_dev(dev_plip[i],pb) || register_netdev(dev_plip[i])) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.99-pre6/linux/drivers/net/ppp_generic.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/ppp_generic.c	Tue May  2 12:40:59 2000
@@ -92,7 +92,6 @@
  */
 struct ppp {
 	struct ppp_file	file;		/* stuff for read/write/poll */
-	char		name[16];	/* unit name */
 	struct list_head channels;	/* list of attached channels */
 	int		n_channels;	/* how many channels are attached */
 	spinlock_t	rlock;		/* lock for receive side */
@@ -2190,7 +2189,6 @@
 	memset(dev, 0, sizeof(struct net_device));
 
 	ppp->file.index = unit;
-	sprintf(ppp->name, "ppp%d", unit);
 	ppp->mru = PPP_MRU;
 	init_ppp_file(&ppp->file, INTERFACE);
 	for (i = 0; i < NUM_NP; ++i)
@@ -2205,7 +2203,7 @@
 
 	ppp->dev = dev;
 	dev->init = ppp_net_init;
-	dev->name = ppp->name;
+	sprintf(dev->name, "ppp%d", unit);
 	dev->priv = ppp;
 	dev->new_style = 1;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c
--- v2.3.99-pre6/linux/drivers/net/pppoe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pppoe.c	Mon May  8 22:21:58 2000
@@ -0,0 +1,998 @@
+/** -*- linux-c -*- ***********************************************************
+ * Linux PPP over Ethernet (PPPoX/PPPoE) Sockets
+ *
+ * PPPoX --- Generic PPP encapsulation socket family
+ * PPPoE --- PPP over Ethernet (RFC 2516)
+ *
+ *
+ * Version:	0.5.0
+ *
+ * Author:	Michal Ostrowski <mostrows@styx.uwaterloo.ca>
+ *
+ * License:
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/if_pppox.h>
+#include <net/sock.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+
+
+
+static int __attribute__((unused)) pppoe_debug = 7;
+#define PPPOE_HASH_SIZE 16
+
+int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+
+struct proto_ops pppoe_ops;
+
+
+#if 0
+#define CHECKPTR(x,y) { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }}
+#define DEBUG(s,args...) if( pppoe_debug & (s) ) printk(KERN_CRIT args );
+#else
+#define CHECKPTR(x,y) do {} while (0);
+#define DEBUG(s,args...) do { } while (0);
+#endif
+
+
+
+static rwlock_t pppoe_hash_lock = RW_LOCK_UNLOCKED;
+
+
+static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b)
+{
+	return (a->sid == b->sid &&
+		(memcmp(a->remote, b->remote, ETH_ALEN) == 0));
+}
+
+static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr)
+{
+	return (a->sid == sid &&
+		(memcmp(a->remote,addr,ETH_ALEN) == 0));
+}
+
+static int hash_item(unsigned long sid, unsigned char *addr)
+{
+	int i = 0;
+	union {
+		char c[sizeof(unsigned long)];
+		unsigned long i;
+	} hash;
+
+	hash.i = sid;
+
+	for (i = 0; i < ETH_ALEN; ++i)
+		hash.c[0] = hash.c[0] ^ addr[i];
+
+	for (i = 1; i < sizeof(int); ++i)
+		hash.c[0] = hash.c[0] ^ hash.c[i];
+
+	i = (int) (hash.c[0] & (PPPOE_HASH_SIZE - 1));
+
+	return i;
+}	
+
+static struct pppox_opt *item_hash_table[PPPOE_HASH_SIZE] = { 0, };
+
+/**********************************************************************
+ *
+ *  Set/get/delete/rehash items  (internal versions)
+ *  
+ **********************************************************************/
+static struct pppox_opt *__get_item(unsigned long sid, unsigned char *addr)
+{
+	int hash = hash_item(sid, addr);
+	struct pppox_opt *ret;
+
+	ret = item_hash_table[hash];
+
+	while (ret && !cmp_addr(&ret->pppoe_pa, sid, addr))
+		ret = ret->next;
+
+	return ret;
+}
+
+static int __set_item(struct pppox_opt *po)
+{
+	int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+	struct pppox_opt *ret;
+
+	ret = item_hash_table[hash];
+	while (ret) {
+		if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa))
+			return -EALREADY;
+
+		ret = ret->next;
+	}
+
+	if (!ret) {
+		po->next = item_hash_table[hash];
+		item_hash_table[hash] = po;
+	}
+
+	return 0;
+}
+
+static struct pppox_opt *__delete_item(unsigned long sid, char *addr)
+{
+	int hash = hash_item(sid, addr);
+	struct pppox_opt *ret, **src;
+
+	ret = item_hash_table[hash];
+	src = &item_hash_table[hash];
+
+	while (ret) {
+		if (cmp_addr(&ret->pppoe_pa, sid, addr)) {
+			*src = ret->next;
+			break;
+		}
+
+		src = &ret->next;
+		ret = ret->next;
+	}
+
+	return ret;
+}
+
+static struct pppox_opt *__find_on_dev(struct net_device *dev, 
+				       struct pppox_opt *start)
+{
+	struct pppox_opt *po;
+	int hash;
+
+	if (start != NULL) {
+		hash = hash_item(start->pppoe_pa.sid, start->pppoe_pa.remote);
+		po   = start;
+	} else {
+		hash = 0;
+		po   = NULL;
+
+		while (!po && ++hash < PPPOE_HASH_SIZE)
+			po = item_hash_table[hash];
+	}
+	
+	while (po && (po->pppoe_dev != dev)){
+		if (po->next) {
+			po = po->next;
+		} else {
+			po = NULL;
+			while (!po && ++hash < PPPOE_HASH_SIZE)
+				po = item_hash_table[hash];
+		}
+	}
+
+	return po;
+}
+
+/**********************************************************************
+ *
+ *  Set/get/delete/rehash items
+ *  
+ **********************************************************************/
+static inline struct pppox_opt *get_item(unsigned long sid, 
+					 unsigned char *addr)
+{
+	struct pppox_opt *po;
+
+	read_lock_bh(&pppoe_hash_lock);
+	po = __get_item(sid, addr);
+	read_unlock_bh(&pppoe_hash_lock);
+
+	return po;
+}
+
+static inline struct pppox_opt *get_item_by_addr(struct sockaddr_pppox *sp)
+{
+	return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote);
+}
+
+static inline int set_item(struct pppox_opt *po)
+{
+	int i;
+
+	if (!po)
+		return -EINVAL;
+
+	write_lock_bh(&pppoe_hash_lock);
+	i = __set_item(po);
+	write_unlock_bh(&pppoe_hash_lock);
+
+	return i;
+}
+
+static inline struct pppox_opt *delete_item(unsigned long sid, char *addr)
+{
+	struct pppox_opt *ret;
+
+	write_lock_bh(&pppoe_hash_lock);
+	ret = __delete_item(sid, addr);
+	write_unlock_bh(&pppoe_hash_lock);
+
+	return ret;
+}
+
+static struct pppox_opt *find_on_dev(struct net_device *dev, 
+				     struct pppox_opt *start)
+{
+	struct pppox_opt *po;
+	read_lock_bh(&pppoe_hash_lock);
+	po = __find_on_dev(dev,start);
+	read_unlock_bh(&pppoe_hash_lock);
+	return po;
+}
+
+/***************************************************************************
+ *
+ *  Handler for device events
+ *  Certain device events require that sockets be unconnected
+ *
+ **************************************************************************/
+static int pppoe_device_event(struct notifier_block *this, 
+			      unsigned long event, void *ptr)
+{
+	int error = NOTIFY_DONE;
+	struct net_device *dev = (struct net_device *) ptr;
+	struct pppox_opt *po = NULL;
+	
+	/* Only look at sockets that are using this specific device. */
+	switch (event) {
+	case NETDEV_CHANGEMTU:
+	    /* A change in mtu is a bad thing, requiring
+	     * LCP re-negotiation.
+	     */
+	case NETDEV_GOING_DOWN:
+	case NETDEV_DOWN:
+		do {
+			po = find_on_dev(dev, po);
+			if(!po)
+				break;
+
+			if (po->sk->state & PPPOX_CONNECTED)
+				pppox_unbind_sock(po->sk);
+			
+			if (po->sk->state & PPPOX_CONNECTED) {
+				lock_sock(po->sk);
+				po->sk->shutdown = RCV_SHUTDOWN&SEND_SHUTDOWN;
+				
+				po->sk->state = PPPOX_DEAD;
+				po->pppoe_dev = NULL;
+
+				wake_up(po->sk->sleep);
+				release_sock(po->sk);
+			}
+		} while (1);
+
+		break;
+	default:
+		break;
+	};
+
+	return error;
+}
+
+
+static struct notifier_block pppoe_notifier = {
+	pppoe_device_event,
+	NULL,
+	0
+};
+
+
+
+
+/************************************************************************
+ *
+ * Receive a PPPoE Session frame.
+ *
+ ***********************************************************************/
+static int pppoe_rcv(struct sk_buff *skb, 
+		      struct net_device *dev,
+		      struct packet_type *pt)
+
+{
+	struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
+	struct pppox_opt *po;
+	struct sock *sk ;
+	
+	po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source);
+
+	if(!po)
+		goto abort;
+
+	sk = po->sk;
+
+	if (!sk || !(sk->state & PPPOX_CONNECTED))
+		goto abort;
+
+	if (sk->state & PPPOX_BOUND) {
+		skb_pull(skb, sizeof(struct pppoe_hdr));
+
+		ppp_input(&po->chan, skb);
+	} else {
+		sock_queue_rcv_skb(sk, skb);
+	}
+
+	return 1;
+
+abort:
+	kfree_skb(skb);
+	return 0;
+}
+
+/************************************************************************
+ *
+ * Receive a PPPoE Discovery frame.
+ * -- This is solely for detection of PADT frames
+ *
+ ***********************************************************************/
+static int pppoe_disc_rcv(struct sk_buff *skb, 
+			  struct net_device *dev,
+			  struct packet_type *pt)
+
+{
+	struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
+	struct pppox_opt *po;
+	struct sock *sk ;
+
+	if (ph->code != PADT_CODE)
+		goto abort;
+
+	po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source);
+
+	if (!po)
+		goto abort;
+
+	sk = po->sk;
+
+	pppox_unbind_sock(sk);
+
+abort:
+	kfree_skb(skb);
+	return 0;
+}
+
+
+
+
+struct packet_type pppoes_ptype = {
+	__constant_htons(ETH_P_PPP_SES),
+	NULL,
+	pppoe_rcv,
+	NULL,
+	NULL
+};
+
+struct packet_type pppoed_ptype = {
+	__constant_htons(ETH_P_PPP_DISC),
+	NULL,
+	pppoe_disc_rcv,
+	NULL,
+	NULL
+};
+
+/**********************************************************************
+ *
+ * The destruct hook --- this can be trashed if there is no need for
+ * the sock to clear its receive queue?
+ *
+ *********************************************************************/
+void sock_pppoe_destruct(struct sock *sk)
+{
+	if (sk->protinfo.destruct_hook)
+		kfree(sk->protinfo.destruct_hook);
+
+	while (skb_queue_len(&sk->receive_queue) > 0) {
+		struct sk_buff *skb = skb_dequeue(&sk->receive_queue);
+		if (skb)
+			kfree_skb(skb);
+	}
+}
+
+int pppoe_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	/* Never seen this called, don't expect it to be called,
+	   though I've curious whether or not it ever will be. */
+	DEBUG(KERN_CRIT "Backlog rcv called: %p\n", sk);
+
+	kfree_skb(skb);
+
+	return 0;
+}
+
+/***********************************************************************
+ *
+ * Initialize a new struct sock.
+ *
+ **********************************************************************/
+static int pppoe_create(struct socket *sock)
+{
+	int error = 0;
+	struct sock *sk;
+	
+	MOD_INC_USE_COUNT;
+	
+	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, 1);
+	if (!sk)
+		return -ENOMEM;
+
+	sock_init_data(sock, sk);
+
+	sock->state = SS_UNCONNECTED;
+	sock->ops   = &pppoe_ops;
+
+	sk->protocol = PX_PROTO_OE;
+	sk->family = PF_PPPOX;
+
+	sk->backlog_rcv = pppoe_backlog_rcv;
+	sk->next = NULL;
+	sk->pprev = NULL;
+	sk->state = PPPOX_NONE;
+	sk->type = SOCK_STREAM;
+
+	sk->protinfo.pppox = kmalloc(sizeof(struct pppox_opt), GFP_KERNEL);
+	if (!sk->protinfo.pppox) {
+		error = -ENOMEM;
+		goto free_sk;
+	}
+
+	memset((void *) sk->protinfo.pppox, 0, sizeof(struct pppox_opt));
+	sk->protinfo.pppox->sk = sk;
+
+	/* Delete the protinfo when it is time to do so. */
+	sk->protinfo.destruct_hook = sk->protinfo.pppox;
+	sock->sk = sk;
+
+	return 0;
+
+free_sk:
+	sk_free(sk);
+	MOD_DEC_USE_COUNT;
+	return error;
+}
+
+int pppoe_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_opt *po;
+	int error = 0;
+
+	if (!sk)
+		return 0;
+
+	if (sk->dead != 0)
+		return -EBADF;
+
+	pppox_unbind_sock(sk);
+
+	sock_orphan(sk);
+
+	/* Signal the death of the socket. */
+	sk->state = PPPOX_DEAD;
+
+	po = sk->protinfo.pppox;
+	if (po->pppoe_pa.sid)
+		delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+
+	kfree(po);
+
+
+	/* Should also do a queue purge here */
+
+	sk->protinfo.pppox = NULL;
+	sock->sk = NULL;
+
+	skb_queue_purge(&sk->receive_queue);
+
+	sock_put(sk);
+	MOD_DEC_USE_COUNT;
+
+	return error;
+}
+
+
+int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
+		  int sockaddr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct net_device *dev = NULL;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_opt  *po=sk->protinfo.pppox;
+	int error;
+
+	lock_sock(sk);
+
+	error = -EINVAL;
+	if (sp->sa_protocol != PX_PROTO_OE)
+		goto end;
+
+	error = -EBUSY;
+	if (sk->state & PPPOX_CONNECTED)
+		goto end;
+
+	dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+		
+	error = -ENODEV; 
+	if (!dev)
+		goto end;
+
+	error = 0;
+	if (po->pppoe_pa.sid) {
+		pppox_unbind_sock(sk);
+
+		/* Delete the old binding */
+		delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote);
+
+		memset(po, 0, sizeof(struct pppox_opt));
+		po->sk = sk;
+
+		sk->state = PPPOX_NONE;
+	}
+
+	/* Don't re-bind if sid==0 */
+	if (sp->sa_addr.pppoe.sid != 0) {
+		memcpy(&po->pppoe_pa,
+		       &sp->sa_addr.pppoe,
+		       sizeof(struct pppoe_addr));
+
+		error = set_item(po);
+		if (error < 0)
+			goto end;
+
+		po->pppoe_dev = dev;
+
+		po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
+				   dev->hard_header_len);
+
+		po->chan.private = sk;
+		po->chan.ops = &pppoe_chan_ops;
+
+		error = ppp_register_channel(&po->chan);
+
+		sk->state = PPPOX_CONNECTED;
+	}
+
+	sk->num = sp->sa_addr.pppoe.sid;
+
+ end:
+	release_sock(sk);
+	return error;
+}
+
+
+int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,
+		  int *usockaddr_len, int peer)
+{
+	int len = sizeof(struct sockaddr_pppox);
+	struct sockaddr_pppox sp;
+
+	sp.sa_family	= AF_PPPOX;
+	sp.sa_protocol	= PX_PROTO_OE;
+	memcpy(&sp.sa_addr.pppoe, &sock->sk->protinfo.pppox->pppoe_pa,
+	       sizeof(struct pppoe_addr));
+
+	memcpy(uaddr, &sp, len);
+
+	*usockaddr_len = len;
+
+	return 0;
+}
+
+
+int pppoe_ioctl(struct socket *sock, unsigned int cmd,
+		unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_opt *po;
+	int val = 0;
+	int err = 0;
+
+	po = sk->protinfo.pppox;
+	switch (cmd) {
+	case PPPIOCGMRU:
+		err = -ENXIO;
+
+		if (!(sk->state & PPPOX_CONNECTED))
+			break;
+
+		err = -EFAULT;
+		if (put_user(po->pppoe_dev->mtu -
+			     sizeof(struct pppoe_hdr) -
+			     PPP_HDRLEN,
+			     (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCSMRU:
+		err = -ENXIO;
+		if (!(sk->state & PPPOX_CONNECTED))
+			break;
+
+		err = -EFAULT;
+		if (get_user(val,(int *) arg))
+			break;
+
+		if (val < (po->pppoe_dev->mtu
+			   - sizeof(struct pppoe_hdr)
+			   - PPP_HDRLEN))
+			err = 0;
+		else
+			err = -EINVAL;
+		break;
+
+	case PPPIOCSFLAGS:
+		err = -EFAULT;
+		if (get_user(val, (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPOEIOCSFWD:
+	{
+		struct pppox_opt *relay_po;
+
+		err = -EBUSY;
+		if (sk->state & PPPOX_BOUND)
+			break;
+
+		err = -ENOTCONN;
+		if (!(sk->state & PPPOX_CONNECTED))
+			break;
+
+		/* PPPoE address from the user specifies an outbound
+		   PPPoE address to which frames are forwarded to */
+		err = -EFAULT;
+		if( copy_from_user(&po->pppoe_relay,
+				   (void*)arg,
+				   sizeof(struct sockaddr_pppox)))
+			break;
+
+		err = -EINVAL;
+		if (po->pppoe_relay.sa_family != AF_PPPOX ||
+		    po->pppoe_relay.sa_protocol!= PX_PROTO_OE)
+			break;
+
+		/* Check that the socket referenced by the address
+		   actually exists. */
+		relay_po = get_item_by_addr(&po->pppoe_relay);
+
+		if (!relay_po)
+			break;
+
+		sk->state |= PPPOX_RELAY;
+		err = 0;
+		break;
+	}
+
+	case PPPOEIOCDFWD:
+		err = -EALREADY;
+		if (!(sk->state & PPPOX_RELAY))
+			break;
+
+		sk->state &= ~PPPOX_RELAY;
+		err = 0;
+		break;
+
+	default:
+	};
+
+	return err;
+}
+
+
+int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
+		  int total_len, struct scm_cookie *scm)
+{
+	struct sk_buff *skb = NULL;
+	struct sock *sk = sock->sk;
+	int error = 0;
+	struct pppoe_hdr hdr;
+	struct pppoe_hdr *ph;
+	struct net_device *dev;
+	char *start;
+	int copied = 0;
+
+	if (sk->dead || !(sk->state & PPPOX_CONNECTED)) {
+		error = -ENOTCONN;
+		goto end;
+	}
+
+	hdr.ver = 1;
+	hdr.type = 1;
+	hdr.code = 0;
+	hdr.sid = sk->num;
+
+	dev = sk->protinfo.pppox->pppoe_dev;
+
+	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
+			   0, GFP_KERNEL);
+	if (!skb) {
+		error = -ENOMEM;
+		goto end;
+	}
+
+	/* Reserve space for headers. */
+	skb_reserve(skb, dev->hard_header_len);
+	skb->nh.raw = skb->data;
+	skb->dev = dev;
+	skb->priority = sk->priority;
+	skb->protocol = __constant_htons(ETH_P_PPP_SES);
+
+	ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr));
+	start = (char *) &ph->tag[0];
+
+	copied = memcpy_fromiovec( start, m->msg_iov, m->msg_iovlen);
+
+	dev->hard_header(skb, dev, ETH_P_PPP_SES,
+			 sk->protinfo.pppox->pppoe_pa.remote,
+			 NULL, copied);
+
+	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
+
+	ph->length = htons(copied);
+
+	dev_queue_xmit(skb);
+	return copied;
+
+end:
+	return error;
+}
+
+/************************************************************************
+ *
+ * xmit function called by generic PPP driver
+ * sends PPP frame over PPPoE socket
+ *
+ ***********************************************************************/
+int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct net_device *dev = sk->protinfo.pppox->pppoe_dev;
+	struct pppoe_hdr hdr;
+	struct pppoe_hdr *ph;
+	int headroom = skb_headroom(skb);
+	int data_len = skb->len;
+
+	if (sk->dead  || !(sk->state & PPPOX_CONNECTED)) {
+		goto abort;
+	}
+
+	hdr.ver	= 1;
+	hdr.type = 1;
+	hdr.code = 0;
+	hdr.sid	= sk->num;
+	hdr.length = htons(skb->len);
+
+	if (!dev) {
+		goto abort;
+	}
+
+	/* Copy the skb if there is no space for the header. */
+	if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {
+		struct sk_buff *skb2;
+
+		skb2 = dev_alloc_skb(32+skb->len +
+				     sizeof(struct pppoe_hdr) +
+				     dev->hard_header_len);
+
+		if (skb2 == NULL)
+			goto abort;
+
+		skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
+		memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
+
+		skb_unlink(skb);
+		kfree_skb(skb);
+		skb = skb2;
+	}
+
+	ph = (struct pppoe_hdr *) skb_push(skb, sizeof(struct pppoe_hdr));
+	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
+	skb->protocol = __constant_htons(ETH_P_PPP_SES);
+
+	skb->nh.raw = skb->data;
+	skb->dev = dev;
+
+	dev->hard_header(skb, dev, ETH_P_PPP_SES,
+			 sk->protinfo.pppox->pppoe_pa.remote,
+			 NULL, data_len);
+
+	if (dev_queue_xmit(skb) < 0)
+		goto abort;
+
+	return 1;
+ abort:
+	return 0;
+}
+
+struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL };
+
+int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb = NULL;
+	int error = 0;
+	int len;
+	struct pppoe_hdr *ph = NULL;
+
+	if (sk->state & PPPOX_BOUND) {
+		error = -EIO;
+		goto end;
+	}
+
+	skb = skb_recv_datagram(sk, flags, 0, &error);
+
+	if (error < 0) {
+		goto end;
+	}
+
+	m->msg_namelen = 0;
+
+	if (skb) {
+		error = 0;
+		ph = (struct pppoe_hdr *) skb->nh.raw;
+		len = ntohs(ph->length);
+
+		error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);
+		if (error < 0)
+			goto do_skb_free;
+		error = len;
+	}
+
+do_skb_free:
+	if (skb)
+		kfree_skb(skb);
+end:
+	return error;
+}
+
+int pppoe_proc_info(char *buffer, char **start, off_t offset, int length)
+{
+	struct pppox_opt *po;
+	int len = 0;
+	off_t pos = 0;
+	off_t begin = 0;
+	int size;
+	int i;
+	
+	len += sprintf(buffer,
+		       "Id       Address              Device\n");
+	pos = len;
+
+	write_lock_bh(&pppoe_hash_lock);
+
+	for (i = 0; i < PPPOE_HASH_SIZE; i++) {
+		po = item_hash_table[i];
+		while (po) {
+			char *dev = po->pppoe_pa.dev;
+
+			size = sprintf(buffer + len,
+				       "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
+				       po->pppoe_pa.sid,
+				       po->pppoe_pa.remote[0],
+				       po->pppoe_pa.remote[1],
+				       po->pppoe_pa.remote[2],
+				       po->pppoe_pa.remote[3],
+				       po->pppoe_pa.remote[4],
+				       po->pppoe_pa.remote[5],
+				       dev);
+			len += size;
+			pos += size;
+			if (pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+
+			if (pos > offset + length)
+				break;
+
+			po = po->next;
+		}
+
+		if (po)
+			break;
+  	}
+	write_unlock_bh(&pppoe_hash_lock);
+
+  	*start = buffer + (offset - begin);
+  	len -= (offset - begin);
+  	if (len > length)
+  		len = length;
+	if (len < 0)
+		len = 0;
+  	return len;
+}
+
+
+struct proto_ops pppoe_ops = {
+    family:		AF_PPPOX,
+    release:		pppoe_release,
+    bind:		sock_no_bind,
+    connect:		pppoe_connect,
+    socketpair:		sock_no_socketpair,
+    accept:		sock_no_accept,
+    getname:		pppoe_getname,
+    poll:		datagram_poll,
+    ioctl:		pppoe_ioctl,
+    listen:		sock_no_listen,
+    shutdown:		sock_no_shutdown,
+    setsockopt:		sock_no_setsockopt,
+    getsockopt:		sock_no_getsockopt,
+    sendmsg:		pppoe_sendmsg,
+    recvmsg:		pppoe_rcvmsg,
+    mmap:		sock_no_mmap
+};
+
+struct pppox_proto pppoe_proto = {
+    create:	pppoe_create,
+    ioctl:	pppoe_ioctl
+};
+
+
+int __init pppoe_init(void)
+{
+ 	int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
+
+	if (err == 0) {
+		printk(KERN_INFO "Registered PPPoE v0.5\n");
+
+		dev_add_pack(&pppoes_ptype);
+		register_netdevice_notifier(&pppoe_notifier);
+		proc_net_create("pppoe", 0, pppoe_proc_info);
+	}
+	return err;
+}
+
+
+#ifdef MODULE
+MODULE_PARM(debug, "i");
+int init_module(void)
+{
+	return pppoe_init();
+}
+
+void cleanup_module(void)
+{
+	unregister_pppox_proto(PX_PROTO_OE);
+	dev_remove_pack(&pppoes_ptype);
+	unregister_netdevice_notifier(&pppoe_notifier);
+	proc_net_remove("pppoe");
+}
+
+#else
+
+int pppoe_proto_init(struct net_proto *np)
+{
+	return pppoe_init();
+}
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pppox.c linux/drivers/net/pppox.c
--- v2.3.99-pre6/linux/drivers/net/pppox.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pppox.c	Mon May  8 22:21:58 2000
@@ -0,0 +1,172 @@
+/** -*- linux-c -*- ***********************************************************
+ * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets
+ *
+ * PPPoX --- Generic PPP encapsulation socket family
+ * PPPoE --- PPP over Ethernet (RFC 2516)
+ *
+ *
+ * Version:	0.5.0
+ *
+ * Author:	Michal Ostrowski <mostrows@styx.uwaterloo.ca>
+ *
+ * License:
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/init.h>
+#include <linux/if_pppox.h>
+#include <net/sock.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/ppp_channel.h>
+
+static struct pppox_proto *proto[PX_MAX_PROTO+1] = { NULL, };
+
+int register_pppox_proto(int proto_num, struct pppox_proto *pp)
+{
+	if (proto_num < 0 || proto_num > PX_MAX_PROTO) {
+		return -EINVAL;
+	}
+
+	if (proto[proto_num])
+		return -EALREADY;
+
+	MOD_INC_USE_COUNT;
+
+	proto[proto_num] = pp;
+	return 0;
+}
+
+void unregister_pppox_proto(int proto_num)
+{
+	if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) {
+	    proto[proto_num] = NULL;
+	    MOD_DEC_USE_COUNT;
+	}
+}
+
+void pppox_unbind_sock(struct sock *sk)
+{
+	/* Clear connection to ppp device, if attached. */
+
+	if (sk->state & PPPOX_BOUND) {
+		ppp_unregister_channel(&sk->protinfo.pppox->chan);
+		sk->state &= ~PPPOX_BOUND;
+	}
+}
+
+EXPORT_SYMBOL(register_pppox_proto);
+EXPORT_SYMBOL(unregister_pppox_proto);
+EXPORT_SYMBOL(pppox_unbind_sock);
+
+int pppox_ioctl(struct socket* sock, unsigned int cmd,
+		unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_opt *po;
+	int err = 0;
+
+	po = sk->protinfo.pppox;
+
+	lock_sock(sk);
+
+	switch (cmd) {
+	case PPPIOCGCHAN:{
+		int index;
+		err = -ENOTCONN;
+		if (!(sk->state & PPPOX_CONNECTED))
+			break;
+
+		err = -EINVAL;
+		index = ppp_channel_index(&po->chan);
+		if (put_user(index , (int *) arg))
+			break;
+
+		err = 0;
+		sk->state |= PPPOX_BOUND;
+		break;
+	}
+	default:
+		if (proto[sk->protocol]->ioctl)
+			err = (*proto[sk->protocol]->ioctl)(sock, cmd, arg);
+
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+
+int pppox_create(struct socket *sock, int protocol)
+{
+	int err = 0;
+
+	if (protocol < 0 || protocol > PX_MAX_PROTO)
+	    return -EPROTOTYPE;
+
+	if (proto[protocol] == NULL)
+	    return -EPROTONOSUPPORT;
+
+	err = (*proto[protocol]->create)(sock);
+
+	if (err == 0) {
+		/* We get to set the ioctl handler. */
+		/* For everything else, pppox is just a shell. */
+		sock->ops->ioctl = pppox_ioctl;
+	}
+
+	return err;
+}
+
+struct net_proto_family pppox_proto_family = {
+	PF_PPPOX,
+	pppox_create
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+void __init pppox_proto_init(struct net_proto *pro)
+#endif
+{
+	int err = 0;
+
+	err = sock_register(&pppox_proto_family);
+
+	if (err == 0)
+		printk(KERN_INFO "Registered PPPoX v0.5\n");
+
+#ifdef CONFIG_PPPOE
+	pppoe_init();
+#endif
+
+	return err;
+}
+
+#ifdef MODULE
+
+MODULE_PARM(debug, "i");
+
+void cleanup_module(void)
+{
+	sock_unregister(PF_PPPOX);
+}
+
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.3.99-pre6/linux/drivers/net/rcpci45.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/rcpci45.c	Tue May  2 12:41:00 2000
@@ -117,7 +117,6 @@
      */
     struct net_device *dev;            
      
-    char devname[8];                /* "ethN" string */
     U8     id;                        /* the AdapterID */
     U32    pci_addr;               /* the pci address of the adapter */
     U32    bus;
@@ -276,8 +275,6 @@
 #endif
 
     pDpa = dev->priv;
-    if (!dev->name)
-        dev->name = pDpa->devname;
 
     pDpa->dev = dev;            /* this is just for easy reference */
     pDpa->function = function;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c
--- v2.3.99-pre6/linux/drivers/net/sb1000.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/sb1000.c	Tue May  2 12:41:00 2000
@@ -1205,9 +1205,8 @@
 MODULE_PARM(io, "1-2i");
 MODULE_PARM(irq, "i");
 
-static char devname[8] = {0, };
 static struct net_device dev_sb1000 = {
-        devname,
+        "",
         0, 0, 0, 0,
         0, 0,
         0, 0, 0, NULL, sb1000_probe };
@@ -1220,8 +1219,8 @@
 {
 	int i;
 	for (i = 0; i < 100; i++) {
-		sprintf(devname, "cm%d", i);
-		if (dev_get(devname) == 0) break;
+		sprintf(dev_sb1000.name, "cm%d", i);
+		if (dev_get(dev_sb1000.name) == 0) break;
 	}
 	if (i == 100) {
 		printk(KERN_ERR "sb1000: can't register any device cm<n>\n");
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.3.99-pre6/linux/drivers/net/shaper.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/shaper.c	Tue May  2 12:41:00 2000
@@ -688,11 +688,9 @@
  
 #ifdef MODULE
 
-static char devicename[9];
-
 static struct net_device dev_shape = 
 {
-	devicename,
+	"",
 	0, 0, 0, 0,
 	0, 0,
 	0, 0, 0, NULL, shaper_probe 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.3.99-pre6/linux/drivers/net/sis900.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/sis900.c	Fri Apr 28 23:00:05 2000
@@ -182,7 +182,8 @@
 	}
 
 	/* setup various bits in PCI command register */
-	pci_enable_device (pci_dev);
+	if (pci_enable_device (pci_dev))
+		return -ENODEV;
 	pci_set_master(pci_dev);
 
 	/* do the real low level jobs */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.3.99-pre6/linux/drivers/net/sk_mca.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/sk_mca.c	Tue May  2 12:41:00 2000
@@ -1068,13 +1068,12 @@
 
 #define DEVMAX 5
 
-static char NameSpace[8 * DEVMAX];
 static struct net_device moddevs[DEVMAX] =
-    { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
-{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
+    { {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
 };
 
 int irq = 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c
--- v2.3.99-pre6/linux/drivers/net/skfp/skfddi.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/skfp/skfddi.c	Tue May  2 12:41:00 2000
@@ -551,7 +551,7 @@
 	int len;
 
 	PRINTK(KERN_INFO "entering insert_device\n");
-	len = sizeof(struct net_device) + 8 + sizeof(struct s_smc);
+	len = sizeof(struct net_device) + sizeof(struct s_smc);
 	new = (struct net_device *) kmalloc(len, GFP_KERNEL);
 	if (new == NULL) {
 		printk("fddi%d: Device not initialised, insufficient memory\n",
@@ -559,8 +559,7 @@
 		return NULL;
 	} else {
 		memset((char *) new, 0, len);
-		new->name = (char *) (new + 1);
-		new->priv = (struct s_smc *) (new->name + 8);
+		new->priv = (struct s_smc *) (new + 1);
 		new->init = init;	/* initialisation routine */
 		if (!loading_module) {
 			new->next = dev->next;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.3.99-pre6/linux/drivers/net/slip.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/slip.c	Tue May  2 12:41:00 2000
@@ -89,7 +89,6 @@
 
 
 typedef struct slip_ctrl {
-	char		if_name[16];	/* "sl0\0" .. "sl99999\0"	*/
 	struct slip	ctrl;		/* SLIP things			*/
 	struct net_device	dev;		/* the device			*/
 } slip_ctrl_t;
@@ -805,8 +804,7 @@
 	sl->dev	      	= &slp->dev;
 	spin_lock_init(&sl->lock);
 	sl->mode        = SL_MODE_DEFAULT;
-	sprintf(slp->if_name, "sl%d", i);
-	slp->dev.name         = slp->if_name;
+	sprintf(slp->dev.name, "sl%d", i);
 	slp->dev.base_addr    = i;
 	slp->dev.priv         = (void*)sl;
 	slp->dev.init         = sl_init;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.3.99-pre6/linux/drivers/net/smc-mca.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/smc-mca.c	Tue May  2 12:41:00 2000
@@ -437,14 +437,11 @@
 #undef MODULE        /* don't want to bother now! */
 
 #define MAX_ULTRAMCA_CARDS 4	/* Max number of Ultra cards per module */
-#define NAMELEN 8		/* # of chars for storing dev->name */
-
-static char namelist[NAMELEN * MAX_ULTRAMCA_CARDS] = { 0, };
 
 static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS] =
 {
 	{
-		NULL,       /* assign a chunk of namelist[] below */
+		"",
 	        0, 0, 0, 0,
 	        0, 0,
 	        0, 0, 0, NULL, NULL
@@ -463,7 +460,6 @@
 
 	for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ultra[this_dev];
-		dev->name = namelist + (NAMELEN * this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = ultramca_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.3.99-pre6/linux/drivers/net/smc-ultra.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/smc-ultra.c	Tue May  2 12:41:00 2000
@@ -424,11 +424,9 @@
 
 #ifdef MODULE
 #define MAX_ULTRA_CARDS	4	/* Max number of Ultra cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_ULTRA_CARDS] = { 0, };
 static struct net_device dev_ultra[MAX_ULTRA_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",		/* assign a chunk of namelist[] below */
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -452,7 +450,6 @@
 
 	for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ultra[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = ultra_probe;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/smc-ultra32.c linux/drivers/net/smc-ultra32.c
--- v2.3.99-pre6/linux/drivers/net/smc-ultra32.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/smc-ultra32.c	Tue May  2 12:41:00 2000
@@ -368,11 +368,9 @@
 
 #ifdef MODULE
 #define MAX_ULTRA32_CARDS   4	/* Max number of Ultra cards per module */
-#define NAMELEN		    8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_ULTRA32_CARDS] = { 0, };
 static struct net_device dev_ultra[MAX_ULTRA32_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -385,7 +383,6 @@
 
 	for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
 		struct net_device *dev = &dev_ultra[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->init = ultra32_probe;
 		if (register_netdev(dev) != 0) {
 			if (found > 0) { /* Got at least one. */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.99-pre6/linux/drivers/net/starfire.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/starfire.c	Thu May 11 13:45:35 2000
@@ -1,31 +1,35 @@
 /* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
 /*
-	Written 1998-1999 by Donald Becker.
+	Written 1998-2000 by Donald Becker.
 
-	This software may be used and distributed according to the terms
-	of the GNU Public License (GPL), incorporated herein by reference.
-
-	The author may be reached as becker@usra.edu, or
-	Donald Becker
-	312 Severn Ave. #W302
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
 	Annapolis MD 21403
 
 	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html
+	http://www.scyld.com/network/starfire.html
+
+	Linux kernel-specific changes:
 	
 	LK1.1.1 (jgarzik):
 	- Use PCI driver interface
 	- Fix MOD_xxx races
 	- softnet fixups
 
+	LK1.1.2 (jgarzik):
+	- Merge Becker version 0.15
 */
 
-static const char *versionA =
-"starfire.c:v0.12+LK1.1.1  3/19/2000  Written by Donald Becker and others\n",
-*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n";
-
-/* A few user-configurable values.   These may be modified when a driver
-   module is loaded.*/
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
 
 /* Used for tuning interrupt latency vs. overhead. */
 static int interrupt_mitigation = 0x0;
@@ -69,16 +73,16 @@
 
 #define PFX "starfire: "
 
-
-#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#if !defined(__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 files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
@@ -94,12 +98,13 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
+/* These identify the driver base version and may not be removed. */
+static char version1[] __devinitdata =
+"starfire.c:v0.15+LK1.1.2 4/28/2000  Written by Donald Becker <becker@scyld.com>\n";
+static char version2[] __devinitdata =
+" Updates and info at http://www.scyld.com/network/starfire.html\n";
 
-#define RUN_AT(x) (jiffies + (x))
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(mtu, "i");
@@ -113,16 +118,10 @@
 
 I. Board Compatibility
 
-State the chips and boards this driver is known to work with.
-Note any similar chips or boards that will not work.
-
-This driver skeleton demonstrates the driver for an idealized
-descriptor-based bus-master PCI chip.
+This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter.
 
 II. Board-specific settings
 
-No jumpers exist on most PCI boards, so this section is usually empty.
-
 III. Driver operation
 
 IIIa. Ring buffers
@@ -194,21 +193,16 @@
 
 */
 
-
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   PCI 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 chip_capability_flags {CanHaveMII=1, };
+
+#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
 
 #if 0
 #define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
 #endif
-#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
 
+#define HAS_IP_COPYSUM 1
 
 enum chipset {
 	CH_6915 = 0,
@@ -223,13 +217,12 @@
 
 
 /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
 static struct chip_info {
-	char *chip_name;
+	const char *name;
 	int io_size;
-	int flags;
-} netdrv_tbl[] = {
-	{ "Adaptec Starfire 6915", 128, CanHaveMII },
+	int drv_flags;
+} netdrv_tbl[] __devinitdata = {
+	{ "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII },
 };
 
 
@@ -337,9 +330,9 @@
 	dma_addr_t tx_done_q_dma;
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media monitoring timer. */
+	int chip_id, drv_flags;
+	struct pci_dev *pci_dev;
 	/* Frequently used values: keep some adjacent for cache effect. */
-	int chip_id;
-	struct pci_dev *pdev;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
@@ -357,7 +350,6 @@
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[2];				/* MII device addresses. */
-	u32 pad[4];							/* Used for 32-byte alignment */
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
@@ -377,62 +369,59 @@
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
+
 
 static int __devinit starfire_init_one (struct pci_dev *pdev,
 					const struct pci_device_id *ent)
 {
 	struct netdev_private *np;
-	int i, irq, option, chip_id = ent->driver_data;
+	int i, irq, option, chip_idx = ent->driver_data;
 	struct net_device *dev;
-	static int card_idx = 0;
+	static int card_idx = -1;
 	static int printed_version = 0;
 	long ioaddr;
-	int io_size = netdrv_tbl[chip_id].io_size;
+	int io_size = netdrv_tbl[chip_idx].io_size;
+
+	card_idx++;
+	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+	
+	if (!printed_version++)
+		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
 
 	ioaddr = pci_resource_start (pdev, 0);
 	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
-		printk (KERN_ERR PFX "no PCI MEM resources, aborting\n");
+		printk (KERN_ERR PFX "card %d: no PCI MEM resources, aborting\n", card_idx);
 		return -ENODEV;
 	}
 	
 	dev = init_etherdev(NULL, sizeof(*np));
 	if (!dev) {
-		printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n");
+		printk (KERN_ERR PFX "card %d: cannot alloc etherdev, aborting\n", card_idx);
 		return -ENOMEM;
 	}
 	
 	irq = pdev->irq; 
-	
+
 	if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
-		printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n",
-			io_size, ioaddr);
+		printk (KERN_ERR PFX "card %d: resource 0x%x @ 0x%lx busy, aborting\n",
+			card_idx, io_size, ioaddr);
 		goto err_out_free_netdev;
 	}
 	
-	if (pci_enable_device (pdev)) {
-		printk (KERN_ERR PFX "cannot enable PCI device, aborting\n");
+	if (pci_enable_device (pdev))
 		goto err_out_free_res;
-	}
 	
 	ioaddr = (long) ioremap (ioaddr, io_size);
 	if (!ioaddr) {
-		printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n",
-			io_size, ioaddr);
+		printk (KERN_ERR PFX "card %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+			card_idx, io_size, ioaddr);
 		goto err_out_free_res;
 	}
 
 	pci_set_master (pdev);
 	
-	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-	card_idx++;
-	
-	if (!printed_version) {
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-		printed_version = 1;
-	}
-
-	printk (KERN_INFO "%s: %s at 0x%lx, ",
-		dev->name, netdrv_tbl[chip_id].chip_name, ioaddr);
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
 
 	/* Serial EEPROM reads are hidden by the hardware. */
 	for (i = 0; i < 6; i++)
@@ -454,13 +443,16 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
+	pdev->driver_data = dev;
+
 	/* private struct aligned and zeroed by init_etherdev */
 	np = dev->priv;
 
-	np->pdev = pdev;
-	np->chip_id = chip_id;
+	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
 	
-	pdev->driver_data = dev;
+	/* save useful data, netdrv_tbl is __devinitdata and might be dropped */
+	np->drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -492,7 +484,7 @@
 	if (mtu)
 		dev->mtu = mtu;
 
-	if (netdrv_tbl[np->chip_id].flags & CanHaveMII) {
+	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
@@ -524,7 +516,7 @@
 {
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
 	int result, boguscnt=1000;
-	/* ??? Must add a busy-wait here. */
+	/* ??? Should we add a busy-wait here? */
 	do
 		result = readl(mdio_addr);
 	while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
@@ -546,12 +538,13 @@
 	long ioaddr = dev->base_addr;
 	int i;
 
+	/* Do we ever need to reset the chip??? */
+
 	MOD_INC_USE_COUNT;
-	/* Do we need to reset the chip??? */
 
 	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
 		MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		return -EAGAIN;
 	}
 
 	/* Disable the Rx and Tx, and reset the chip. */
@@ -562,26 +555,26 @@
 			   dev->name, dev->irq);
 	/* Allocate the various queues, failing gracefully. */
 	if (np->tx_done_q == 0)
-		np->tx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_done_q_dma);
+		np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
 	if (np->rx_done_q == 0)
-		np->rx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_done_q_dma);
+		np->rx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_done_q_dma);
 	if (np->tx_ring == 0)
-		np->tx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_ring_dma);
+		np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
 	if (np->rx_ring == 0)
-		np->rx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_ring_dma);
+		np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
 	if (np->tx_done_q == 0  ||  np->rx_done_q == 0
 		|| np->rx_ring == 0 ||  np->tx_ring == 0) {
 		if (np->tx_done_q)
-			pci_free_consistent(np->pdev, PAGE_SIZE,
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
 								np->tx_done_q, np->tx_done_q_dma);
 		if (np->rx_done_q)
-			pci_free_consistent(np->pdev, PAGE_SIZE,
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
 								np->rx_done_q, np->rx_done_q_dma);
 		if (np->tx_ring)
-			pci_free_consistent(np->pdev, PAGE_SIZE,
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
 								np->tx_ring, np->tx_ring_dma);
 		if (np->rx_ring)
-			pci_free_consistent(np->pdev, PAGE_SIZE,
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
 								np->rx_ring, np->rx_ring_dma);
 		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
@@ -632,6 +625,8 @@
 	if (dev->if_port == 0)
 		dev->if_port = np->default_port;
 
+	netif_start_queue(dev);
+
 	if (debug > 1)
 		printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);
 	set_rx_mode(dev);
@@ -649,15 +644,13 @@
 	/* Enable the Rx and Tx units. */
 	writel(0x000F, ioaddr + GenCtrl);
 
-	netif_start_queue(dev);
-
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done netdev_open().\n",
 			   dev->name);
 
 	/* Set the timer to check for link beat. */
 	init_timer(&np->timer);
-	np->timer.expires = RUN_AT(3*HZ);
+	np->timer.expires = jiffies + 3*HZ;
 	np->timer.data = (unsigned long)dev;
 	np->timer.function = &netdev_timer;				/* timer handler */
 	add_timer(&np->timer);
@@ -670,21 +663,22 @@
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+	int negotiated =  mii_reg5 & np->advertising;
 	int duplex, new_tx_mode ;
 
 	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0);
 	if (np->duplex_lock)
 		duplex = 1;
 	else
-		duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+		duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (duplex)
 		new_tx_mode |= 2;
 	if (np->full_duplex != duplex) {
 		np->full_duplex = duplex;
 		if (debug)
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-				   " partner capability of %4.4x.\n", dev->name,
-				   duplex ? "full" : "half", np->phys[0], mii_reg5);
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
+				   " negotiated capability %4.4x.\n", dev->name,
+				   duplex ? "full" : "half", np->phys[0], negotiated);
 	}
 	if (new_tx_mode != np->tx_mode) {
 		np->tx_mode = new_tx_mode;
@@ -718,11 +712,10 @@
 	}
 #endif
 
-	np->timer.expires = RUN_AT(next_tick);
+	np->timer.expires = jiffies + next_tick;
 	add_timer(&np->timer);
 }
 
-
 static void tx_timeout(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -753,6 +746,7 @@
 	/* Trigger an immediate transmit demand. */
 	/* XXX todo */
 
+	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
 }
 
@@ -775,12 +769,12 @@
 		np->rx_info[i].skb = skb;
 		if (skb == NULL)
 			break;
-		np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		skb->dev = dev;			/* Mark as being used by this device. */
 		/* Grrr, we cannot offset to correctly align the IP header. */
 		np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
 	}
-	writew(i-1, dev->base_addr + RxDescQIdx);
+	writew(i - 1, dev->base_addr + RxDescQIdx);
 	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	/* Clear the remainder of the Rx buffer ring. */
@@ -819,10 +813,10 @@
 
 	np->tx_info[entry].skb = skb;
 	np->tx_info[entry].mapping =
-		pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+		pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
 
 	np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping);
-	/* Add  |TxDescIntr to generate Tx-done interrupts. */
+	/* Add  "| TxDescIntr" to generate Tx-done interrupts. */
 	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID);
 	if (debug > 5) {
 		printk(KERN_DEBUG "%s: Tx #%d slot %d  %8.8x %8.8x.\n",
@@ -862,7 +856,8 @@
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
 	struct netdev_private *np;
-	long ioaddr, boguscnt = max_interrupt_work;
+	long ioaddr;
+	int boguscnt = max_interrupt_work;
 
 #ifndef final_version			/* Can never occur. */
 	if (dev == NULL) {
@@ -889,8 +884,8 @@
 			netdev_rx(dev);
 
 		/* Scavenge the skbuff list based on the Tx-done queue.
-		   There are redundant checks here that may be cleaned up when
-		   after the driver has proven reliable. */
+		   There are redundant checks here that may be cleaned up
+		   after the driver has proven to be reliable. */
 		{
 			int consumer = readl(ioaddr + TxConsumerIdx);
 			int tx_status;
@@ -905,7 +900,8 @@
 					   (np->tx_done+1) & (DONE_Q_SIZE-1),
 					   le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
 #endif
-			while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
+			while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status))
+				   != 0) {
 				if (debug > 4)
 					printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
 						   dev->name, np->tx_done, tx_status);
@@ -917,9 +913,9 @@
 					entry >>= 3;
 
 					skb = np->tx_info[entry].skb;
-					pci_unmap_single(np->pdev,
-									 np->tx_info[entry].mapping,
-									 skb->len, PCI_DMA_TODEVICE);
+					pci_unmap_single(np->pci_dev,
+							 np->tx_info[entry].mapping,
+							 skb->len, PCI_DMA_TODEVICE);
 
 					/* Scavenge the descriptor. */
 					dev_kfree_skb_irq(skb);
@@ -954,16 +950,27 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readl(ioaddr + IntrStatus));
 
-	return;
+#ifndef final_version
+	/* Code that should never be run!  Remove after testing.. */
+	{
+		static int stopit = 10;
+		if (!netif_running(dev)  &&  --stopit < 0) {
+			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
+				   dev->name);
+			free_irq(irq, dev);
+		}
+	}
+#endif
 }
 
-/* This routine is logically part of the interrupt handler, but seperated
+/* This routine is logically part of the interrupt handler, but separated
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 	u32 desc_status;
+
 	if (np->rx_done_q == 0) {
 		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
 			   dev->name, np->rx_done, np->tx_done_q);
@@ -977,7 +984,7 @@
 				   np->rx_done, desc_status);
 		if (--boguscnt < 0)
 			break;
-		if (! (desc_status & RxOK)) {
+		if ( ! (desc_status & RxOK)) {
 			/* There was a error. */
 			if (debug > 2)
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
@@ -1002,9 +1009,9 @@
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pdev,
-									np->rx_info[entry].mapping,
-									pkt_len, PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single(np->pci_dev,
+						    np->rx_info[entry].mapping,
+						    pkt_len, PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
 				eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
@@ -1015,11 +1022,19 @@
 			} else {
 				char *temp;
 
-				pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 				skb = np->rx_info[entry].skb;
 				temp = skb_put(skb, pkt_len);
 				np->rx_info[entry].skb = NULL;
 				np->rx_info[entry].mapping = 0;
+#ifndef final_version				/* Remove after testing. */
+				if (le32_to_cpu(np->rx_ring[entry].rxaddr & ~3) != ((unsigned long) temp))
+					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+						   "do not match in netdev_rx: %d vs. %p / %p.\n",
+						   dev->name,
+						   le32_to_cpu(np->rx_ring[entry].rxaddr),
+						   skb->head, temp);
+#endif
 			}
 #ifndef final_version				/* Remove after testing. */
 			/* You will want this info for the initial debug. */
@@ -1059,7 +1074,7 @@
 			if (skb == NULL)
 				break;			/* Better luck next round. */
 			np->rx_info[entry].mapping =
-				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			skb->dev = dev;			/* Mark as being used by this device. */
 			np->rx_ring[entry].rxaddr =
 				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
@@ -1108,7 +1123,7 @@
 		np->stats.rx_fifo_errors++;
 }
 
-static struct enet_statistics *get_stats(struct net_device *dev)
+static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -1263,7 +1278,7 @@
 	if (debug > 2) {
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
 			   np->tx_ring_dma);
-		for (i = 0; i < 8 /* TX_RING_SIZE */; i++)
+		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
 			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
 				   i, le32_to_cpu(np->tx_ring[i].status),
 				   le32_to_cpu(np->tx_ring[i].addr),
@@ -1284,7 +1299,7 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
 		if (np->rx_info[i].skb != NULL) {
-			pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(np->rx_info[i].skb);
 		}
 		np->rx_info[i].skb = NULL;
@@ -1293,9 +1308,9 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		struct sk_buff *skb = np->tx_info[i].skb;
 		if (skb != NULL) {
-			pci_unmap_single(np->pdev,
-							 np->tx_info[i].mapping,
-							 skb->len, PCI_DMA_TODEVICE);
+			pci_unmap_single(np->pci_dev,
+					 np->tx_info[i].mapping,
+					 skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 		}
 		np->tx_info[i].skb = NULL;
@@ -1313,10 +1328,8 @@
 	struct net_device *dev = pdev->driver_data;
 	struct netdev_private *np;
 	
-	if (!dev) {
-		printk (KERN_WARNING "bug: removing starfire pci dev without driver\n");
-		return;
-	}
+	if (!dev)
+		BUG();
 
 	np = dev->priv;
 
@@ -1324,16 +1337,16 @@
 	iounmap((char *)dev->base_addr);
 
 	if (np->tx_done_q)
-		pci_free_consistent(np->pdev, PAGE_SIZE,
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
 				    np->tx_done_q, np->tx_done_q_dma);
 	if (np->rx_done_q)
-		pci_free_consistent(np->pdev, PAGE_SIZE,
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
 				    np->rx_done_q, np->rx_done_q_dma);
 	if (np->tx_ring)
-		pci_free_consistent(np->pdev, PAGE_SIZE,
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
 				    np->tx_ring, np->tx_ring_dma);
 	if (np->rx_ring)
-		pci_free_consistent(np->pdev, PAGE_SIZE,
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
 				    np->rx_ring, np->rx_ring_dma);
 
 	kfree(dev);
@@ -1350,15 +1363,7 @@
 
 static int __init starfire_init (void)
 {
-	int rc;
-	
-	MOD_INC_USE_COUNT;
-	
-	rc = pci_module_init (&starfire_driver);
-	
-	MOD_DEC_USE_COUNT;
-	
-	return rc;
+	return pci_module_init (&starfire_driver);
 }
 
 
@@ -1374,8 +1379,8 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -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"
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
+ *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.3.99-pre6/linux/drivers/net/strip.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/strip.c	Tue May  2 12:41:00 2000
@@ -311,7 +311,6 @@
      */
 
     struct tty_struct *tty;			/* ptr to TTY structure		*/
-    char8              if_name;			/* Dynamically generated name	*/
     struct net_device      dev;			/* Our device structure		*/
 
     /*
@@ -1180,7 +1179,7 @@
     FirmwareVersion    firmware_version    = strip_info->firmware_version;
     SerialNumber       serial_number       = strip_info->serial_number;
     BatteryVoltage     battery_voltage     = strip_info->battery_voltage;
-    char8              if_name             = strip_info->if_name;
+    char*              if_name             = strip_info->dev.name;
     MetricomAddress    true_dev_addr       = strip_info->true_dev_addr;
     MetricomAddress    dev_dev_addr        = *(MetricomAddress*)strip_info->dev.dev_addr;
     int                manual_dev_addr     = strip_info->manual_dev_addr;
@@ -1196,7 +1195,7 @@
 #endif
     RestoreInterrupts(intstat);
 
-    p += sprintf(p, "\nInterface name\t\t%s\n", if_name.c);
+    p += sprintf(p, "\nInterface name\t\t%s\n", if_name);
     p += sprintf(p, " Radio working:\t\t%s\n", working ? "Yes" : "No");
     radio_address_to_string(&true_dev_addr, &addr_string);
     p += sprintf(p, " Radio address:\t\t%s\n", addr_string.c);
@@ -2664,8 +2663,7 @@
     strip_info->idle_timer.function = strip_IdleTask;
 
     /* Note: strip_info->if_name is currently 8 characters long */
-    sprintf(strip_info->if_name.c, "st%d", channel_id);
-    strip_info->dev.name         = strip_info->if_name.c;
+    sprintf(strip_info->dev.name, "st%d", channel_id);
     strip_info->dev.base_addr    = channel_id;
     strip_info->dev.priv         = (void*)strip_info;
     strip_info->dev.next         = NULL;
@@ -2736,7 +2734,7 @@
     MOD_INC_USE_COUNT;
 #endif
 
-    printk(KERN_INFO "STRIP: device \"%s\" activated\n", strip_info->if_name.c);
+    printk(KERN_INFO "STRIP: device \"%s\" activated\n", strip_info->dev.name);
 
     /*
      * Done.  We have linked the TTY line to a channel.
@@ -2767,7 +2765,7 @@
 
     tty->disc_data = 0;
     strip_info->tty = NULL;
-    printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->if_name.c);
+    printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->dev.name);
     strip_free(strip_info);
     tty->disc_data = NULL;
 #ifdef MODULE
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tokenring/abyss.c linux/drivers/net/tokenring/abyss.c
--- v2.3.99-pre6/linux/drivers/net/tokenring/abyss.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/tokenring/abyss.c	Fri Apr 28 23:00:05 2000
@@ -114,23 +114,28 @@
 		if (versionprinted++ == 0)
 			printk("%s", version);
 
-		pci_enable_device(pdev);
+		if (pci_enable_device(pdev))
+			continue;
 
 		/* Remove I/O space marker in bit 0. */
 		pci_irq_line = pdev->irq;
-		pci_ioaddr = pdev->resource[0].start ; 
+		pci_ioaddr = pci_resource_start (pdev, 0);
 		
-		if(check_region(pci_ioaddr, ABYSS_IO_EXTENT))
+		if(!request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss"))
 			continue;
 		
 		/* At this point we have found a valid card. */
 		
 		dev = init_trdev(NULL, 0);
+		if (!dev) {
+			release_region(pci_ioaddr, ABYSS_IO_EXTENT);
+			continue;
+		}
 		
-		request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss");
 		if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
 			       "abyss", dev)) { 
 			release_region(pci_ioaddr, ABYSS_IO_EXTENT) ; 
+			/* XXX free trdev */
 			continue; /*return (-ENODEV);*/ /* continue; ?? */
 		}
 		
@@ -140,7 +145,6 @@
 		  }
 		*/
 
-		pci_ioaddr &= ~3 ; 
 		dev->base_addr	= pci_ioaddr;
 		dev->irq 		= pci_irq_line;
 		dev->dma		= 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- v2.3.99-pre6/linux/drivers/net/tokenring/smctr.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/tokenring/smctr.c	Wed May 10 16:56:42 2000
@@ -49,6 +49,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/mca.h>
+#include <linux/delay.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tokenring/smctr.h linux/drivers/net/tokenring/smctr.h
--- v2.3.99-pre6/linux/drivers/net/tokenring/smctr.h	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/tokenring/smctr.h	Wed May 10 16:56:42 2000
@@ -1382,7 +1382,8 @@
  * Definitions for the field:
  * bic_type (Bus interface chip type)
  */
-#define BIC_NO_CHIP             0x0000  /* Bus interface chip not implemented */#define BIC_583_CHIP            0x0001  /* 83C583 bus interface chip */
+#define BIC_NO_CHIP             0x0000  /* Bus interface chip not implemented */
+#define BIC_583_CHIP            0x0001  /* 83C583 bus interface chip */
 #define BIC_584_CHIP            0x0002  /* 83C584 bus interface chip */
 #define BIC_585_CHIP            0x0003  /* 83C585 bus interface chip */
 #define BIC_593_CHIP            0x0004  /* 83C593 bus interface chip */
@@ -1486,7 +1487,8 @@
 
 #define MAX_8023_SIZE           1500    /* Max 802.3 size of frame. */
 #define DEFAULT_ERX_VALUE       4       /* Number of 16-byte blocks for 790B early Rx. */
-#define DEFAULT_ETX_VALUE       32      /* Number of bytes for 790B early Tx. */#define DEFAULT_TX_RETRIES      3       /* Number of transmit retries */
+#define DEFAULT_ETX_VALUE       32      /* Number of bytes for 790B early Tx. */
+#define DEFAULT_TX_RETRIES      3       /* Number of transmit retries */
 #define LPBK_FRAME_SIZE         1024    /* Default loopback frame for Rx calibration test. */
 #define MAX_LOOKAHEAD_SIZE      252     /* Max lookahead size for ethernet. */
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
--- v2.3.99-pre6/linux/drivers/net/tokenring/tms380tr.c	Fri Mar 10 16:40:43 2000
+++ linux/drivers/net/tokenring/tms380tr.c	Wed May  3 01:45:18 2000
@@ -270,8 +270,6 @@
 	tp->timer.expires	= jiffies + 30*HZ;
 	tp->timer.function	= tms380tr_timer_end_wait;
 	tp->timer.data		= (unsigned long)dev;
-	tp->timer.next		= NULL;
-	tp->timer.prev		= NULL;
 	add_timer(&tp->timer);
 
 	printk(KERN_INFO "%s: Adapter RAM size: %dK\n", 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tokenring/tmspci.c linux/drivers/net/tokenring/tmspci.c
--- v2.3.99-pre6/linux/drivers/net/tokenring/tmspci.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/tokenring/tmspci.c	Fri Apr 28 23:00:05 2000
@@ -137,11 +137,12 @@
 		if (versionprinted++ == 0)
 			printk("%s", version);
 
-		pci_enable_device(pdev);
+		if (pci_enable_device(pdev))
+			continue;
 
 		/* Remove I/O space marker in bit 0. */
 		pci_irq_line = pdev->irq;
-		pci_ioaddr = pdev->resource[0].start ; 
+		pci_ioaddr = pci_resource_start (pdev, 0);
 		
 		if(check_region(pci_ioaddr, TMS_PCI_IO_EXTENT))
 			continue;
@@ -149,11 +150,15 @@
 		/* At this point we have found a valid card. */
     
 		dev = init_trdev(NULL, 0);
+		if (!dev) {
+			continue; /*return (-ENOMEM);*/ /* continue; ?? */
+		}
 		
-		request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name);
+		request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name); /* XXX check return */
 		if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
 			       cardinfo->name, dev)) { 
 			release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); 
+			/* XXX free trdev */
 			continue; /*return (-ENODEV);*/ /* continue; ?? */
 		}
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.3.99-pre6/linux/drivers/net/tulip/tulip_core.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/tulip/tulip_core.c	Sat Apr 29 10:26:54 2000
@@ -1348,13 +1348,15 @@
 		netif_device_detach (dev);
 		tulip_down (dev);
 	}
+//	pci_set_power_state(pdev, 3);
 }
 
 
-static void tulip_resume (struct pci_dev *pdev)
+static void tulip_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pdev->driver_data;
 
+	pci_enable_device(pdev);
 	if (dev && !netif_device_present (dev)) {
 		tulip_up (dev);
 		netif_device_attach (dev);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.99-pre6/linux/drivers/net/via-rhine.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/via-rhine.c	Fri May  5 12:37:52 2000
@@ -1,22 +1,27 @@
 /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
 /*
-	Written 1998-1999 by Donald Becker.
+	Written 1998-2000 by Donald Becker.
 
-	This software may be used and distributed according to the terms
-	of the GNU Public License (GPL), incorporated herein by reference.
-	Drivers derived from this code also fall under the GPL and must retain
-	this authorship and copyright notice.
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
 
 	This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet
 	controller.  It also works with the older 3043 Rhine-I chip.
 
-	The author may be reached as becker@cesdis.edu, or
-	Donald Becker
-	312 Severn Ave. #W302
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
 	Annapolis MD 21403
 
-	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
+
+	This driver contains some changes from the original Donald Becker
+	version. He may or may not be interested in bug reports on this
+	code. You can find his versions at:
+	http://www.scyld.com/network/via-rhine.html
 
 
 	Linux kernel version history:
@@ -41,10 +46,15 @@
 	LK1.1.4:
 	- Urban Widmark: fix gcc 2.95.2 problem and
 	                 remove writel's to fixed address 0x7c
+
+	LK1.1.5:
+	- Urban Widmark: mdio locking, bounce buffer changes
+	                 merges from Beckers 1.05 version
+	                 added netif_running_on/off support
 */
 
-/* A few user-configurable values.   These may be modified when a driver
-   module is loaded. */
+/* A few user-configurable values.
+   These may be modified when a driver module is loaded. */
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
@@ -74,7 +84,8 @@
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	8
+#define TX_RING_SIZE	16
+#define TX_QUEUE_LEN	10				/* Limit ring entries actually used.  */
 #define RX_RING_SIZE	16
 
 
@@ -89,7 +100,7 @@
 #if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
 #warning  You must compile this file with the correct options!
 #warning  See the last lines of the source file.
-#error  See the last lines of the source file for the proper compile-command.
+#error  You must compile this driver with "-O".
 #endif
 
 #include <linux/module.h>
@@ -109,10 +120,11 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-static const char *versionA __devinitdata =
-"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";
+/* These identify the driver base version and may not be removed. */
+static char version1[] __devinitdata =
+"via-rhine.c:v1.05-LK1.1.5  5/2/2000  Written by Donald Becker\n";
+static char version2[] __devinitdata =
+"  http://www.scyld.com/network/via-rhine.html\n";
 
 
 
@@ -137,9 +149,7 @@
 #define writel outl
 #endif
 
-#define RUN_AT(x) (jiffies + (x))
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
@@ -262,7 +272,7 @@
 };
 
 
-enum chip_capability_flags {CanHaveMII=1, };
+enum chip_capability_flags {CanHaveMII=1, HasESIPhy=2 };
 
 #if defined(VIA_USE_MEMORY)
 #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
@@ -309,6 +319,19 @@
 	IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
 };
 
+/* MII interface, status flags.
+   Not to be confused with the MIIStatus register ... */
+enum mii_status_bits {
+	MIICap100T4			= 0x8000,
+	MIICap10100HdFd		= 0x7800,
+	MIIPreambleSupr		= 0x0040,
+	MIIAutoNegCompleted	= 0x0020,
+	MIIRemoteFault		= 0x0010,
+	MIICapAutoNeg		= 0x0008,
+	MIILink				= 0x0004,
+	MIIJabber			= 0x0002,
+	MIIExtended			= 0x0001
+};
 
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
@@ -355,7 +378,11 @@
 	/* The saved address of a sent-in-place packet/buffer, for later free(). */
 	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
-	unsigned char *tx_buf[TX_RING_SIZE];	/* Tx bounce buffers */
+
+	/* Tx bounce buffers */
+	unsigned char *tx_buf[TX_RING_SIZE];
+	unsigned char *tx_bufs;
+	dma_addr_t tx_bufs_dma;
 
 	struct pci_dev *pdev;
 	struct net_device_stats stats;
@@ -363,25 +390,23 @@
 	spinlock_t lock;
 
 	/* Frequently used values: keep some adjacent for cache effect. */
-	int chip_id;
+	int chip_id, drv_flags;
 	struct rx_desc *rx_head_desc;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
 	u16 chip_cmd;						/* Current setting for ChipCmd */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
 
 	/* These values are keep track of the transceiver/media in use. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
-	unsigned int medialock:1;			/* Do not sense media. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	u8 tx_thresh, rx_thresh;
 
 	/* MII transceiver section. */
-	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[2];				/* MII device addresses. */
+	u16 mii_status;						/* last read MII status */
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
@@ -400,6 +425,7 @@
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
+static inline void clear_tally_counters(long ioaddr);
 
 
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
@@ -420,8 +446,8 @@
 	
 	/* print version once and once only */
 	if (! did_version++) {
-		printk (KERN_INFO "%s", versionA);
-		printk (KERN_INFO "%s", versionB);
+		printk (KERN_INFO "%s", version1);
+		printk (KERN_INFO "%s", version2);
 	}
 	
 	card_idx++;
@@ -454,11 +480,8 @@
 
 	ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
 
-	if (pci_enable_device (pdev)) {
-		printk (KERN_ERR "unable to init PCI device (card #%d)\n",
-			card_idx);
+	if (pci_enable_device (pdev))
 		goto err_out_free_dma;
-	}
 	
 	if (pci_flags & PCI_USES_MASTER)
 		pci_set_master (pdev);
@@ -500,8 +523,8 @@
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
 		   dev->name, via_rhine_chip_info[chip_id].name, ioaddr);
 
-	/* Ideally we would be read the EEPROM but access may be locked. */
-	for (i = 0; i <6; i++)
+	/* Ideally we would read the EEPROM but access may be locked. */
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
 	for (i = 0; i < 5; i++)
 			printk("%2.2x:", dev->dev_addr[i]);
@@ -516,6 +539,7 @@
 	np = dev->priv;
 	spin_lock_init (&np->lock);
 	np->chip_id = chip_id;
+	np->drv_flags = via_rhine_chip_info[chip_id].drv_flags;
 	np->pdev = pdev;
 	np->rx_ring = ring;
 	np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
@@ -530,8 +554,6 @@
 		if (option & 0x200)
 			np->full_duplex = 1;
 		np->default_port = option & 15;
-		if (np->default_port)
-			np->medialock = 1;
 	}
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
 		np->full_duplex = 1;
@@ -551,7 +573,7 @@
 	
 	pdev->driver_data = dev;
 
-	if (via_rhine_chip_info[chip_id].drv_flags & CanHaveMII) {
+	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Standard for this chip. */
 		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
@@ -565,7 +587,6 @@
 					   mdio_read(dev, phy, 5));
 			}
 		}
-		np->mii_cnt = phy_idx;
 	}
 
 	return 0;
@@ -630,7 +651,6 @@
 	writeb(regnum, ioaddr + MIIRegAddr);
 	writew(value, ioaddr + MIIData);
 	writeb(0x20, ioaddr + MIICmd);			/* Trigger write. */
-	return;
 }
 
 
@@ -654,6 +674,14 @@
 		printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
 			   dev->name, dev->irq);
 
+	np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
+									   &np->tx_bufs_dma);
+	if (np->tx_bufs == NULL) {
+		free_irq(dev->irq, dev);
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
 	via_rhine_init_ring(dev);
 
 	writel(np->rx_ring_dma, ioaddr + RxRingPtr);
@@ -689,6 +717,12 @@
 
 	via_rhine_check_duplex(dev);
 
+	/* The LED outputs of various MII xcvrs should be configured.  */
+	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
+	/* For ESI phys, turn on bit 7 in register 0x17. */
+	mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
+			   (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
 			   "MII status: %4.4x.\n",
@@ -697,7 +731,7 @@
 
 	/* Set the timer to check for link beat. */
 	init_timer(&np->timer);
-	np->timer.expires = RUN_AT(1);
+	np->timer.expires = jiffies + 2;
 	np->timer.data = (unsigned long)dev;
 	np->timer.function = &via_rhine_timer;				/* timer handler */
 	add_timer(&np->timer);
@@ -737,15 +771,30 @@
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
+	int mii_status;
 
 	if (debug > 3) {
 		printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 	}
 
+	spin_lock_irq (&np->lock);
+
 	via_rhine_check_duplex(dev);
 
-	np->timer.expires = RUN_AT(next_tick);
+	/* make IFF_RUNNING follow the MII status bit "Link established" */
+	mii_status = mdio_read(dev, np->phys[0], 1);
+	if ( (mii_status & MIILink) != (np->mii_status & MIILink) ) {
+		if (mii_status & MIILink)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
+	}
+	np->mii_status = mii_status;
+
+	spin_unlock_irq (&np->lock);
+
+	np->timer.expires = jiffies + next_tick;
 	add_timer(&np->timer);
 }
 
@@ -755,6 +804,11 @@
 	struct netdev_private *np = (struct netdev_private *) dev->priv;
 	long ioaddr = dev->base_addr;
 
+	/* Lock to protect mdio_read and access to stats. A friendly
+       advice to the implementor of the XXXs in this function is to be
+       sure not to spin too long (whatever that means :) */
+	spin_lock_irq (&np->lock);
+
 	printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
 		"%4.4x, resetting...\n",
 		dev->name, readw (ioaddr + IntrStatus),
@@ -771,6 +825,8 @@
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
+
+	spin_unlock_irq (&np->lock);
 }
 
 
@@ -797,7 +853,7 @@
 	/* Mark the last entry as wrapping the ring. */
 	np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
 
-	/* Fill in the Rx buffers. */
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
 		np->rx_skbuff[i] = skb;
@@ -821,7 +877,7 @@
 		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
 		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_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
 	}
 	np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
 
@@ -832,13 +888,12 @@
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	unsigned entry;
-	unsigned long flags;
 
 	/* Caution: the write order is important here, set the field
 	   with the "ownership" bits last. */
 
 	/* lock eth irq */
-	spin_lock_irqsave (&np->lock, flags);
+	spin_lock_irq (&np->lock);
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
@@ -846,21 +901,15 @@
 	np->tx_skbuff[entry] = skb;
 
 	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
-		if (np->tx_buf[entry] == NULL &&
-			(np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) {
-			spin_unlock_irqrestore (&np->lock, flags);
-			return 1;
-		}
 		memcpy(np->tx_buf[entry], skb->data, skb->len);
-		np->tx_skbuff_dma[entry] =
-			pci_map_single(np->pdev, np->tx_buf[entry], skb->len,
-						   PCI_DMA_TODEVICE);
+		np->tx_skbuff_dma[entry] = 0;
+		np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma +
+										  (np->tx_buf[entry] - np->tx_bufs));
 	} else {
 		np->tx_skbuff_dma[entry] =
-			pci_map_single(np->pdev, skb->data, skb->len,
-						   PCI_DMA_TODEVICE);
+			pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+		np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
 	}
-	np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
 
 	np->tx_ring[entry].desc_length = 
 		cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
@@ -873,12 +922,12 @@
 	/* Wake the potentially-idle transmit channel. */
 	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 
-	if (np->cur_tx == np->dirty_tx + TX_RING_SIZE)
+	if (np->cur_tx == np->dirty_tx + TX_QUEUE_LEN)
 		netif_stop_queue(dev);
 
 	dev->trans_start = jiffies;
 
-	spin_unlock_irqrestore (&np->lock, flags);
+	spin_unlock_irq (&np->lock);
 
 	if (debug > 4) {
 		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
@@ -892,8 +941,9 @@
 static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
-	long ioaddr, boguscnt = max_interrupt_work;
+	long ioaddr;
 	u32 intr_status;
+	int boguscnt = max_interrupt_work;
 
 	ioaddr = dev->base_addr;
 	
@@ -940,7 +990,7 @@
 
 	spin_lock (&np->lock);
 
-	/* if tx_full is set, they're all dirty, not clean */
+	/* find and cleanup dirty tx descriptors */
 	while (np->dirty_tx != np->cur_tx) {
 		txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
 		if (txstatus & DescOwn)
@@ -961,18 +1011,20 @@
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
 			np->stats.collisions += (txstatus >> 3) & 15;
-			np->stats.tx_bytes += le32_to_cpu(np->tx_ring[entry].desc_length) & 0x7ff;
+			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
 			np->stats.tx_packets++;
 		}
 		/* Free the original skb. */
-		pci_unmap_single(np->pdev,
-						 le32_to_cpu(np->tx_ring[entry].addr),
-						 np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+		if (np->tx_skbuff_dma[entry]) {
+			pci_unmap_single(np->pdev,
+							 np->tx_skbuff_dma[entry],
+							 np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+		}
 		dev_kfree_skb_irq(np->tx_skbuff[entry]);
 		np->tx_skbuff[entry] = NULL;
 		entry = (++np->dirty_tx) % TX_RING_SIZE;
 	}
-	if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2)
+	if ((np->cur_tx - np->dirty_tx) < TX_QUEUE_LEN - 4)
 		netif_wake_queue (dev);
 
 	spin_unlock (&np->lock);
@@ -1019,12 +1071,17 @@
 				if (desc_status & 0x0030) np->stats.rx_length_errors++;
 				if (desc_status & 0x0048) np->stats.rx_fifo_errors++;
 				if (desc_status & 0x0004) np->stats.rx_frame_errors++;
-				if (desc_status & 0x0002) np->stats.rx_crc_errors++;
+				if (desc_status & 0x0002) {
+					/* this can also be updated outside the interrupt handler */
+					spin_lock (&np->lock);
+					np->stats.rx_crc_errors++;
+					spin_unlock (&np->lock);
+				}
 			}
 		} else {
 			struct sk_buff *skb;
 			/* Length should omit the CRC */
-			u16 pkt_len = data_size - 4;
+			int pkt_len = data_size - 4;
 
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
@@ -1034,7 +1091,11 @@
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry],
 						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-#if ! defined(__alpha__) || USE_IP_COPYSUM		/* Avoid misaligned on Alpha */
+
+				/* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum
+				   is memcpy for all archs so this is kind of pointless right
+				   now ... or? */
+#if HAS_IP_COPYSUM                     /* Call copy + cksum if available. */
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
@@ -1090,6 +1151,8 @@
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
+	spin_lock (&np->lock);
+
 	if (intr_status & (IntrMIIChange | IntrLinkChange)) {
 		if (readb(ioaddr + MIIStatus) & 0x02)
 			/* Link failed, restart autonegotiation. */
@@ -1105,6 +1168,7 @@
 	if (intr_status & IntrStatsMax) {
 		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
+		clear_tally_counters(ioaddr);
 	}
 	if (intr_status & IntrTxAbort) {
 		/* Stats counted in Tx-done handler, just restart Tx. */
@@ -1124,22 +1188,37 @@
 		/* Recovery for other fault sources not known. */
 		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 	}
+
+	spin_unlock (&np->lock);
 }
 
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
+	unsigned long flags;
 
-	/* Nominally we should lock this segment of code for SMP, although
-	   the vulnerability window is very small and statistics are
-	   non-critical. */
+	spin_lock_irqsave(&np->lock, flags);
 	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
+	clear_tally_counters(ioaddr);
+	spin_unlock_irqrestore(&np->lock, flags);
 
 	return &np->stats;
 }
 
+/* Clears the "tally counters" for CRC errors and missed frames(?).
+   It has been reported that some chips need a write of 0 to clear
+   these, for others the counters are set to 1 when written to and
+   instead cleared when read. So we clear them both ways ... */
+static inline void clear_tally_counters(const long ioaddr)
+{
+	writel(0, ioaddr + RxMissed);
+	readw(ioaddr + RxCRCErrs);
+	readw(ioaddr + RxMissed);
+}
+
+
 /* The big-endian AUTODIN II ethernet CRC calculation.
    N.B. Do not use for bulk data, use a table-based routine instead.
    This is common code and should be moved to net/core/crc.c */
@@ -1193,23 +1272,34 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&np->lock, flags);
+	retval = 0;
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
+		data[0] = np->phys[0] & 0x1f;
 		/* Fall Through */
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-		return 0;
+		break;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+			break;
+		}
 		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		return 0;
+		break;
 	default:
-		return -EOPNOTSUPP;
+		retval = -EOPNOTSUPP;
 	}
+
+	spin_unlock_irqrestore(&np->lock, flags);
+	return retval;
 }
 
 static int via_rhine_close(struct net_device *dev)
@@ -1217,6 +1307,9 @@
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&np->lock, flags);
 
 	netif_stop_queue(dev);
 
@@ -1232,6 +1325,11 @@
 
 	del_timer(&np->timer);
 
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	/* Make sure there is no irq-handler running on a different CPU. */
+	synchronize_irq();
+
 	free_irq(dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
@@ -1247,11 +1345,24 @@
 		np->rx_skbuff[i] = 0;
 	}
 
+	/* Free all the skbuffs in the Tx queue, and also any bounce buffers. */
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (np->tx_skbuff[i])
+		np->tx_ring[i].tx_status = 0;
+		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->tx_skbuff[i]) {
+			if (np->tx_skbuff_dma[i]) {
+				pci_unmap_single(np->pdev,
+								 np->tx_skbuff_dma[i],
+								 np->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+			}
 			dev_kfree_skb(np->tx_skbuff[i]);
+		}
 		np->tx_skbuff[i] = 0;
+		np->tx_buf[i] = 0;
 	}
+	pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
+						np->tx_bufs, np->tx_bufs_dma);
 
 	MOD_DEC_USE_COUNT;
 
@@ -1294,15 +1405,7 @@
 
 static int __init via_rhine_init (void)
 {
-	int rc;
-	
-	MOD_INC_USE_COUNT;
-	
-	rc = pci_module_init (&via_rhine_driver);
-	
-	MOD_DEC_USE_COUNT;
-	
-	return rc;
+	return pci_module_init (&via_rhine_driver);
 }
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c
--- v2.3.99-pre6/linux/drivers/net/wan/comx.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/comx.c	Tue May  2 12:41:00 2000
@@ -877,7 +877,7 @@
 		return -ENOMEM;
 	}
 	memset(dev, 0, sizeof(struct net_device));
-	dev->name = (char *)new_dir->name;
+	strcpy(dev->name, (char *)new_dir->name);
 	dev->init = comx_init_dev;
 
 	if (register_netdevice(dev)) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- v2.3.99-pre6/linux/drivers/net/wan/cosa.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/cosa.c	Tue May  2 12:41:00 2000
@@ -588,7 +588,7 @@
 	memset(chan->pppdev.dev, 0, sizeof(struct net_device));
 	sppp_attach(&chan->pppdev);
 	d=chan->pppdev.dev;
-	d->name = chan->name;
+	strcpy(d->name, chan->name);
 	d->base_addr = chan->cosa->datareg;
 	d->irq = chan->cosa->irq;
 	d->dma = chan->cosa->dma;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.99-pre6/linux/drivers/net/wan/cycx_x25.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/net/wan/cycx_x25.c	Thu May  4 11:31:21 2000
@@ -422,7 +422,7 @@
 	}
 
 	/* prepare network device data space for registration */
-	dev->name = chan->name;
+	strcpy(dev->name, chan->name);
 	dev->init = if_init;
 	dev->priv = chan;
 
@@ -1513,11 +1513,8 @@
 {
 	x25_channel_t *chan = dev->priv;
 
-	if (chan->svc) {
-		del_timer(&chan->timer);
-		chan->timer.expires = jiffies + chan->idle_tmout * HZ;
-		add_timer(&chan->timer);
-	}
+	if (chan->svc)
+		mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
 }
 #ifdef CYCLOMX_X25_DEBUG
 static void x25_dump_config(TX25Config *conf)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- v2.3.99-pre6/linux/drivers/net/wan/dlci.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/wan/dlci.c	Tue May  2 12:41:00 2000
@@ -441,13 +441,6 @@
 		return(-ENOMEM);
 
 	memset(master, 0, sizeof(*master));
-	master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
-
-	if (!master->name)
-	{
-		kfree(master);
-		return(-ENOMEM);
-	}
 
 	strcpy(master->name, buf);
 	master->init = dlci_init;
@@ -456,7 +449,6 @@
 	err = register_netdev(master);
 	if (err < 0)
 	{
-		kfree(master->name);
 		kfree(master);
 		return(err);
 	}
@@ -472,7 +464,6 @@
 	{
 		unregister_netdev(master);
 		kfree(master->priv);
-		kfree(master->name);
 		kfree(master);
 		return(err);
 	}
@@ -516,7 +507,6 @@
 		open_dev[i] = NULL;
 
 	kfree(master->priv);
-	kfree(master->name);
 	kfree(master);
 
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c
--- v2.3.99-pre6/linux/drivers/net/wan/hostess_sv11.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/wan/hostess_sv11.c	Tue May  2 12:41:00 2000
@@ -44,7 +44,6 @@
 	void *if_ptr;	/* General purpose pointer (used by SPPP) */
 	struct z8530_dev sync;
 	struct ppp_device netdev;
-	char name[16];
 };
 
 /*
@@ -279,7 +278,6 @@
 	dev->chanA.netdevice=sv->netdev.dev;
 	dev->chanA.dev=dev;
 	dev->chanB.dev=dev;
-	dev->name=sv->name;
 	
 	if(dma)
 	{
@@ -323,55 +321,48 @@
 	/*
 	 *	Now we can take the IRQ
 	 */
-	
-	for(i=0;i<999;i++)
+	if(dev_alloc_name(dev->chanA.netdevice,"hdlc%d")>=0)
 	{
-		sprintf(sv->name,"hdlc%d", i);
-		if(dev_get(sv->name)==0)
-		{
-			struct net_device *d=dev->chanA.netdevice;
-	
-			/* 
-			 *	Initialise the PPP components
-			 */
-			sppp_attach(&sv->netdev);
-			
-			/*
-			 *	Local fields
-			 */	
-			sprintf(sv->name,"hdlc%d", i);
-			
-			d->name = sv->name;
-			d->base_addr = iobase;
-			d->irq = irq;
-			d->priv = sv;
-			d->init = NULL;
-			
-			d->open = hostess_open;
-			d->stop = hostess_close;
-			d->hard_start_xmit = hostess_queue_xmit;
-			d->get_stats = hostess_get_stats;
-			d->set_multicast_list = NULL;
-			d->do_ioctl = hostess_ioctl;
+		struct net_device *d=dev->chanA.netdevice;
+
+		/* 
+		 *	Initialise the PPP components
+		 */
+		sppp_attach(&sv->netdev);
+		
+		/*
+		 *	Local fields
+		 */	
+		
+		d->base_addr = iobase;
+		d->irq = irq;
+		d->priv = sv;
+		d->init = NULL;
+		
+		d->open = hostess_open;
+		d->stop = hostess_close;
+		d->hard_start_xmit = hostess_queue_xmit;
+		d->get_stats = hostess_get_stats;
+		d->set_multicast_list = NULL;
+		d->do_ioctl = hostess_ioctl;
 #ifdef LINUX_21			
-			d->neigh_setup = hostess_neigh_setup_dev;
-			dev_init_buffers(d);
+		d->neigh_setup = hostess_neigh_setup_dev;
+		dev_init_buffers(d);
 #else
-			d->init = return_0;
+		d->init = return_0;
 #endif
-			d->set_mac_address = NULL;
-			
-			if(register_netdev(d)==-1)
-			{
-				printk(KERN_ERR "%s: unable to register device.\n",
-					sv->name);
-				goto fail;
-			}				
-
-			z8530_describe(dev, "I/O", iobase);
-			dev->active=1;
-		 	return sv;	
-		}
+		d->set_mac_address = NULL;
+		
+		if(register_netdev(d)==-1)
+		{
+			printk(KERN_ERR "%s: unable to register device.\n",
+				d->name);
+			goto fail;
+		}				
+
+		z8530_describe(dev, "I/O", iobase);
+		dev->active=1;
+		return sv;	
 	}
 dmafail2:
 	if(dma==1)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.3.99-pre6/linux/drivers/net/wan/lapbether.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/wan/lapbether.c	Thu May  4 11:31:21 2000
@@ -441,7 +441,7 @@
 	}
 	
 	dev->priv = (void *)lapbeth;	/* pointer back */
-	dev->name = buf;
+	strcpy(dev->name, buf);
 	dev->init = lapbeth_dev_init;
 
 	if (register_netdev(dev) != 0) {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- v2.3.99-pre6/linux/drivers/net/wan/lmc/lmc_main.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/lmc/lmc_main.c	Thu May  4 11:31:21 2000
@@ -856,11 +856,6 @@
     /*
      *	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
@@ -868,7 +863,6 @@
      * 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
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.3.99-pre6/linux/drivers/net/wan/sdla_chdlc.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/sdla_chdlc.c	Thu May  4 11:31:21 2000
@@ -603,7 +603,7 @@
 	chdlc_priv_area->mc = conf->mc;
 
 	/* prepare network device data space for registration */
-	dev->name = card->u.c.if_name;
+	strcpy(dev->name, card->u.c.if_name);
 	dev->init = &if_init;
 	dev->priv = chdlc_priv_area;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.3.99-pre6/linux/drivers/net/wan/sdla_fr.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/sdla_fr.c	Thu May  4 11:31:21 2000
@@ -814,7 +814,7 @@
 	chan->transmit_length = 0;
 
 	/* prepare network device data space for registration */
-	dev->name = chan->name;
+	strcpy(dev->name, chan->name);
 	dev->init = &if_init;
 	dev->priv = chan;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.3.99-pre6/linux/drivers/net/wan/sdla_ppp.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/wan/sdla_ppp.c	Thu May  4 11:31:21 2000
@@ -501,7 +501,7 @@
 
 
 	/* prepare network device data space for registration */
-	dev->name = card->u.p.if_name;
+	strcpy(dev->name, card->u.p.if_name);
 	dev->init = &if_init;
 	dev->priv = ppp_priv_area;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.3.99-pre6/linux/drivers/net/wan/sdla_x25.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/wan/sdla_x25.c	Thu May  4 11:31:21 2000
@@ -464,7 +464,7 @@
 	}
 
 	/* prepare network device data space for registration */
-	dev->name = chan->name;
+	strcpy(dev->name, chan->name);
 	dev->init = &if_init;
 	dev->priv = chan;
 	return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c
--- v2.3.99-pre6/linux/drivers/net/wan/sealevel.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/wan/sealevel.c	Tue May  2 12:41:00 2000
@@ -35,7 +35,6 @@
 	void *if_ptr;	/* General purpose pointer (used by SPPP) */
 	struct z8530_channel *chan;
 	struct ppp_device netdev;
-	char name[16];
 	int channel;
 };
 
@@ -223,7 +222,6 @@
 	struct slvl_device *sv;
 	struct slvl_board *b;
 	
-	int i;
 	unsigned long flags;
 	int u;
 	
@@ -306,7 +304,6 @@
 	dev->chanB.netdevice=b->dev[1].netdev.dev;
 	dev->chanA.dev=dev;
 	dev->chanB.dev=dev;
-	dev->name=b->dev[0].name;
 
 	dev->chanA.txdma=3;
 	dev->chanA.rxdma=1;
@@ -350,52 +347,46 @@
 		sv=&b->dev[u];
 		sv->channel = u;
 	
-		for(i=0;i<999;i++)
+		if(dev_alloc_name(sv->chan->netdevice,"hdlc%d")>=0)
 		{
-			sprintf(sv->name,"hdlc%d", i);
-			if(dev_get(sv->name)==0)
-			{
-				struct net_device *d=sv->chan->netdevice;
-	
-				/* 
-				 *	Initialise the PPP components
-				 */
-				sppp_attach(&sv->netdev);
-			
-				/*
-				 *	Local fields
-				 */	
-				sprintf(sv->name,"hdlc%d", i);
-				
-				d->name = sv->name;
-				d->base_addr = iobase;
-				d->irq = irq;
-				d->priv = sv;
-				d->init = NULL;
+			struct net_device *d=sv->chan->netdevice;
+
+			/* 
+			 *	Initialise the PPP components
+			 */
+			sppp_attach(&sv->netdev);
+		
+			/*
+			 *	Local fields
+			 */	
 			
-				d->open = sealevel_open;
-				d->stop = sealevel_close;
-				d->hard_start_xmit = sealevel_queue_xmit;
-				d->get_stats = sealevel_get_stats;
-				d->set_multicast_list = NULL;
-				d->do_ioctl = sealevel_ioctl;
+			d->base_addr = iobase;
+			d->irq = irq;
+			d->priv = sv;
+			d->init = NULL;
+		
+			d->open = sealevel_open;
+			d->stop = sealevel_close;
+			d->hard_start_xmit = sealevel_queue_xmit;
+			d->get_stats = sealevel_get_stats;
+			d->set_multicast_list = NULL;
+			d->do_ioctl = sealevel_ioctl;
 #ifdef LINUX_21			
-				d->neigh_setup = sealevel_neigh_setup_dev;
-				dev_init_buffers(d);
+			d->neigh_setup = sealevel_neigh_setup_dev;
+			dev_init_buffers(d);
 #else
-				d->init = return_0;
+			d->init = return_0;
 #endif
-				d->set_mac_address = NULL;
-			
-				if(register_netdev(d)==-1)
-				{
-					printk(KERN_ERR "%s: unable to register device.\n",
-						sv->name);
-					goto fail_unit;
-				}				
+			d->set_mac_address = NULL;
+		
+			if(register_netdev(d)==-1)
+			{
+				printk(KERN_ERR "%s: unable to register device.\n",
+					d->name);
+				goto fail_unit;
+			}				
 
-				break;
-			}
+			break;
 		}
 	}
 	z8530_describe(dev, "I/O", iobase);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- v2.3.99-pre6/linux/drivers/net/wan/x25_asy.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/wan/x25_asy.c	Thu May  4 11:31:21 2000
@@ -32,7 +32,6 @@
 #include "x25_asy.h"
 
 typedef struct x25_ctrl {
-	char		if_name[8];	/* "xasy0\0" .. "xasy99999\0"	*/
 	struct x25_asy	ctrl;		/* X.25 things			*/
 	struct net_device	dev;		/* the device			*/
 } x25_asy_ctrl_t;
@@ -82,8 +81,7 @@
 		/* Initialize channel control data */
 		set_bit(SLF_INUSE, &slp->ctrl.flags);
 		slp->ctrl.tty         = NULL;
-		sprintf(slp->if_name, "x25asy%d", i);
-		slp->dev.name         = slp->if_name;
+		sprintf(slp->dev.name, "x25asy%d", i);
 		slp->dev.base_addr    = i;
 		slp->dev.priv         = (void*)&(slp->ctrl);
 		slp->dev.next         = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.3.99-pre6/linux/drivers/net/wavelan.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/net/wavelan.c	Tue May  2 12:41:00 2000
@@ -4211,7 +4211,6 @@
 				break;
 			}
 			memset(dev, 0x00, sizeof(struct net_device));
-			dev->name = name[i];
 			dev->base_addr = io[i];
 			dev->irq = irq[i];
 			dev->init = &wavelan_config;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.3.99-pre6/linux/drivers/net/wavelan.p.h	Sat Feb 26 22:31:47 2000
+++ linux/drivers/net/wavelan.p.h	Wed May  3 01:45:19 2000
@@ -695,10 +695,8 @@
 /* Parameters set by insmod */
 static int	io[4]	= { 0, 0, 0, 0 };
 static int	irq[4]	= { 0, 0, 0, 0 };
-static char	name[4][IFNAMSIZ] = { "", "", "", "" };
 MODULE_PARM(io, "1-4i");
 MODULE_PARM(irq, "1-4i");
-MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ));
 #endif	/* MODULE */
 
 #endif	/* WAVELAN_P_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v2.3.99-pre6/linux/drivers/net/wd.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/wd.c	Tue May  2 12:41:00 2000
@@ -442,11 +442,9 @@
 
 #ifdef MODULE
 #define MAX_WD_CARDS	4	/* Max number of wd cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_WD_CARDS] = { 0, };
 static struct net_device dev_wd[MAX_WD_CARDS] = {
 	{
-		NULL,		/* assign a chunk of namelist[] below */
+		"",		/* assign a chunk of namelist[] below */
 		0, 0, 0, 0,
 		0, 0,
 		0, 0, 0, NULL, NULL
@@ -472,7 +470,6 @@
 
 	for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
 		struct net_device *dev = &dev_wd[this_dev];
-		dev->name = namelist+(NAMELEN*this_dev);
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->mem_start = mem[this_dev];
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.99-pre6/linux/drivers/net/yellowfin.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/net/yellowfin.c	Fri Apr 28 23:00:05 2000
@@ -1255,6 +1255,7 @@
 		goto err_out_free_pio_region;
 	}
 	
+	/* XXX check enable_device for failure */
 	pci_enable_device (pdev);
 	pci_set_master (pdev);
 
@@ -1263,6 +1264,7 @@
 #else
 	real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
 	ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
+	/* XXX check for failure */
 #endif
 	irq = pdev->irq;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.99-pre6/linux/drivers/pci/pci.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/pci/pci.c	Fri Apr 28 23:05:24 2000
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
+#include <linux/pm.h>
 
 #include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
@@ -1020,6 +1021,106 @@
 	return b;
 }
 
+#ifdef CONFIG_PM
+
+/*
+ * PCI Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ */
+static int pci_pm_suspend_device(struct pci_dev *dev)
+{
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->suspend)
+			driver->suspend(dev);
+	}
+	return 0;
+}
+
+static int pci_pm_resume_device(struct pci_dev *dev)
+{
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->resume)
+			driver->resume(dev);
+	}
+	return 0;
+}
+
+static int pci_pm_suspend_bus(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	/* Walk the bus children list */
+	list_for_each(list, &bus->children) 
+		pci_pm_suspend_bus(pci_bus_b(list));
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_suspend_device(pci_dev_b(list));
+
+	/* Suspend the bus controller.. */
+	pci_pm_suspend_device(bus->self);
+	return 0;
+}
+
+static int pci_pm_resume_bus(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	pci_pm_resume_device(bus->self);
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_resume_device(pci_dev_b(list));
+
+	/* And then walk the bus children */
+	list_for_each(list, &bus->children)
+		pci_pm_resume_bus(pci_bus_b(list));
+	return 0;
+}
+
+static int pci_pm_suspend(void)
+{
+	struct list_head *list;
+
+	list_for_each(list, &pci_root_buses)
+		pci_pm_suspend_bus(pci_bus_b(list));
+	return 0;
+}
+
+static int pci_pm_resume(void)
+{
+	struct list_head *list;
+
+	list_for_each(list, &pci_root_buses)
+		pci_pm_resume_bus(pci_bus_b(list));
+	return 0;
+}
+
+static int pci_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	switch (rqst) {
+	case PM_SUSPEND:
+		return pci_pm_suspend();
+	case PM_RESUME:
+		return pci_pm_resume();
+	}	
+	return 0;
+}
+#endif
+
 void __init pci_init(void)
 {
 	struct pci_dev *dev;
@@ -1029,6 +1130,10 @@
 	pci_for_each_dev(dev) {
 		pci_fixup_device(PCI_FIXUP_FINAL, dev);
 	}
+
+#ifdef CONFIG_PM
+	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+#endif
 }
 
 static int __init pci_setup(char *str)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.3.99-pre6/linux/drivers/pci/pci.ids	Wed Apr 26 16:34:08 2000
+++ linux/drivers/pci/pci.ids	Tue May  2 13:06:57 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.56 2000/04/17 16:11:58 mj Exp $
+#	$Id: pci.ids,v 1.60 2000/05/01 19:53:05 mj Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -315,7 +315,8 @@
 	0046  DECchip 21554
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
-	1065  RAID Controller
+	1065  StrongARM DC21285
+		1069 0020  DAC960P
 1012  Micronics Computers Inc
 1013  Cirrus Logic
 	0038  GD 7548
@@ -372,6 +373,7 @@
 	002d  Python
 	002e  ServeRAID controller
 	0036  Miami
+	003a  CPU to PCI Bridge
 	003e  16/4 Token ring UTP/STP controller
 		1014 003e  Token-Ring Adapter
 		1014 00cd  Token-Ring Adapter + Wake-On-LAN
@@ -379,16 +381,30 @@
 		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
+	0045  SSA Adapter
 	0046  MPIC interrupt controller
 	0047  PCI to PCI Bridge
 	0048  PCI to PCI Bridge
+	004e  ATM Controller (14104e00)
+	004f  ATM Controller (14104f00)
+	0050  ATM Controller (14105000)
 	0053  25 MBit ATM Controller
 	0057  MPEG PCI Bridge
 	005c  i82557B 10/100
+	007c  ATM Controller (14107c00)
 	007d  3780IDSP [MWave]
+	0090  GXT 3000P
+		1014 008E  GXT-3000P
 	0095  20H2999 PCI Docking Bridge
+	00a5  ATM Controller (1410a500)
+	00a6  ATM 155MBPS MM Controller (1410a600)
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
 		1902 00b8  Fire GL1
+	00be  ATM 622MBPS Controller (1410be00)
+	0142  Yotta Video Compositor Input
+		1014 0143 Yotta Input Controller (ytin)
+	0144  Yotta Video Compositor Output
+		1014 0145 Yotta Output Controller (ytout)
 	ffff  MPIC-2 interrupt controller
 1015  LSI Logic Corp of Canada
 1016  ICL Personal Systems
@@ -1387,6 +1403,7 @@
 	1077  VScom 400 4 port serial adaptor
 	9036  9036
 	9050  PCI <-> IOBus Bridge
+		10b5 2273  SH-ARC SoHard ARCnet card
 		d84d 4006  EX-4006 1P
 		d84d 4008  EX-4008 1P EPP/ECP
 		d84d 4014  EX-4014 2P
@@ -2398,6 +2415,7 @@
 11ae  Aztech System Ltd
 11af  Avid Technology Inc.
 11b0  V3 Semiconductor Inc.
+	0002  V300PSC
 	0292  V292PBC [Am29030/40 Bridge]
 	0960  V96xPBC
 	c960  V96DPC
@@ -2496,7 +2514,7 @@
 	0458  LT WinModem
 	0459  LT WinModem
 	045a  LT WinModem
-	0480  Venus WinModem (V90, 56KFlex)
+	0480  Venus Modem (V90, 56KFlex)
 11c2  Sand Microelectronics
 11c3  NEC Corp
 11c4  Document Technologies, Inc
@@ -2665,7 +2683,7 @@
 		139c 0017  Raven
 		14af 0002  Maxi Gamer Phoenix
 		3030 3030  Skywell Magic TwinPower
-	0004  Voodoo Banshee
+	0004  Voodoo Banshee [Velocity 100]
 	0005  Voodoo 3
 		121a 0004  Voodoo3 AGP
 		121a 0030  Voodoo3 AGP
@@ -3014,6 +3032,7 @@
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
 	0001  AceNIC Gigabit Ethernet
+		1410 0104  Gigabit Ethernet-SX PCI Adapter (14100401)
 12af  TDK USA Corp
 12b0  Jorge Scientific Corp
 12b1  GammaLink
@@ -3962,6 +3981,25 @@
 156f  M-Systems Flash Disk Pioneers Ltd
 1570  Lecroy Corp
 1571  Contemporary Controls
+	a001  CCSI PCI20-485 ARCnet
+	a002  CCSI PCI20-485D ARCnet
+	a003  CCSI PCI20-485X ARCnet
+	a004  CCSI PCI20-CXB ARCnet
+	a005  CCSI PCI20-CXS ARCnet
+	a006  CCSI PCI20-FOG-SMA ARCnet
+	a007  CCSI PCI20-FOG-ST ARCnet
+	a008  CCSI PCI20-TB5 ARCnet
+	a009  CCSI PCI20-5-485 5Mbit ARCnet
+	a00a  CCSI PCI20-5-485D 5Mbit ARCnet
+	a00b  CCSI PCI20-5-485X 5Mbit ARCnet
+	a00c  CCSI PCI20-5-FOG-ST 5Mbit ARCnet
+	a00d  CCSI PCI20-5-FOG-SMA 5Mbit ARCnet
+	a201  CCSI PCI22-485 10Mbit ARCnet
+	a202  CCSI PCI22-485D 10Mbit ARCnet
+	a203  CCSI PCI22-485X 10Mbit ARCnet
+	a204  CCSI PCI22-CHB 10Mbit ARCnet
+	a205  CCSI PCI22-FOG_ST 10Mbit ARCnet
+	a206  CCSI PCI22-THB 10Mbit ARCnet
 1572  Otis Elevator Company
 1573  Lattice - Vantis
 1574  Fairchild Semiconductor
@@ -4203,6 +4241,8 @@
 45fb  Baldor Electric Company
 4680  Umax Computer Corp
 4843  Hercules Computer Technology Inc
+4916  RedCreek Communications Inc
+	1960  RedCreek PCI adapter
 4943  Growth Networks
 4978  Axil Computer Inc
 4a14  NetVin
@@ -4728,6 +4768,7 @@
 	01  Token ring network controller
 	02  FDDI network controller
 	03  ATM network controller
+	04  ISDN controller
 	80  Network controller
 C 03  Display controller
 	00  VGA compatible controller
@@ -4759,6 +4800,10 @@
 	08  RACEway bridge
 		00  Transparent mode
 		01  Endpoint mode
+	09  Semi-transparent PCI-to-PCI bridge
+		40  Primary bus towards host CPU
+		80  Secondary bus towards host CPU
+	0a  InfiniBand to PCI host bridge
 	80  Bridge
 C 07  Communication controller
 	00  Serial controller
@@ -4836,6 +4881,7 @@
 		Fe  USB Device
 	04  Fiber Channel
 	05  SMBus
+	06  InfiniBand
 C 0d  Wireless controller
 	00  IRDA controller
 	01  Consumer IR controller
@@ -4850,8 +4896,10 @@
 	04  Satellite data communication controller
 C 10  Encryption controller
 	00  Network and computing encryption device
-	01  Entertainment encryption device
+	10  Entertainment encryption device
 	80  Encryption controller
 C 11  Signal processing controller
 	00  DPIO module
+	01  Performance counters
+	10  Communication synchronizer
 	80  Signal processing controller
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.3.99-pre6/linux/drivers/pci/proc.c	Sat Feb 26 22:31:47 2000
+++ linux/drivers/pci/proc.c	Sat Apr 29 10:19:57 2000
@@ -389,7 +389,7 @@
 
 	*eof = 1;
 	pci_for_each_dev(dev) {
-		nprinted = sprint_dev_config(dev, buf + len, count - len);
+		nprinted = sprint_dev_config(dev, buf + len, PAGE_SIZE - len);
 		if (nprinted < 0) {
 			*eof = 0;
 			break;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.3.99-pre6/linux/drivers/pci/quirks.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/pci/quirks.c	Wed May  3 09:06:37 2000
@@ -164,6 +164,23 @@
 }
 
 /*
+ * VIA ACPI: One IO region pointed to by longword at
+ *	0x48 or 0x20 (256 bytes of ACPI registers)
+ */
+static void __init quirk_via_acpi(struct pci_dev *dev)
+{
+	u8 rev;
+	u32 region;
+
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
+	if (rev & 0x10) {
+		pci_read_config_dword(dev, 0x48, &region);
+		region &= PCI_BASE_ADDRESS_IO_MASK;
+		quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES);
+	}
+}
+
+/*
  *  The main table of quirks.
  */
 
@@ -192,6 +209,8 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_via_acpi },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	quirk_piix4acpi },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101 },
 	{ 0 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- v2.3.99-pre6/linux/drivers/pcmcia/bulkmem.c	Thu Feb 10 17:11:12 2000
+++ linux/drivers/pcmcia/bulkmem.c	Tue May  2 17:37:22 2000
@@ -231,7 +231,7 @@
 	    busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
 	    busy->erase = erase;
 	    busy->client = handle;
-	    busy->timeout.prev = busy->timeout.next = NULL;
+	    init_timer(&busy->timeout);
 	    busy->timeout.data = (u_long)busy;
 	    busy->timeout.function = &handle_erase_timeout;
 	    busy->prev = busy->next = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.3.99-pre6/linux/drivers/pcmcia/cardbus.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/pcmcia/cardbus.c	Wed May  3 01:45:18 2000
@@ -305,7 +305,7 @@
 			if (res->flags)
 				pci_assign_resource(dev, r);
 		}
-		pci_enable_device(dev);
+		pci_enable_device(dev); /* XXX check return */
 
 		/* Does this function have an interrupt at all? */
 		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.99-pre6/linux/drivers/pcmcia/cs.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/pcmcia/cs.c	Mon May  8 21:26:05 2000
@@ -45,7 +45,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
-#include <linux/compile.h>
+#include <linux/pm.h>
 #include <linux/pci.h>
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -62,9 +62,6 @@
 #include "cs_internal.h"
 #include "rsrc_mgr.h"
 
-#include <linux/pm.h>
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
-
 #ifdef PCMCIA_DEBUG
 int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
@@ -83,20 +80,17 @@
 #define CB_OPT ""
 #endif
 #ifdef CONFIG_PM
-#define APM_OPT " [pm]"
+#define PM_OPT " [pm]"
 #else
-#define APM_OPT ""
+#define PM_OPT ""
 #endif
 #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM)
 #define OPTIONS " none"
 #else
-#define OPTIONS PCI_OPT CB_OPT APM_OPT
+#define OPTIONS PCI_OPT CB_OPT PM_OPT
 #endif
 
 static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
-#ifdef MODULE
-static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION;
-#endif
 static const char *options = "options: " OPTIONS;
 
 MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
@@ -107,40 +101,30 @@
 
 /* Parameters that can be set with 'insmod' */
 
-static int setup_delay		= HZ/20;	/* ticks */
-static int resume_delay		= HZ/5;		/* ticks */
-static int shutdown_delay	= HZ/40;	/* ticks */
-static int vcc_settle		= HZ*4/10;	/* ticks */
-static int reset_time		= 10;		/* usecs */
-static int unreset_delay	= HZ/10;	/* ticks */
-static int unreset_check	= HZ/10;	/* ticks */
-static int unreset_limit	= 30;		/* unreset_check's */
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+INT_MODULE_PARM(setup_delay,	HZ/20);		/* ticks */
+INT_MODULE_PARM(resume_delay,	HZ/5);		/* ticks */
+INT_MODULE_PARM(shutdown_delay,	HZ/40);		/* ticks */
+INT_MODULE_PARM(vcc_settle,	HZ*4/10);	/* ticks */
+INT_MODULE_PARM(reset_time,	10);		/* usecs */
+INT_MODULE_PARM(unreset_delay,	HZ/10);		/* ticks */
+INT_MODULE_PARM(unreset_check,	HZ/10);		/* ticks */
+INT_MODULE_PARM(unreset_limit,	30);		/* unreset_check's */
 
 /* Access speed for attribute memory windows */
-static int cis_speed		= 300;	/* ns */
+INT_MODULE_PARM(cis_speed,	300);		/* ns */
 
 /* Access speed for IO windows */
-static int io_speed		= 0;	/* ns */
+INT_MODULE_PARM(io_speed,	0);		/* ns */
 
 /* Optional features */
 #ifdef CONFIG_PM
-static int do_apm		= 1;
-MODULE_PARM(do_apm, "i");
+INT_MODULE_PARM(do_apm,		1);
 #else
-static int do_apm		= 0;
+INT_MODULE_PARM(do_apm,		0);
 #endif
 
-MODULE_PARM(setup_delay, "i");
-MODULE_PARM(resume_delay, "i");
-MODULE_PARM(shutdown_delay, "i");
-MODULE_PARM(vcc_settle, "i");
-MODULE_PARM(reset_time, "i");
-MODULE_PARM(unreset_delay, "i");
-MODULE_PARM(unreset_check, "i");
-MODULE_PARM(unreset_limit, "i");
-MODULE_PARM(cis_speed, "i");
-MODULE_PARM(io_speed, "i");
-
 /*====================================================================*/
 
 socket_state_t dead_socket = {
@@ -340,7 +324,6 @@
 	s->sock = ns;
 	s->setup.data = sockets;
 	s->setup.function = &setup_socket;
-	s->setup_timeout = 0;
 	s->shutdown.data = sockets;
 	s->shutdown.function = &shutdown_socket;
 	/* base address = 0, map = 0 */
@@ -361,10 +344,13 @@
 	    char name[3];
 	    sprintf(name, "%02d", i);
 	    s->proc = proc_mkdir(name, proc_pccard);
+	    if (s->proc)
+		ss_entry->proc_setup(ns, s->proc);
 #ifdef PCMCIA_DEBUG
-	    create_proc_read_entry("clients",0,s->proc,proc_read_clients,s);
+	    if (s->proc)
+		create_proc_read_entry("clients", 0, s->proc,
+				       proc_read_clients, s);
 #endif
-	    ss_entry->proc_setup(ns, s->proc);
 	}
 #endif
     }
@@ -390,6 +376,7 @@
 #ifdef PCMCIA_DEBUG
 	    remove_proc_entry("clients", s->proc);
 #endif
+	    remove_proc_entry(name, proc_pccard);
 	}
     }
 #endif
@@ -659,6 +646,7 @@
 	    }
 	    s->state |= SOCKET_SETUP_PENDING;
 	    s->setup.function = &setup_socket;
+	    s->setup_timeout = 0;
 	    if (s->state & SOCKET_SUSPEND)
 		s->setup.expires = jiffies + resume_delay;
 	    else
@@ -2346,9 +2334,6 @@
 static int __init init_pcmcia_cs(void)
 {
     printk(KERN_INFO "%s\n", release);
-#ifdef MODULE
-    printk(KERN_INFO "  %s\n", kernel);
-#endif
     printk(KERN_INFO "  %s\n", options);
     DEBUG(0, "%s\n", version);
     if (do_apm)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.3.99-pre6/linux/drivers/pcmcia/ds.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/pcmcia/ds.c	Tue May  2 17:36:53 2000
@@ -897,7 +897,7 @@
 	init_waitqueue_head(&s->queue);
 	init_waitqueue_head(&s->request);
 	s->handle = NULL;
-	s->removal.prev = s->removal.next = NULL;
+	init_timer(&s->removal);
 	s->removal.data = i;
 	s->removal.function = &handle_removal;
 	s->bind = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.3.99-pre6/linux/drivers/pcmcia/i82365.c	Fri Mar 10 16:40:43 2000
+++ linux/drivers/pcmcia/i82365.c	Wed May  3 01:45:17 2000
@@ -1518,7 +1518,7 @@
     if (poll_interval != 0) {
 	poll_timer.function = pcic_interrupt_wrapper;
 	poll_timer.data = 0;
-	poll_timer.prev = poll_timer.next = NULL;
+	init_timer(&poll_timer);
     	poll_timer.expires = jiffies + poll_interval;
 	add_timer(&poll_timer);
     }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- v2.3.99-pre6/linux/drivers/pcmcia/tcic.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/pcmcia/tcic.c	Tue May  2 17:38:58 2000
@@ -450,7 +450,7 @@
     /* Set up polling */
     poll_timer.function = &tcic_timer;
     poll_timer.data = 0;
-    poll_timer.prev = poll_timer.next = NULL;
+    init_timer(&poll_timer);
 
     /* Build interrupt mask */
     printk(", %d sockets\n" KERN_INFO "  irq list (", sockets);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.3.99-pre6/linux/drivers/pcmcia/yenta.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/pcmcia/yenta.c	Wed May  3 01:45:19 2000
@@ -786,10 +786,8 @@
 	/*
 	 * Do some basic sanity checking..
 	 */
-	if (pci_enable_device(dev)) {
-		printk("Unable to enable device\n");
+	if (pci_enable_device(dev))
 		return -1;
-	}
 	if (!dev->resource[0].start) {
 		printk("No cardbus resource!\n");
 		return -1;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.99-pre6/linux/drivers/sbus/char/pcikbd.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sbus/char/pcikbd.c	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.45 2000/04/24 06:10:19 davem Exp $
+/* $Id: pcikbd.c,v 1.46 2000/05/03 06:37:05 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -425,8 +425,7 @@
 static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks)
 {
 	unsigned long flags;
-	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
-						 pcikbd_kd_nosound };
+	static struct timer_list sound_timer = { function: pcikbd_kd_nosound };
 
 	save_flags(flags); cli();
 	del_timer(&sound_timer);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.3.99-pre6/linux/drivers/sbus/char/sab82532.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sbus/char/sab82532.c	Mon May  8 22:21:57 2000
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.44 2000/04/26 09:36:32 davem Exp $
+/* $Id: sab82532.c,v 1.45 2000/05/08 22:23:08 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -352,6 +352,11 @@
 		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) {
 		sab82532_cec_wait(info);
@@ -360,13 +365,6 @@
 		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) {
 #if 1
 		printk("sab82532: receive_chars: RFO");
@@ -835,8 +833,8 @@
 				SAB82532_IMR0_PLLA;
 	writeb(info->interrupt_mask0, &info->regs->w.imr0);
 	info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF |
-				SAB82532_IMR1_TIN | SAB82532_IMR1_XON |
-				SAB82532_IMR1_XPR;
+				SAB82532_IMR1_TIN | SAB82532_IMR1_CSC |
+				SAB82532_IMR1_XON | SAB82532_IMR1_XPR;
 	writeb(info->interrupt_mask1, &info->regs->w.imr1);
 
 	if (info->tty)
@@ -1056,10 +1054,14 @@
 		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode);
 		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);
 		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode);
+		info->interrupt_mask1 &= ~(SAB82532_IMR1_CSC);
+		writeb(info->interrupt_mask1, &info->regs->w.imr1);
 	} else {
 		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);
 		writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);
 		writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode);
+		info->interrupt_mask1 |= SAB82532_IMR1_CSC;
+		writeb(info->interrupt_mask1, &info->regs->w.imr1);
 	}
 	writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode);
 	restore_flags(flags);
@@ -2171,7 +2173,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.44 $";
+	char *revision = "$Revision: 1.45 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.3.99-pre6/linux/drivers/sbus/char/sunkbd.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sbus/char/sunkbd.c	Wed May  3 01:47:57 2000
@@ -438,7 +438,7 @@
 static void keyboard_timer (unsigned long ignored);
 
 static struct timer_list
-auto_repeat_timer = { NULL, NULL, 0, 0, keyboard_timer };
+auto_repeat_timer = { function: keyboard_timer };
 
 /* Keeps track of the last pressed key */
 static unsigned char last_keycode;
@@ -1219,8 +1219,7 @@
 static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks)
 {
 	unsigned long flags;
-	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
-						 sunkbd_kd_nosound };
+	static struct timer_list sound_timer = { function: sunkbd_kd_nosound };
 
 	spin_lock_irqsave(&sunkbd_lock, flags);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.3.99-pre6/linux/drivers/sbus/char/sunmouse.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sbus/char/sunmouse.c	Wed May  3 01:47:57 2000
@@ -563,13 +563,13 @@
 		/* This is a buggy application doing termios on the mouse driver */
 		/* we ignore it.  I keep this check here so that we will notice   */
 		/* future mouse vuid ioctls */
-		break;
+		return -ENOTTY;
 		
 	default:
 #ifdef DEBUG
 		printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
 #endif
-		return -1;
+		return -EINVAL;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c
--- v2.3.99-pre6/linux/drivers/sbus/char/vfc_i2c.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/sbus/char/vfc_i2c.c	Fri May  5 12:37:52 2000
@@ -88,8 +88,7 @@
 
 void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) 
 {
-	dev->poll_timer.next = NULL;
-	dev->poll_timer.prev = NULL;
+	init_timer(&dev->poll_timer);
 	dev->poll_timer.expires = jiffies + 
 		((unsigned long)usecs*(HZ))/1000000;
 	dev->poll_timer.data=(unsigned long)dev;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.3.99-pre6/linux/drivers/scsi/NCR5380.c	Fri Sep 10 23:57:31 1999
+++ linux/drivers/scsi/NCR5380.c	Wed May 10 16:56:42 2000
@@ -563,14 +563,10 @@
 
 static __inline__ void run_main(void)
 {
-	unsigned long flags;
-	save_flags(flags);
-	cli();
 	if (!main_running) {
 		main_running = 1;
 		NCR5380_main();
 	}
-	restore_flags(flags);
 }
 
 #ifdef USLEEP
@@ -667,9 +663,7 @@
 	((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp;
 	*prev = instance;
    
-	del_timer(&usleep_timer);
-	usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires;
-	add_timer(&usleep_timer);
+	mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires);
 	restore_flags(flags);
 	return 0;
 }
@@ -1226,7 +1220,6 @@
 	 * sense data is only guaranteed to be valid while the condition exists.
 	 */
 
-	cli();
 	if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
 		LIST(cmd, hostdata->issue_queue);
 		cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.3.99-pre6/linux/drivers/scsi/aha152x.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/aha152x.c	Fri Apr 28 12:16:20 2000
@@ -676,8 +676,10 @@
 {
 	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
 		/* Adaptec 152x */
-	{ "Adaptec AHA-1520B",		0x000b, 19 },
+	{ "Adaptec AHA-1520B",		0x000b, 17 },
 		/* Adaptec 152x rev B */
+	{ "Adaptec AHA-1520B",		0x0026, 17 },
+		/* Iomega Jaz Jet ISA (AIC6370Q) */
 	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
 		/* on-board controller */
 	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.99-pre6/linux/drivers/scsi/aic7xxx.c	Fri Mar 10 16:40:43 2000
+++ linux/drivers/scsi/aic7xxx.c	Fri Apr 28 22:50:14 2000
@@ -3585,9 +3585,7 @@
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
       {
-        del_timer(&p->dev_timer);
-        p->dev_timer.expires = p->dev_expires[i];
-        add_timer(&p->dev_timer);
+        mod_timer(&p->dev_timer, p->dev_expires[i]);
         p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
     }
@@ -5045,11 +5043,7 @@
                 }
                 else if ( time_after_eq(p->dev_timer.expires,
                                         p->dev_expires[tindex]) )
-                {
-                  del_timer(&p->dev_timer);
-                  p->dev_timer.expires = p->dev_expires[tindex];
-                  add_timer(&p->dev_timer);
-                }
+                  mod_timer(&p->dev_timer, p->dev_expires[tindex]);
               }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
               if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
@@ -12058,9 +12052,7 @@
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
       {
-        del_timer(&p->dev_timer);
-        p->dev_timer.expires = p->dev_expires[p->scsi_id];
-        add_timer(&p->dev_timer);
+        mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
         p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.3.99-pre6/linux/drivers/scsi/ini9100u.c	Tue Nov 23 22:42:21 1999
+++ linux/drivers/scsi/ini9100u.c	Wed May 10 16:56:43 2000
@@ -403,28 +403,28 @@
 		/* Initial tulip chip           */
 		switch (i) {
 		case 0:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr0, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr0, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 1:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr1, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr1, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 2:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr2, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr2, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 3:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr3, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr3, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 4:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr4, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr4, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 5:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr5, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr5, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 6:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr6, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr6, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		case 7:
-			ok = request_irq(pHCB->HCS_Intr, i91u_intr7, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+			ok = request_irq(pHCB->HCS_Intr, i91u_intr7, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
 			break;
 		default:
 			i91u_panic("i91u: Too many host adapters\n");
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- v2.3.99-pre6/linux/drivers/scsi/pcmcia/aha152x_stub.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	Mon May  8 21:26:05 2000
@@ -5,7 +5,7 @@
     This driver supports the Adaptec AHA-1460, the New Media Bus
     Toaster, and the New Media Toast & Jam.
     
-    aha152x_cs.c 1.52 2000/01/11 01:04:31
+    aha152x_cs.c 1.53 2000/05/04 01:30:00
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -62,7 +62,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"aha152x_cs.c 1.52 2000/01/11 01:04:31 (David Hinds)";
+"aha152x_cs.c 1.53 2000/05/04 01:30:00 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -194,6 +194,7 @@
     if (*linkp == NULL)
 	return;
 
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	aha152x_release_cs((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -379,10 +380,8 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    link->release.expires = jiffies + HZ/20;
-	    add_timer(&link->release);
-	}
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- v2.3.99-pre6/linux/drivers/scsi/pcmcia/fdomain_stub.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	Mon May  8 21:26:05 2000
@@ -2,7 +2,7 @@
 
     A driver for Future Domain-compatible PCMCIA SCSI cards
 
-    fdomain_cs.c 1.41 1999/11/15 06:05:48
+    fdomain_cs.c 1.42 2000/05/04 01:30:00
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -59,7 +59,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"fdomain_cs.c 1.41 1999/11/15 06:05:48 (David Hinds)";
+"fdomain_cs.c 1.42 2000/05/04 01:30:00 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -176,6 +176,7 @@
     if (*linkp == NULL)
 	return;
 
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	fdomain_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -343,10 +344,8 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    link->release.expires = jiffies + HZ/20;
-	    add_timer(&link->release);
-	}
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- v2.3.99-pre6/linux/drivers/scsi/pcmcia/qlogic_stub.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	Mon May  8 21:26:05 2000
@@ -2,7 +2,7 @@
 
     A driver for the Qlogic SCSI card
 
-    qlogic_cs.c 1.77 2000/02/01 19:08:09
+    qlogic_cs.c 1.78 2000/05/04 01:30:00
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -66,7 +66,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"qlogic_cs.c 1.77 2000/02/01 19:08:09 (David Hinds)";
+"qlogic_cs.c 1.78 2000/05/04 01:30:00 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -182,6 +182,7 @@
     if (*linkp == NULL)
 	return;
 
+    del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	qlogic_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -365,10 +366,8 @@
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    link->release.expires = jiffies + HZ/20;
-	    add_timer(&link->release);
-	}
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
 	break;
     case CS_EVENT_CARD_INSERTION:
 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c
--- v2.3.99-pre6/linux/drivers/scsi/pluto.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/pluto.c	Wed May  3 01:47:58 2000
@@ -48,7 +48,7 @@
 } *fcs __initdata = { 0 };
 static int fcscount __initdata = 0;
 static atomic_t fcss __initdata = ATOMIC_INIT(0);
-static struct timer_list fc_timer __initdata = { 0 };
+static struct timer_list fc_timer __initdata = { function: NULL };
 DECLARE_MUTEX_LOCKED(fc_sem);
 
 static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.99-pre6/linux/drivers/scsi/scsi.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/scsi/scsi.c	Mon May  8 15:52:43 2000
@@ -447,8 +447,10 @@
                          * to the user.
                          */
                         if( interruptable ) {
-                                if (signal_pending(current))
+                                if (signal_pending(current)) {
+                                        spin_unlock_irqrestore(&device_request_lock, flags);
                                         return NULL;
+                                }
                         }
 		} else {
                         spin_unlock_irqrestore(&device_request_lock, flags);
@@ -1417,7 +1419,11 @@
 	spin_lock_irqsave(&device_request_lock, flags);
 
 	if (SDpnt->queue_depth == 0)
+	{
 		SDpnt->queue_depth = host->cmd_per_lun;
+		if (SDpnt->queue_depth == 0)
+			SDpnt->queue_depth = 1; /* live to fight another day */
+	}
 	SDpnt->device_queue = NULL;
 
 	for (j = 0; j < SDpnt->queue_depth; j++) {
@@ -1809,8 +1815,8 @@
 		/* FIXME (DB) This assumes that the queue_depth routines can be used
 		   in this context as well, while they were all designed to be
 		   called only once after the detect routine. (DB) */
-		if (HBA_ptr->select_queue_depths != NULL)
-			(HBA_ptr->select_queue_depths) (HBA_ptr, HBA_ptr->host_queue);
+		/* queue_depth routine moved to inside scan_scsis(,1,,,) so
+		   it is called before build_commandblocks() */
 
 		err = length;
 		goto out;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.3.99-pre6/linux/drivers/scsi/scsi_scan.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/scsi/scsi_scan.c	Wed May 10 18:17:48 2000
@@ -347,6 +347,12 @@
 		if (SDpnt != oldSDpnt) {
 
 			/* it could happen the blockdevice hasn't yet been inited */
+			/* queue_depth() moved from scsi_proc_info() so that
+			   it is called before scsi_build_commandblocks() */
+			if (shpnt->select_queue_depths != NULL)
+				(shpnt->select_queue_depths)(shpnt,
+							     shpnt->host_queue);
+
 			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 				if (sdtpnt->init && sdtpnt->dev_noticed)
 					(*sdtpnt->init) ();
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.99-pre6/linux/drivers/sound/Config.in	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/Config.in	Thu May 11 13:45:35 2000
@@ -79,6 +79,8 @@
    int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128
 fi
 
+tristate '  VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX
+
 dep_tristate '  OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
 
 if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
@@ -144,7 +146,6 @@
       fi
    fi
 
-   dep_tristate '    VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS
    dep_tristate '    Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
    dep_tristate '    Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
    dep_tristate '    Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.99-pre6/linux/drivers/sound/Makefile	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/Makefile	Thu May 11 13:45:35 2000
@@ -66,12 +66,12 @@
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
 
-obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o sb_lib.o uart401.o ac97.o
+obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 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_ICH)		+= i810_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 obj-$(CONFIG_SOUND_CMPCI)	+= cmpci.o
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- v2.3.99-pre6/linux/drivers/sound/ac97_codec.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/sound/ac97_codec.c	Wed May 10 16:56:43 2000
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/bitops.h>
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/awacs_defs.h linux/drivers/sound/awacs_defs.h
--- v2.3.99-pre6/linux/drivers/sound/awacs_defs.h	Mon Jul 12 16:21:25 1999
+++ linux/drivers/sound/awacs_defs.h	Wed Dec 31 16:00:00 1969
@@ -1,224 +0,0 @@
-/*********************************************************/
-/* This file was written by someone, somewhere, sometime */
-/* And is released into the Public Domain                */
-/*********************************************************/
-
-#ifndef _AWACS_DEFS_H_
-#define _AWACS_DEFS_H_
-
-/*******************************/
-/* AWACs Audio Register Layout */
-/*******************************/
-
-struct awacs_regs {
-    unsigned	control;	/* Audio control register */
-    unsigned	pad0[3];
-    unsigned	codec_ctrl;	/* Codec control register */
-    unsigned	pad1[3];
-    unsigned	codec_stat;	/* Codec status register */
-    unsigned	pad2[3];
-    unsigned	clip_count;	/* Clipping count register */
-    unsigned	pad3[3];
-    unsigned	byteswap;	/* Data is little-endian if 1 */
-};
-
-/*******************/
-/* Audio Bit Masks */
-/*******************/
-
-/* Audio Control Reg Bit Masks */
-/* ----- ------- --- --- ----- */
-#define MASK_ISFSEL	(0xf)		/* Input SubFrame Select */
-#define MASK_OSFSEL	(0xf << 4)	/* Output SubFrame Select */
-#define MASK_RATE	(0x7 << 8)	/* Sound Rate */
-#define MASK_CNTLERR	(0x1 << 11)	/* Error */
-#define MASK_PORTCHG	(0x1 << 12)	/* Port Change */
-#define MASK_IEE	(0x1 << 13)	/* Enable Interrupt on Error */
-#define MASK_IEPC	(0x1 << 14)	/* Enable Interrupt on Port Change */
-#define MASK_SSFSEL	(0x3 << 15)	/* Status SubFrame Select */
-
-/* Audio Codec Control Reg Bit Masks */
-/* ----- ----- ------- --- --- ----- */
-#define MASK_NEWECMD	(0x1 << 24)	/* Lock: don't write to reg when 1 */
-#define MASK_EMODESEL	(0x3 << 22)	/* Send info out on which frame? */
-#define MASK_EXMODEADDR	(0x3ff << 12)	/* Extended Mode Address -- 10 bits */
-#define MASK_EXMODEDATA	(0xfff)		/* Extended Mode Data -- 12 bits */
-
-/* Audio Codec Control Address Values / Masks */
-/* ----- ----- ------- ------- ------ - ----- */
-#define MASK_ADDR0	(0x0 << 12)	/* Expanded Data Mode Address 0 */
-#define MASK_ADDR_MUX	MASK_ADDR0	/* Mux Control */
-#define MASK_ADDR_GAIN	MASK_ADDR0
-
-#define MASK_ADDR1	(0x1 << 12)	/* Expanded Data Mode Address 1 */
-#define MASK_ADDR_MUTE	MASK_ADDR1
-#define MASK_ADDR_RATE	MASK_ADDR1
-
-#define MASK_ADDR2	(0x2 << 12)	/* Expanded Data Mode Address 2 */
-#define MASK_ADDR_VOLA	MASK_ADDR2	/* Volume Control A -- Headphones */
-#define MASK_ADDR_VOLHD MASK_ADDR2
-
-#define MASK_ADDR4	(0x4 << 12)	/* Expanded Data Mode Address 4 */
-#define MASK_ADDR_VOLC	MASK_ADDR4	/* Volume Control C -- Speaker */
-#define MASK_ADDR_VOLSPK MASK_ADDR4
-
-/* Address 0 Bit Masks & Macros */
-/* ------- - --- ----- - ------ */
-#define MASK_GAINRIGHT	(0xf)		/* Gain Right Mask */
-#define MASK_GAINLEFT	(0xf << 4)	/* Gain Left Mask */
-#define MASK_GAINLINE	(0x1 << 8)	/* Change Gain for Line??? */
-#define MASK_GAINMIC	(0x0 << 8)	/* Change Gain for Mic??? */
-
-#define MASK_MUX_CD	(0x1 << 9)	/* Select CD in MUX */
-#define MASK_MUX_AUDIN	(0x1 << 10)	/* Select Audio In in MUX */
-#define MASK_MUX_MIC	(0x1 << 11)	/* Select Mic in MUX */
-#define MASK_MUX_LINE	MASK_MUX_AUDIN
-
-#define GAINRIGHT(x)	((x) & MASK_GAINRIGHT)
-#define GAINLEFT(x)	(((x) << 4) & MASK_GAINLEFT)
-
-/* Address 1 Bit Masks */
-/* ------- - --- ----- */
-#define MASK_ADDR1RES1	(0x3)		/* Reserved */
-#define MASK_RECALIBRATE (0x1 << 2)	/* Recalibrate */
-#define MASK_SAMPLERATE	(0x7 << 3)	/* Sample Rate: */
-#define MASK_LOOPTHRU	(0x1 << 6)	/* Loopthrough Enable */
-#define MASK_CMUTE	(0x1 << 7)	/* Output C (Speaker) Mute when 1 */
-#define MASK_SPKMUTE	MASK_CMUTE
-#define MASK_ADDR1RES2	(0x1 << 8)	/* Reserved */
-#define MASK_AMUTE	(0x1 << 9)	/* Output A (Headphone) Mute when 1 */
-#define MASK_HDMUTE	MASK_AMUTE
-#define MASK_PAROUT	(0x3 << 10)	/* Parallel Out (???) */
-
-#define SAMPLERATE_48000	(0x0 << 3)	/* 48 or 44.1 kHz */
-#define SAMPLERATE_32000	(0x1 << 3)	/* 32 or 29.4 kHz */
-#define SAMPLERATE_24000	(0x2 << 3)	/* 24 or 22.05 kHz */
-#define SAMPLERATE_19200	(0x3 << 3)	/* 19.2 or 17.64 kHz */
-#define SAMPLERATE_16000	(0x4 << 3)	/* 16 or 14.7 kHz */
-#define SAMPLERATE_12000	(0x5 << 3)	/* 12 or 11.025 kHz */
-#define SAMPLERATE_9600		(0x6 << 3)	/* 9.6 or 8.82 kHz */
-#define SAMPLERATE_8000		(0x7 << 3)	/* 8 or 7.35 kHz */
-
-/* Address 2 & 4 Bit Masks & Macros */
-/* ------- - - - --- ----- - ------ */
-#define MASK_OUTVOLRIGHT (0xf)		/* Output Right Volume */
-#define MASK_ADDR2RES1	(0x2 << 4)	/* Reserved */
-#define MASK_ADDR4RES1	MASK_ADDR2RES1
-#define MASK_OUTVOLLEFT	(0xf << 6)	/* Output Left Volume */
-#define MASK_ADDR2RES2	(0x2 << 10)	/* Reserved */
-#define MASK_ADDR4RES2	MASK_ADDR2RES2
-
-#define VOLRIGHT(x)	(((~(x)) & MASK_OUTVOLRIGHT))
-#define VOLLEFT(x)	(((~(x)) << 6) & MASK_OUTVOLLEFT)
-
-/* Audio Codec Status Reg Bit Masks */
-/* ----- ----- ------ --- --- ----- */
-#define MASK_EXTEND	(0x1 << 23)	/* Extend */
-#define MASK_VALID	(0x1 << 22)	/* Valid Data? */
-#define MASK_OFLEFT	(0x1 << 21)	/* Overflow Left */
-#define MASK_OFRIGHT	(0x1 << 20)	/* Overflow Right */
-#define MASK_ERRCODE	(0xf << 16)	/* Error Code */
-#define MASK_REVISION	(0xf << 12)	/* Revision Number */
-#define MASK_MFGID	(0xf << 8)	/* Mfg. ID */
-#define MASK_CODSTATRES	(0xf << 4)	/* bits 4 - 7 reserved */
-#define MASK_INPPORT	(0xf)		/* Input Port */
-#define MASK_HDPCONN	8		/* headphone plugged in */
-
-/* Clipping Count Reg Bit Masks */
-/* -------- ----- --- --- ----- */
-#define MASK_CLIPLEFT	(0xff << 7)	/* Clipping Count, Left Channel */
-#define MASK_CLIPRIGHT	(0xff)		/* Clipping Count, Right Channel */
-
-/* DBDMA ChannelStatus Bit Masks */
-/* ----- ------------- --- ----- */
-#define MASK_CSERR	(0x1 << 7)	/* Error */
-#define MASK_EOI	(0x1 << 6)	/* End of Input -- only for Input Channel */
-#define MASK_CSUNUSED	(0x1f << 1)	/* bits 1-5 not used */
-#define MASK_WAIT	(0x1)		/* Wait */
-
-/* Various Rates */
-/* ------- ----- */
-#define RATE_48000	(0x0 << 8)	/* 48 kHz */
-#define RATE_44100	(0x0 << 8)	/* 44.1 kHz */
-#define RATE_32000	(0x1 << 8)	/* 32 kHz */
-#define RATE_29400	(0x1 << 8)	/* 29.4 kHz */
-#define RATE_24000	(0x2 << 8)	/* 24 kHz */
-#define RATE_22050	(0x2 << 8)	/* 22.05 kHz */
-#define RATE_19200	(0x3 << 8)	/* 19.2 kHz */
-#define RATE_17640	(0x3 << 8)	/* 17.64 kHz */
-#define RATE_16000	(0x4 << 8)	/* 16 kHz */
-#define RATE_14700	(0x4 << 8)	/* 14.7 kHz */
-#define RATE_12000	(0x5 << 8)	/* 12 kHz */
-#define RATE_11025	(0x5 << 8)	/* 11.025 kHz */
-#define RATE_9600	(0x6 << 8)	/* 9.6 kHz */
-#define RATE_8820	(0x6 << 8)	/* 8.82 kHz */
-#define RATE_8000	(0x7 << 8)	/* 8 kHz */
-#define RATE_7350	(0x7 << 8)	/* 7.35 kHz */
-
-#define RATE_LOW	1	/* HIGH = 48kHz, etc;  LOW = 44.1kHz, etc. */
-
-
-/* Burgundy values */
-
-#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
-#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
-
-#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12)
-
-#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
-
-#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
-#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
-
-#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
-
-#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12)
-
-#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
-#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
-#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
-
-#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
-#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
-#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3)
-#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
-
-#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1)
-#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2)
-#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3)
-#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
-
-
-/* These are all default values for the burgundy */
-#define DEF_BURGUNDY_INPSEL21 (0xAA)
-#define DEF_BURGUNDY_INPSEL3 (0x0A)
-
-#define DEF_BURGUNDY_GAINCD (0x33)
-#define DEF_BURGUNDY_GAINLINE (0x44)
-#define DEF_BURGUNDY_GAINMIC (0x44)
-#define DEF_BURGUNDY_GAINMODEM (0x06)
-
-/* Remember: lowest volume here is 0x9b */
-#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
-#define DEF_BURGUNDY_VOLLINE (0x00000000)
-#define DEF_BURGUNDY_VOLMIC (0x00000000)
-#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
-
-#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f)
-#define DEF_BURGUNDY_OUTPUTENABLES (0x0A)
-
-#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF)
-
-#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E)
-
-#define DEF_BURGUNDY_ATTENSPEAKER (0x44)
-#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
-#define DEF_BURGUNDY_ATTENHP (0xCC)
-
-#endif /* _AWACS_DEFS_H_ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/dmasound/awacs_defs.h linux/drivers/sound/dmasound/awacs_defs.h
--- v2.3.99-pre6/linux/drivers/sound/dmasound/awacs_defs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/awacs_defs.h	Mon Jul 12 16:21:25 1999
@@ -0,0 +1,224 @@
+/*********************************************************/
+/* This file was written by someone, somewhere, sometime */
+/* And is released into the Public Domain                */
+/*********************************************************/
+
+#ifndef _AWACS_DEFS_H_
+#define _AWACS_DEFS_H_
+
+/*******************************/
+/* AWACs Audio Register Layout */
+/*******************************/
+
+struct awacs_regs {
+    unsigned	control;	/* Audio control register */
+    unsigned	pad0[3];
+    unsigned	codec_ctrl;	/* Codec control register */
+    unsigned	pad1[3];
+    unsigned	codec_stat;	/* Codec status register */
+    unsigned	pad2[3];
+    unsigned	clip_count;	/* Clipping count register */
+    unsigned	pad3[3];
+    unsigned	byteswap;	/* Data is little-endian if 1 */
+};
+
+/*******************/
+/* Audio Bit Masks */
+/*******************/
+
+/* Audio Control Reg Bit Masks */
+/* ----- ------- --- --- ----- */
+#define MASK_ISFSEL	(0xf)		/* Input SubFrame Select */
+#define MASK_OSFSEL	(0xf << 4)	/* Output SubFrame Select */
+#define MASK_RATE	(0x7 << 8)	/* Sound Rate */
+#define MASK_CNTLERR	(0x1 << 11)	/* Error */
+#define MASK_PORTCHG	(0x1 << 12)	/* Port Change */
+#define MASK_IEE	(0x1 << 13)	/* Enable Interrupt on Error */
+#define MASK_IEPC	(0x1 << 14)	/* Enable Interrupt on Port Change */
+#define MASK_SSFSEL	(0x3 << 15)	/* Status SubFrame Select */
+
+/* Audio Codec Control Reg Bit Masks */
+/* ----- ----- ------- --- --- ----- */
+#define MASK_NEWECMD	(0x1 << 24)	/* Lock: don't write to reg when 1 */
+#define MASK_EMODESEL	(0x3 << 22)	/* Send info out on which frame? */
+#define MASK_EXMODEADDR	(0x3ff << 12)	/* Extended Mode Address -- 10 bits */
+#define MASK_EXMODEDATA	(0xfff)		/* Extended Mode Data -- 12 bits */
+
+/* Audio Codec Control Address Values / Masks */
+/* ----- ----- ------- ------- ------ - ----- */
+#define MASK_ADDR0	(0x0 << 12)	/* Expanded Data Mode Address 0 */
+#define MASK_ADDR_MUX	MASK_ADDR0	/* Mux Control */
+#define MASK_ADDR_GAIN	MASK_ADDR0
+
+#define MASK_ADDR1	(0x1 << 12)	/* Expanded Data Mode Address 1 */
+#define MASK_ADDR_MUTE	MASK_ADDR1
+#define MASK_ADDR_RATE	MASK_ADDR1
+
+#define MASK_ADDR2	(0x2 << 12)	/* Expanded Data Mode Address 2 */
+#define MASK_ADDR_VOLA	MASK_ADDR2	/* Volume Control A -- Headphones */
+#define MASK_ADDR_VOLHD MASK_ADDR2
+
+#define MASK_ADDR4	(0x4 << 12)	/* Expanded Data Mode Address 4 */
+#define MASK_ADDR_VOLC	MASK_ADDR4	/* Volume Control C -- Speaker */
+#define MASK_ADDR_VOLSPK MASK_ADDR4
+
+/* Address 0 Bit Masks & Macros */
+/* ------- - --- ----- - ------ */
+#define MASK_GAINRIGHT	(0xf)		/* Gain Right Mask */
+#define MASK_GAINLEFT	(0xf << 4)	/* Gain Left Mask */
+#define MASK_GAINLINE	(0x1 << 8)	/* Change Gain for Line??? */
+#define MASK_GAINMIC	(0x0 << 8)	/* Change Gain for Mic??? */
+
+#define MASK_MUX_CD	(0x1 << 9)	/* Select CD in MUX */
+#define MASK_MUX_AUDIN	(0x1 << 10)	/* Select Audio In in MUX */
+#define MASK_MUX_MIC	(0x1 << 11)	/* Select Mic in MUX */
+#define MASK_MUX_LINE	MASK_MUX_AUDIN
+
+#define GAINRIGHT(x)	((x) & MASK_GAINRIGHT)
+#define GAINLEFT(x)	(((x) << 4) & MASK_GAINLEFT)
+
+/* Address 1 Bit Masks */
+/* ------- - --- ----- */
+#define MASK_ADDR1RES1	(0x3)		/* Reserved */
+#define MASK_RECALIBRATE (0x1 << 2)	/* Recalibrate */
+#define MASK_SAMPLERATE	(0x7 << 3)	/* Sample Rate: */
+#define MASK_LOOPTHRU	(0x1 << 6)	/* Loopthrough Enable */
+#define MASK_CMUTE	(0x1 << 7)	/* Output C (Speaker) Mute when 1 */
+#define MASK_SPKMUTE	MASK_CMUTE
+#define MASK_ADDR1RES2	(0x1 << 8)	/* Reserved */
+#define MASK_AMUTE	(0x1 << 9)	/* Output A (Headphone) Mute when 1 */
+#define MASK_HDMUTE	MASK_AMUTE
+#define MASK_PAROUT	(0x3 << 10)	/* Parallel Out (???) */
+
+#define SAMPLERATE_48000	(0x0 << 3)	/* 48 or 44.1 kHz */
+#define SAMPLERATE_32000	(0x1 << 3)	/* 32 or 29.4 kHz */
+#define SAMPLERATE_24000	(0x2 << 3)	/* 24 or 22.05 kHz */
+#define SAMPLERATE_19200	(0x3 << 3)	/* 19.2 or 17.64 kHz */
+#define SAMPLERATE_16000	(0x4 << 3)	/* 16 or 14.7 kHz */
+#define SAMPLERATE_12000	(0x5 << 3)	/* 12 or 11.025 kHz */
+#define SAMPLERATE_9600		(0x6 << 3)	/* 9.6 or 8.82 kHz */
+#define SAMPLERATE_8000		(0x7 << 3)	/* 8 or 7.35 kHz */
+
+/* Address 2 & 4 Bit Masks & Macros */
+/* ------- - - - --- ----- - ------ */
+#define MASK_OUTVOLRIGHT (0xf)		/* Output Right Volume */
+#define MASK_ADDR2RES1	(0x2 << 4)	/* Reserved */
+#define MASK_ADDR4RES1	MASK_ADDR2RES1
+#define MASK_OUTVOLLEFT	(0xf << 6)	/* Output Left Volume */
+#define MASK_ADDR2RES2	(0x2 << 10)	/* Reserved */
+#define MASK_ADDR4RES2	MASK_ADDR2RES2
+
+#define VOLRIGHT(x)	(((~(x)) & MASK_OUTVOLRIGHT))
+#define VOLLEFT(x)	(((~(x)) << 6) & MASK_OUTVOLLEFT)
+
+/* Audio Codec Status Reg Bit Masks */
+/* ----- ----- ------ --- --- ----- */
+#define MASK_EXTEND	(0x1 << 23)	/* Extend */
+#define MASK_VALID	(0x1 << 22)	/* Valid Data? */
+#define MASK_OFLEFT	(0x1 << 21)	/* Overflow Left */
+#define MASK_OFRIGHT	(0x1 << 20)	/* Overflow Right */
+#define MASK_ERRCODE	(0xf << 16)	/* Error Code */
+#define MASK_REVISION	(0xf << 12)	/* Revision Number */
+#define MASK_MFGID	(0xf << 8)	/* Mfg. ID */
+#define MASK_CODSTATRES	(0xf << 4)	/* bits 4 - 7 reserved */
+#define MASK_INPPORT	(0xf)		/* Input Port */
+#define MASK_HDPCONN	8		/* headphone plugged in */
+
+/* Clipping Count Reg Bit Masks */
+/* -------- ----- --- --- ----- */
+#define MASK_CLIPLEFT	(0xff << 7)	/* Clipping Count, Left Channel */
+#define MASK_CLIPRIGHT	(0xff)		/* Clipping Count, Right Channel */
+
+/* DBDMA ChannelStatus Bit Masks */
+/* ----- ------------- --- ----- */
+#define MASK_CSERR	(0x1 << 7)	/* Error */
+#define MASK_EOI	(0x1 << 6)	/* End of Input -- only for Input Channel */
+#define MASK_CSUNUSED	(0x1f << 1)	/* bits 1-5 not used */
+#define MASK_WAIT	(0x1)		/* Wait */
+
+/* Various Rates */
+/* ------- ----- */
+#define RATE_48000	(0x0 << 8)	/* 48 kHz */
+#define RATE_44100	(0x0 << 8)	/* 44.1 kHz */
+#define RATE_32000	(0x1 << 8)	/* 32 kHz */
+#define RATE_29400	(0x1 << 8)	/* 29.4 kHz */
+#define RATE_24000	(0x2 << 8)	/* 24 kHz */
+#define RATE_22050	(0x2 << 8)	/* 22.05 kHz */
+#define RATE_19200	(0x3 << 8)	/* 19.2 kHz */
+#define RATE_17640	(0x3 << 8)	/* 17.64 kHz */
+#define RATE_16000	(0x4 << 8)	/* 16 kHz */
+#define RATE_14700	(0x4 << 8)	/* 14.7 kHz */
+#define RATE_12000	(0x5 << 8)	/* 12 kHz */
+#define RATE_11025	(0x5 << 8)	/* 11.025 kHz */
+#define RATE_9600	(0x6 << 8)	/* 9.6 kHz */
+#define RATE_8820	(0x6 << 8)	/* 8.82 kHz */
+#define RATE_8000	(0x7 << 8)	/* 8 kHz */
+#define RATE_7350	(0x7 << 8)	/* 7.35 kHz */
+
+#define RATE_LOW	1	/* HIGH = 48kHz, etc;  LOW = 44.1kHz, etc. */
+
+
+/* Burgundy values */
+
+#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
+#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
+
+#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12)
+#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12)
+#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12)
+#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12)
+
+#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12)
+#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12)
+#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
+#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
+
+#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
+#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
+
+#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
+
+#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12)
+
+#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
+#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
+#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
+
+#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
+#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
+#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3)
+#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
+
+#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1)
+#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2)
+#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3)
+#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
+
+
+/* These are all default values for the burgundy */
+#define DEF_BURGUNDY_INPSEL21 (0xAA)
+#define DEF_BURGUNDY_INPSEL3 (0x0A)
+
+#define DEF_BURGUNDY_GAINCD (0x33)
+#define DEF_BURGUNDY_GAINLINE (0x44)
+#define DEF_BURGUNDY_GAINMIC (0x44)
+#define DEF_BURGUNDY_GAINMODEM (0x06)
+
+/* Remember: lowest volume here is 0x9b */
+#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
+#define DEF_BURGUNDY_VOLLINE (0x00000000)
+#define DEF_BURGUNDY_VOLMIC (0x00000000)
+#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
+
+#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f)
+#define DEF_BURGUNDY_OUTPUTENABLES (0x0A)
+
+#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF)
+
+#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E)
+
+#define DEF_BURGUNDY_ATTENSPEAKER (0x44)
+#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
+#define DEF_BURGUNDY_ATTENHP (0xCC)
+
+#endif /* _AWACS_DEFS_H_ */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- v2.3.99-pre6/linux/drivers/sound/emu10k1/main.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/emu10k1/main.c	Wed May 10 22:55:24 2000
@@ -80,7 +80,7 @@
 	"EMU10K1",
 };
 
-static struct pci_device_id emu10k1_pci_tbl[] __initdata = {
+static struct pci_device_id emu10k1_pci_tbl[] = {
 	{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
 	{0,}
@@ -616,7 +616,6 @@
 	}
 
 	if (pci_enable_device(pci_dev)) {
-		printk(KERN_ERR "emu10k1: couldn't enable device\n");
 		kfree(card);
 		return -ENODEV;
 	}
@@ -764,7 +763,7 @@
 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 = {
+static struct pci_driver emu10k1_pci_driver = {
 	name:"emu10k1",
 	id_table:emu10k1_pci_tbl,
 	probe:emu10k1_probe,
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.99-pre6/linux/drivers/sound/es1370.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/es1370.c	Fri Apr 28 23:00:04 2000
@@ -2494,11 +2494,12 @@
 		printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
 		goto err_region;
 	}
+	if (pci_enable_device(pcidev))
+		goto err_irq;
 	if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) {
 		printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	pci_enable_device(pcidev);
 	/* initialize codec registers */
 	/* note: setting CTRL_SERR_DIS is reported to break
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.99-pre6/linux/drivers/sound/es1371.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/es1371.c	Fri Apr 28 23:00:04 2000
@@ -2664,11 +2664,12 @@
 		printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
 		goto err_region;
 	}
+	if (pci_enable_device(pcidev))
+		goto err_irq;
 	if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
 		printk(KERN_ERR PFX "irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	pci_enable_device(pcidev);
 	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n"
 	       KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
 	/* register devices */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.99-pre6/linux/drivers/sound/esssolo1.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/esssolo1.c	Fri Apr 28 23:00:04 2000
@@ -2252,11 +2252,12 @@
 		printk(KERN_ERR "solo1: io ports in use\n");
 		goto err_region4;
 	}
+	if (pci_enable_device(pcidev))
+		goto err_irq;
 	if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
 		printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	pci_enable_device(pcidev);
 	printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
 	printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
 	/* register devices */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.3.99-pre6/linux/drivers/sound/i810_audio.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/i810_audio.c	Wed May 10 16:57:18 2000
@@ -924,7 +924,10 @@
 
 	status = inl(card->iobase + GLOB_STA);
 	if(!(status & INT_MASK)) 
+	{
+		spin_unlock(&card->lock);
 		return;  /* not for us */
+	}
 
 //	printk("Interrupt %X: ", status);
 	if(status & (INT_PO|INT_PI|INT_MC))
@@ -1735,14 +1738,16 @@
 		return -ENODEV;
 	}
 
+	if (pci_enable_device(pci_dev))
+		return -EIO;
 	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->iobase = pci_resource_start (pci_dev, 1);
+	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
 	card->irq = pci_dev->irq;
@@ -1752,7 +1757,6 @@
 	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, 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.3.99-pre6/linux/drivers/sound/mad16.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/mad16.c	Wed May 10 16:56:43 2000
@@ -643,10 +643,10 @@
 static void __init attach_mad16(struct address_info *hw_config)
 {
 
-	static char     interrupt_bits[12] = {
+	static signed char     interrupt_bits[12] = {
 		-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
 	};
-	char bits;
+	signed char bits;
 
 	static char     dma_bits[4] = {
 		1, 2, 0, 3
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v2.3.99-pre6/linux/drivers/sound/midibuf.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/midibuf.c	Wed May  3 01:45:17 2000
@@ -51,7 +51,7 @@
 
 
 static struct timer_list poll_timer = {
-	NULL, NULL, 0, 0, midi_poll
+	function: midi_poll
 };
 
 static volatile int open_devs = 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.3.99-pre6/linux/drivers/sound/sb_card.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/sb_card.c	Wed May 10 16:56:43 2000
@@ -40,6 +40,8 @@
  *  Thanks to Gaël Quéri and Alessandro Zummo for testing and fixes.
  *  Paul E. Laufer <pelaufer@csupomona.edu>
  *
+ * 06-05-2000 added another card. Daniel M. Newman <dmnewman@pobox.com>
+ *
  */
 
 #include <linux/config.h>
@@ -262,6 +264,11 @@
 		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(0x002a),
+		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),
@@ -435,6 +442,11 @@
 		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
 		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
 		1,0,0,0},
+	{"Creative SB16 PnP", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002a), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
 	{0}
 };
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.99-pre6/linux/drivers/sound/sonicvibes.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/sonicvibes.c	Fri Apr 28 23:00:05 2000
@@ -2520,7 +2520,8 @@
 		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
 		goto err_region1;
 	}
-	pci_enable_device(pcidev);
+	if (pci_enable_device(pcidev))
+		goto err_irq;
 	/* initialize codec registers */
 	outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
 	udelay(50);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.3.99-pre6/linux/drivers/sound/soundcard.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/soundcard.c	Wed May  3 01:45:18 2000
@@ -734,7 +734,7 @@
 
 
 static struct timer_list seq_timer =
-{NULL, NULL, 0, 0, do_sequencer_timer};
+{function: do_sequencer_timer};
 
 void request_sound_timer(int count)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h
--- v2.3.99-pre6/linux/drivers/sound/soundmodule.h	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/soundmodule.h	Thu May 11 13:45:35 2000
@@ -26,4 +26,4 @@
 	0
 };
 
-#endif
+#endif /* _SOUNDMODULE_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v2.3.99-pre6/linux/drivers/sound/sys_timer.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/sys_timer.c	Wed May  3 01:45:18 2000
@@ -29,7 +29,7 @@
 
 
 static struct timer_list def_tmr =
-{NULL, NULL, 0, 0, poll_def_tmr};
+{function: poll_def_tmr};
 
 static unsigned long
 tmr2ticks(int tmr_value)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.3.99-pre6/linux/drivers/sound/trident.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/trident.c	Wed May 10 16:56:43 2000
@@ -101,6 +101,7 @@
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include <linux/bitops.h>
 
 #include "trident.h"
 
@@ -284,7 +285,7 @@
 	/* 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 (*free_pcm_channel)(struct trident_card *, unsigned int chan);
 	void (*address_interrupt)(struct trident_card *);
 };
 
@@ -434,13 +435,19 @@
 #endif
 }
 
-static int trident_check_channel_interrupt(struct trident_card * card, int channel)
+static u32 trident_get_interrupt_mask (struct trident_card * card,
+				       unsigned int b)
 {
-	unsigned int mask = 1 << (channel & 0x1f);
-	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
-	u32 reg, addr = bank->addresses->aint;
+	struct trident_pcm_bank *bank = &card->banks[b];
+	u32 addr = bank->addresses->aint;
+	return inl(TRID_REG(card, addr));
+}
 
-	reg = inl(TRID_REG(card, addr));
+static int trident_check_channel_interrupt(struct trident_card * card,
+					   unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	u32 reg = trident_get_interrupt_mask (card, channel >> 5);
 
 #ifdef DEBUG
 	if (reg & mask)
@@ -450,7 +457,8 @@
 	return (reg & mask) ? TRUE : FALSE;
 }
 
-static void trident_ack_channel_interrupt(struct trident_card * card, int channel)
+static void trident_ack_channel_interrupt(struct trident_card * card,
+					  unsigned int channel)
 {
 	unsigned int mask = 1 << (channel & 0x1f);
 	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
@@ -473,11 +481,7 @@
 	int idx;
 
 	bank = &card->banks[BANK_B];
-	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 = 31; idx >= 0; idx--) {
 		if (!(bank->bitmap & (1 << idx))) {
 			struct trident_channel *channel = &bank->channels[idx];
@@ -486,6 +490,9 @@
 			return channel;
 		}
 	}
+
+	/* no more free channels avaliable */
+	printk(KERN_ERR "trident: no more channels available on Bank B.\n");
 	return NULL;
 }
 
@@ -496,12 +503,7 @@
 
 	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++) {
+	for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) {
 		if (!(bank->bitmap & (1 << idx))) {
 			struct trident_channel *channel = &bank->channels[idx];
 			bank->bitmap |= 1 << idx;
@@ -509,6 +511,9 @@
 			return channel;
 		}
 	}
+
+	/* no more free channels avaliable */
+	printk(KERN_ERR "trident: no more channels available on Bank B.\n");
 	return NULL;
 }
 
@@ -529,7 +534,8 @@
 }
 
 
-static void trident_free_pcm_channel(struct trident_card *card, int channel)
+static void trident_free_pcm_channel(struct trident_card *card,
+				     unsigned int channel)
 {
 	int bank;
 
@@ -539,12 +545,10 @@
 	bank = channel >> 5;
 	channel = channel & 0x1f;
 
-	if (card->banks[bank].bitmap & (1 << (channel))) {
-		card->banks[bank].bitmap &= ~(1 << (channel));
-	}
+	card->banks[bank].bitmap &= ~(1 << (channel));
 }
 
-static void ali_free_pcm_channel(struct trident_card *card, int channel)
+static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel)
 {
 	int bank;
 
@@ -554,9 +558,7 @@
 	bank = channel >> 5;
 	channel = channel & 0x1f;
 
-	if (card->banks[bank].bitmap & (1 << (channel))) {
-		card->banks[bank].bitmap &= ~(1 << (channel));
-	}
+	card->banks[bank].bitmap &= ~(1 << (channel));
 }
 
 
@@ -569,14 +571,16 @@
 	if (channel > 63)
 		return FALSE;
 
-	/* select hardware channel to write */
+       /* select hardware channel to write */
 	outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
-	/* output the channel registers */
+
+	/* Output the channel registers, but don't write register
+	   three to an ALI chip. */
+
 	for (i = 0; i < CHANNEL_REGS; i++) {
+		if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451)
+			continue;
 		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;
@@ -1229,21 +1233,50 @@
 static void ali_address_interrupt(struct trident_card *card)
 {
 	int i;
-	struct trident_state *state;
-	
+	u32 mask = trident_get_interrupt_mask (card, BANK_A);
+
+#ifdef DEBUG
+	/* Sanity check to make sure that every state has a channel
+	   and vice versa. */
+	u32 done = 0;
+	unsigned ns = 0;
+	unsigned nc = 0;
 	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 {
+		if (card->banks[BANK_A].bitmap & (1<<i))
+			nc ++;
+
+		if (card->states[i]) {
+			u32 bit = 1 << card->states[i]->dmabuf.channel->num;
+			if (bit & done) 
+				printk (KERN_ERR "trident: channel allocated to two states\n");
+			ns++;
+
+			done |= bit;
+		}
+	}
+	if (ns != nc) 
+		printk (KERN_ERR "trident: number of states != number of channels\n");
+#endif
+
+	for (i = 0; mask && i < NR_HW_CH; i++) {			
+		struct trident_state *state = card->states[i];
+		if (!state)
+			continue;
+
+		trident_ack_channel_interrupt(card, state->dmabuf.channel->num);
+		mask &= ~ (1<<state->dmabuf.channel->num);
+		state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
+		trident_update_ptr(state);
+	}
+
+	if (mask) 
+		for (i = 0; i < NR_HW_CH; i++)
+			if (mask & (1<<i)) {
 				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)
@@ -1897,7 +1930,7 @@
 		
 	if (dmabuf->channel == NULL) {
 		kfree (card->states[i]);
-		card->states[i] = NULL;;
+		card->states[i] = NULL;
 		return -ENODEV;
 	}
 
@@ -1954,6 +1987,11 @@
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&state->open_sem);
 
+#ifdef DEBUG
+	printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n", 
+	       state->virt,
+	       dmabuf->channel->num);
+#endif
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -2343,13 +2381,16 @@
 	}
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
 
-	iobase = pci_dev->resource[0].start;
+	iobase = pci_resource_start (pci_dev, 0);
 	if (check_region(iobase, 256)) {
 		printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
 		       iobase);
 		return -ENODEV;
 	}
 
+	if (pci_enable_device(pci_dev))
+		return -ENODEV;
+
 	if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "trident: out of memory\n");
 		return -ENOMEM;
@@ -2371,7 +2412,6 @@
 	devs = card;
 
 	pci_set_master(pci_dev);
-	pci_enable_device(pci_dev);
 
 	printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
 	       card_names[pci_id->driver_data], card->iobase, card->irq);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/trident.h linux/drivers/sound/trident.h
--- v2.3.99-pre6/linux/drivers/sound/trident.h	Wed Apr 26 16:34:08 2000
+++ linux/drivers/sound/trident.h	Sat Apr 29 19:55:12 2000
@@ -103,6 +103,11 @@
 	ALI_PCM_IN_CHANNEL	= 31
 };
 
+enum ali_pcm_out_channel_num {
+	ALI_PCM_OUT_CHANNEL_FIRST = 1,
+	ALI_PCM_OUT_CHANNEL_LAST = 30
+};
+
 enum ali_ac97_power_control_bit {
 	ALI_EAPD_POWER_DOWN	= 0x8000
 };
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.3.99-pre6/linux/drivers/sound/trix.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/trix.c	Wed May 10 16:56:43 2000
@@ -276,7 +276,7 @@
 
 	int tmp;
 	unsigned char conf;
-	static char irq_translate[] = {
+	static signed char irq_translate[] = {
 		-1, -1, -1, 0, 1, 2, -1, 3
 	};
 
@@ -346,7 +346,7 @@
 static int __init probe_trix_mpu(struct address_info *hw_config)
 {
 	unsigned char conf;
-	static char irq_bits[] = {
+	static int irq_bits[] = {
 		-1, -1, -1, 1, 2, 3, -1, 4, -1, 5
 	};
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v2.3.99-pre6/linux/drivers/sound/uart6850.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/uart6850.c	Wed May  3 01:45:18 2000
@@ -76,7 +76,7 @@
 
 
 static struct timer_list uart6850_timer = {
-	NULL, NULL, 0, 0, poll_uart6850
+	function: poll_uart6850
 };
 
 static void uart6850_input_loop(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.3.99-pre6/linux/drivers/sound/via82cxxx_audio.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/via82cxxx_audio.c	Thu May 11 13:45:35 2000
@@ -5,51 +5,45 @@
  * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
  * See the "COPYING" file distributed with this software for more info.
  *
- * Documentation for this driver available as
- * linux/Documentation/sound/via82cxxx.txt.
+ * For a list of known bugs (errata) and documentation,
+ * see via82cxxx.txt in linux/Documentation/sound.
  *
- * Since the mixer is called from the OSS glue the kernel lock is always held
- * on our AC97 mixing
  */
  
 
-#define VIA_VERSION	"1.1.2.1"
+#define VIA_VERSION	"1.1.5"
 
 
-
-#include <linux/module.h>
 #include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
-
+#include <linux/spinlock.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/ac97_codec.h>
 #include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
-#include "sb.h"
-#include "ac97.h"
-#include "mpu401.h"
 
-#ifndef SOUND_LOCK
-#define SOUND_LOCK do {} while (0)
-#define SOUND_LOCK_END do {} while (0)
-#endif
 
-#define VIA_DEBUG 0	/* define to 1 to enable debugging output and checks */
-#if VIA_DEBUG
+#undef VIA_DEBUG	/* define to enable debugging output and checks */
+#ifdef VIA_DEBUG
 /* note: prints function name for you */
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
 
-#define VIA_NDEBUG 0	/* define to 1 to disable lightweight runtime checks */
-#if VIA_NDEBUG
+#define VIA_NDEBUG	/* define to disable lightweight runtime checks */
+#ifdef VIA_NDEBUG
 #define assert(expr)
 #else
 #define assert(expr) \
@@ -59,29 +53,109 @@
         }
 #endif
 
+/* user switch: undefine to exclude /proc data */
+#define VIA_PROC_FS 1
+
+/* don't mess with this */
+#ifndef CONFIG_PROC_FS
+#undef VIA_PROC_FS
+#endif
+
 #define arraysize(x)            (sizeof(x)/sizeof(*(x)))
 
-#define MAX_CARDS	2
+#define MAX_CARDS	1
 
 #define	LINE_SIZE	10
 
 #define VIA_CARD_NAME	"VIA 82Cxxx Audio driver " VIA_VERSION
-#define VIA_MODULE_NAME "via_audio"
+#define VIA_MODULE_NAME "via82cxxx"
 #define PFX		VIA_MODULE_NAME ": "
 
 #define VIA_COUNTER_LIMIT	100000
 
+/* size of DMA buffers */
+#define VIA_DMA_BUFFERS		16
+#define VIA_DMA_BUF_SIZE	PAGE_SIZE
+
 /* 82C686 function 5 (audio codec) PCI configuration registers */
+#define VIA_ACLINK_CTRL		0x41
 #define VIA_FUNC_ENABLE		0x42
 #define VIA_PNP_CONTROL		0x43
-#define VIA_AC97_CTRL		0x80
+#define VIA_FM_NMI_CTRL		0x48
+
+/*
+ * controller base 0 (scatter-gather) registers
+ *
+ * NOTE: Via datasheet lists first channel as "read"
+ * channel and second channel as "write" channel.
+ * I changed the naming of the constants to be more
+ * clear than I felt the datasheet to be.
+ */
+
+#define VIA_BASE0_PCM_OUT_CHAN	0x00 /* output PCM to user */
+#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
+#define VIA_BASE0_PCM_OUT_CHAN_CTRL	0x01
+#define VIA_BASE0_PCM_OUT_CHAN_TYPE	0x02
+#define VIA_BASE0_PCM_OUT_BLOCK_COUNT	0x0C
+
+#define VIA_BASE0_PCM_IN_CHAN		0x10 /* input PCM from user */
+#define VIA_BASE0_PCM_IN_CHAN_STATUS	0x10
+#define VIA_BASE0_PCM_IN_CHAN_CTRL	0x11
+#define VIA_BASE0_PCM_IN_CHAN_TYPE	0x12
+
+/* offsets from base */
+#define VIA_PCM_STATUS			0x00
+#define VIA_PCM_CONTROL			0x01
+#define VIA_PCM_TYPE			0x02
+#define VIA_PCM_TABLE_ADDR		0x04
+
+/* XXX unused DMA channel for FM PCM data */
+#define VIA_BASE0_FM_OUT_CHAN		0x20
+#define VIA_BASE0_FM_OUT_CHAN_STATUS	0x20
+#define VIA_BASE0_FM_OUT_CHAN_CTRL	0x21
+#define VIA_BASE0_FM_OUT_CHAN_TYPE	0x22
+
+#define VIA_BASE0_AC97_CTRL		0x80
+#define VIA_BASE0_SGD_STATUS_SHADOW	0x84
+#define VIA_BASE0_GPI_INT_ENABLE	0x8C
+
+/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
+#define VIA_IRQ_ON_FLAG			(1<<0)	/* int on each flagged scatter block */
+#define VIA_IRQ_ON_EOL			(1<<1)	/* int at end of scatter list */
+#define VIA_INT_SEL_PCI_LAST_LINE_READ	(0)	/* int at PCI read of last line */
+#define VIA_INT_SEL_LAST_SAMPLE_SENT	(1<<2)	/* int at last sample sent */
+#define VIA_INT_SEL_ONE_LINE_LEFT	(1<<3)	/* int at less than one line to send */
+#define VIA_PCM_FMT_STEREO		(1<<4)	/* PCM stereo format (bit clear == mono) */
+#define VIA_PCM_FMT_16BIT		(1<<5)	/* PCM 16-bit format (bit clear == 8-bit) */
+#define VIA_PCM_FIFO			(1<<6)	/* enable FIFO?  documented as "reserved" */
+#define VIA_RESTART_SGD_ON_EOL		(1<<7)	/* restart scatter-gather at EOL */
+#define VIA_PCM_FMT_MASK		(VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
+#define VIA_CHAN_TYPE_MASK		(VIA_RESTART_SGD_ON_EOL | \
+					 VIA_PCM_FIFO | \
+					 VIA_IRQ_ON_FLAG | \
+					 VIA_IRQ_ON_EOL)
+#define VIA_CHAN_TYPE_INT_SELECT	(VIA_INT_SEL_LAST_SAMPLE_SENT)
 
 /* PCI configuration register bits and masks */
 #define VIA_CR40_AC97_READY	0x01
 #define VIA_CR40_AC97_LOW_POWER	0x02
 #define VIA_CR40_SECONDARY_READY 0x04
 
-#define VIA_CR41_ACLINK_ENABLE	0x80
+#define VIA_CR41_AC97_ENABLE	0x80 /* enable AC97 codec */
+#define VIA_CR41_AC97_RESET	0x40 /* clear bit to reset AC97 */
+#define VIA_CR41_AC97_WAKEUP	0x20 /* wake up from power-down mode */
+#define VIA_CR41_AC97_SDO	0x10 /* force Serial Data Out (SDO) high */
+#define VIA_CR41_VRA		0x08 /* enable variable sample rate */
+#define VIA_CR41_PCM_ENABLE	0x04 /* AC Link SGD Read Channel PCM Data Output */
+#define VIA_CR41_FM_PCM_ENABLE	0x02 /* AC Link FM Channel PCM Data Out */
+#define VIA_CR41_SB_PCM_ENABLE	0x01 /* AC Link SB PCM Data Output */
+#define VIA_CR41_BOOT_MASK	(VIA_CR41_AC97_ENABLE | \
+				 VIA_CR41_AC97_WAKEUP | \
+				 VIA_CR41_AC97_SDO)
+#define VIA_CR41_RUN_MASK	(VIA_CR41_AC97_ENABLE | \
+				 VIA_CR41_AC97_RESET | \
+				 VIA_CR41_VRA | \
+				 VIA_CR41_PCM_ENABLE)
 
 #define VIA_CR42_SB_ENABLE	0x01
 #define VIA_CR42_MIDI_ENABLE	0x02
@@ -91,632 +165,2372 @@
 #define VIA_CR44_SECOND_CODEC_SUPPORT	(1 << 6)
 #define VIA_CR44_AC_LINK_ACCESS		(1 << 7)
 
+#define VIA_CR48_FM_TRAP_TO_NMI		(1 << 2)
+
+/* controller base 0 register bitmasks */
+#define VIA_INT_DISABLE_MASK		(~(0x01|0x02))
+#define VIA_SGD_STOPPED			(1 << 2)
+#define VIA_SGD_ACTIVE			(1 << 7)
+#define VIA_SGD_TERMINATE		(1 << 6)
+#define VIA_SGD_FLAG			(1 << 0)
+#define VIA_SGD_EOL			(1 << 1)
+#define VIA_SGD_START			(1 << 7)
+
 #define VIA_CR80_FIRST_CODEC		0
 #define VIA_CR80_SECOND_CODEC		(1 << 30)
 #define VIA_CR80_FIRST_CODEC_VALID	(1 << 25)
+#define VIA_CR80_VALID			(1 << 25)
 #define VIA_CR80_SECOND_CODEC_VALID	(1 << 27)
 #define VIA_CR80_BUSY			(1 << 24)
-#define VIA_CR80_READ_MODE		(1 << 23)
+#define VIA_CR83_BUSY			(1)
+#define VIA_CR83_FIRST_CODEC_VALID	(1 << 1)
+#define VIA_CR80_READ			(1 << 23)
 #define VIA_CR80_WRITE_MODE		0
-#define VIA_CR80_REG_IDX(idx)		(((idx) & 0x7E) << 16)
+#define VIA_CR80_REG_IDX(idx)		((((idx) & 0xFF) >> 1) << 16)
 
-struct via_info {
-	struct address_info sb_data;
-	struct address_info opl3_data;
-	struct pci_dev *pdev;
-	struct ac97_hwint ac97;
-	int mixer_oss_dev;
-	int have_ac97;
+/* h r puff n stuff */
+#define VIA_FMT_STEREO	0x01
+#define VIA_FMT_16BIT	0x02
+#define VIA_FMT_MASK	0x03
+#define VIA_DAC_SHIFT	0   
+#define VIA_ADC_SHIFT	4
+
+/* undocumented(?) values for setting rate, from Via's source */
+#define VIA_SET_RATE_IN		0x00320000 /* set input rate */
+#define VIA_SET_RATE_OUT	0x002c0000 /* set output rate */
+
+
+/* scatter-gather DMA table entry, exactly as passed to hardware */
+struct via_sgd_table {
+	u32 addr;
+	u32 count;	/* includes additional bits also */
 };
-static struct via_info		cards [MAX_CARDS];
-static unsigned			num_cards = 0;
+#define VIA_EOL (1 << 31)
+#define VIA_FLAG (1 << 30)
 
 
-static const struct {
-	int revision;
-	const char *rev_name;
-} via_chip_revs[] __initdata = {
-	{ 0x10, "A" },
-	{ 0x11, "B" },
-	{ 0x12, "C" },
-	{ 0x13, "D" },
-	{ 0x14, "E" },
-	{ 0x20, "H" },
+enum via_channel_states {
+	sgd_stopped = 0,
+	sgd_in_progress = 1,
 };
 
-static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data)
-{
-	struct resource *rsrc = &pdev->resource[0];
-	outw ((u16)data,rsrc->start+port);	
-	outw ((u16)(data>>16),rsrc->start+port+2);	
-}
 
-static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port)
-{
-	struct resource *rsrc = &pdev->resource[0];
-	return
-		((u32)inw (rsrc->start+port)) |
-		(((u32)inw (rsrc->start+port+2)) << 16);
-}
+struct via_sgd_data {
+	dma_addr_t handle;
+	volatile void *cpuaddr;
+};
 
-/****************************************************************
- *
- * Intel Audio Codec '97 interface
- *
- *
- */
- 
-static inline void via_ac97_wait_idle (struct pci_dev *pdev)
-{
-	u32 tmp;
-	int counter = VIA_COUNTER_LIMIT;
-	
-	DPRINTK ("ENTER\n");
 
-	assert (pdev != NULL);
-	
-	do {
-		tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL);
-	} while ((tmp & VIA_CR80_BUSY) && (counter-- > 0));
+struct via_channel {
+	unsigned rate;		/* sample rate */
 
-	DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached");
-}
+	u8 pcm_fmt;		/* VIA_PCM_FMT_xxx */
+	
+	atomic_t state;
+	atomic_t buf_in_use;
+	atomic_t next_buf;
+	
+	volatile struct via_sgd_table *sgtable;
+	dma_addr_t sgt_handle;
+	
+	struct via_sgd_data sgbuf [VIA_DMA_BUFFERS];
+	
+	wait_queue_head_t wait;
+	
+	long iobase;
+};
 
 
-static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg)
-{
-	u32 data;
-	struct via_info *card;
+/* data stored for each chip */
+struct via_info {
 	struct pci_dev *pdev;
+	long baseaddr;
 	
-	DPRINTK ("ENTER\n");
+	struct ac97_codec ac97;
+	spinlock_t lock;
+	int card_num;		/* unique card number, from 0 */
 
-	assert (dev != NULL);
-	assert (dev->driver_private != NULL);
+	int dev_dsp;		/* /dev/dsp index from register_sound_dsp() */
+	
+	unsigned rev_h : 1;
 
-	card = (struct via_info *) dev->driver_private;
-	pdev = card->pdev;
-	assert (pdev != NULL);
+	wait_queue_head_t open_wait;
+	int open_mode;
+	
+	struct via_channel ch_in;
+	struct via_channel ch_out;
+};
 
-	via_ac97_wait_idle (pdev);
-	data =	VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
-		VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg);
-	via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
-	via_ac97_wait_idle (pdev);
-	data = via_ac97_read32 (pdev,VIA_AC97_CTRL);
 
-#if 0
-	if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
-		DPRINTK ("EXIT, first codec not valid, returning -1\n");
-		return -1;
-	}
-#endif
+/* number of cards, used for assigning unique numbers to cards */
+static unsigned via_num_cards = 0;
 
-	DPRINTK ("EXIT, returning %d\n", data & 0xFFFF);
-	return data & 0xFFFF;
-}
 
+/****************************************************************
+ *
+ * prototypes
+ *
+ *
+ */
+
+static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id);
+static void via_remove_one (struct pci_dev *pdev);
 
-static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value)
-{
-	u32 data;
-	struct via_info *card;
-	struct pci_dev *pdev;
-	
-	DPRINTK ("ENTER\n");
+static ssize_t via_dsp_read(struct file *file, char *buffer, size_t count, loff_t *ppos);
+static ssize_t via_dsp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos);
+static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait);
+static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int via_dsp_open (struct inode *inode, struct file *file);
+static int via_dsp_release(struct inode *inode, struct file *file);
+
+static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
+static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
+static u8 via_ac97_wait_idle (struct via_info *card);
+static u32 via_ac97_wait_valid (struct via_info *card);
+
+static void via_chan_free (struct via_info *card, struct via_channel *chan);
+static void via_chan_clear (struct via_channel *chan);
+static void via_chan_pcm_fmt (struct via_info *card,
+			      struct via_channel *chan, int reset);
 
-	assert (dev != NULL);
-	assert (dev->driver_private != NULL);
 
-	card = (struct via_info *) dev->driver_private;
-	pdev = card->pdev;
-	assert (pdev != NULL);
+/****************************************************************
+ *
+ * Various data the driver needs
+ *
+ *
+ */
 
-	via_ac97_wait_idle (pdev);
-	data =	VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
-		VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value;
-	via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
 
-#if 0
-	if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
-		DPRINTK ("EXIT, first codec invalid, returning -1\n");
-		return -1;
-	}
-#endif
+static struct pci_device_id via_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci,via_pci_tbl);
 
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
 
+static struct pci_driver via_driver = {
+	name:		VIA_MODULE_NAME,
+	id_table:	via_pci_tbl,
+	probe:		via_init_one,
+	remove:		via_remove_one,
+};
 
-static int via_ac97_reset (struct ac97_hwint *dev)
-{
-	struct via_info *card;
-	struct pci_dev *pdev;
-	
-	DPRINTK ("ENTER\n");
 
-	assert (dev != NULL);
-	assert (dev->driver_private != NULL);
+/****************************************************************
+ *
+ * Low-level base 0 register read/write helpers
+ *
+ *
+ */
+
+static inline void via_chan_stop (int iobase)
+{
+	if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
+		outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
+}
 
-	card = (struct via_info *) dev->driver_private;
-	pdev = card->pdev;
-	assert (pdev != NULL);
+static inline void via_chan_status_clear (int iobase)
+{
+	u8 tmp = inb (iobase + VIA_PCM_STATUS);
 	
-	pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO);
+	if (tmp != 0)
+		outb (tmp, iobase + VIA_PCM_STATUS);
+}
 
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
+static inline void sg_begin (struct via_channel *chan)
+{
+	outb (VIA_SGD_START, chan->iobase + VIA_PCM_CONTROL);
 }
 
 
-static struct via_info *via_ac97_find_card_for_mixer (int dev)
+static inline int via_chan_bufs_in_use (struct via_channel *chan)
 {
-	int x;
-
-	DPRINTK ("ENTER\n");
+	return atomic_read(&chan->next_buf) -
+	       atomic_read(&chan->buf_in_use);
+}
 
-	for (x = 0; x < num_cards; x++)
-		if (cards[x].mixer_oss_dev == dev) {
-			DPRINTK ("EXIT, returning %p\n", cards + x);
-			return cards + x;
-		}
 
-	DPRINTK ("EXIT, returning 0\n");
-	return NULL;
+static inline int via_chan_full (struct via_channel *chan)
+{
+	return (via_chan_bufs_in_use (chan) == VIA_DMA_BUFFERS);
 }
 
 
-static int
-via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+static inline int via_chan_empty (struct via_channel *chan)
 {
-	int rc;
-	struct via_info *card = via_ac97_find_card_for_mixer (dev);
+	return (atomic_read(&chan->next_buf) ==
+	        atomic_read(&chan->buf_in_use));
+}
+
+
+/****************************************************************
+ *
+ * Miscellaneous debris
+ *
+ *
+ */
 
+static void via_stop_everything (struct via_info *card)
+{
 	DPRINTK ("ENTER\n");
 
-	if (card != NULL) {
-		rc = ac97_mixer_ioctl (&card->ac97, cmd, arg);
-		DPRINTK ("EXIT, returning %d\n", rc);
-		return rc;
-	}
-	
-	DPRINTK ("EXIT, returning -ENODEV\n");
-	return -ENODEV;
+	assert (card != NULL);
 
+	/*
+	 * terminate any existing operations on audio read/write channels
+	 */
+	via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
+	via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
+	via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+
+	/*
+	 * clear any existing stops / flags (sanity check mainly)
+	 */
+	via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
+	via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
+	via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+	
+	/*
+	 * clear any enabled interrupt bits, reset to 8-bit mono PCM mode
+	 */
+	outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
+	outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
+	outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+	DPRINTK ("EXIT\n");
 }
 
-static struct mixer_operations via_ac97_mixer_operations =
-{
-	"VIA82Cxxx",
-	"via82cxxxAC97Mixer",
-	via_ac97_default_mixer_ioctl
-};
 
-static int __init via_attach_ac97 (struct via_info *card)
+static int via_set_rate (struct via_info *card, unsigned rate, int inhale_deeply)
 {
-	int mixer;
-	struct ac97_hwint *mdev;
+#if 0
+	unsigned long flags;
+	u32 status;
+	u8 status8;
+#endif
 
-	DPRINTK ("ENTER\n");
+	DPRINTK ("ENTER, rate = %d, inhale = %s\n",
+		 rate, inhale_deeply ? "yes" : "no");
 
-	assert (card != NULL);
+	if (rate > 48000)		rate = 48000;
+	if (rate < 4000) 		rate = 4000;
+	
+#if 0
+	status8 = via_ac97_wait_idle (card);
+	if (status8 & VIA_CR83_BUSY) {
+		DPRINTK ("EXIT, status=0x%X, returning -EIO\n", status);
+		return -EIO;
+	}
 
-	mdev = &card->ac97;
+	if (inhale_deeply) {
+		card->ch_in.rate = rate;
 
-	memset (mdev, 0, sizeof (*mdev));
-	mdev->reset_device = via_ac97_reset;
-	mdev->read_reg = via_ac97_read_reg;
-	mdev->write_reg = via_ac97_write_reg;
-	mdev->driver_private = (void *) card;
+		spin_lock_irqsave (&card->lock, flags);
+		outl (VIA_SET_RATE_IN + rate,
+		      card->baseaddr + VIA_BASE0_AC97_CTRL);
+		spin_unlock_irqrestore (&card->lock, flags);
+	} else {
+		card->ch_out.rate = rate;
 
-	if (ac97_init (mdev)) {
-		printk (KERN_ERR PFX "Unable to init AC97\n");
-		DPRINTK ("EXIT, returning -1\n");
-		return -1;
-	}
-	mixer = sound_alloc_mixerdev ();
-	if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) {
-		printk (KERN_ERR PFX "Unable to alloc mixerdev\n");
-		DPRINTK ("EXIT, returning -1\n");
-		return -1;
+		spin_lock_irqsave (&card->lock, flags);
+		outl (VIA_SET_RATE_OUT + rate,
+		      card->baseaddr + VIA_BASE0_AC97_CTRL);
+		spin_unlock_irqrestore (&card->lock, flags);
 	}
-	mixer_devs[mixer] = &via_ac97_mixer_operations;
-	card->mixer_oss_dev = mixer;
 
-	/* Some reasonable default values.  */
-	ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85);
-	ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100);
-	ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65);
-	ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65);
+#else
+	via_ac97_write_reg (&card->ac97, AC97_POWER_CONTROL,
+		(via_ac97_read_reg (&card->ac97, AC97_POWER_CONTROL) & ~0x0200) |
+		0x0200);
+	via_ac97_write_reg (&card->ac97, AC97_PCM_FRONT_DAC_RATE, rate);
+	via_ac97_write_reg (&card->ac97, AC97_POWER_CONTROL,
+		via_ac97_read_reg (&card->ac97, AC97_POWER_CONTROL) & ~0x0200);
+#endif
 
-	printk (KERN_INFO PFX "Initialized AC97 mixer\n");
-	
-	card->have_ac97 = mixer;
-	
 	DPRINTK ("EXIT, returning 0\n");
-	return 0;
+	return rate;
 }
 
 
-static void via_unload_ac97 (struct via_info *card)
+static inline int via_set_adc_rate (struct via_info *card, int rate)
 {
-	DPRINTK ("ENTER\n");
-
-	assert (card != NULL);
+	return via_set_rate (card, rate, 1);
+}
 
-	if (card->have_ac97 >= 0)
-		sound_unload_mixerdev (card->have_ac97);
 
-	DPRINTK ("EXIT\n");
+static inline int via_set_dac_rate (struct via_info *card, int rate)
+{
+	return via_set_rate (card, rate, 0);
 }
 
 
-#ifdef CONFIG_PROC_FS
-
 /****************************************************************
  *
- * /proc/driver/via82cxxx/info
+ * Channel-specific operations
  *
  *
  */
-
-static int via_info_read_proc (char *page, char **start, off_t off,
-			       int count, int *eof, void *data)
+ 
+static int via_chan_init (struct via_info *card, 
+			  struct via_channel *chan, long chan_ofs)
 {
-#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
-
-	int len = 0, i;
-	u8 r40, r41, r42, r44;
+	int i;
+	unsigned long flags;
 	
 	DPRINTK ("ENTER\n");
 
-	len += sprintf (page+len, VIA_CARD_NAME "\n\n");
-	
-	for (i = 0; i < num_cards; i++) {
-		pci_read_config_byte (cards[i].pdev, 0x40, &r40);
-		pci_read_config_byte (cards[i].pdev, 0x42, &r41);
-		pci_read_config_byte (cards[i].pdev, 0x42, &r42);
-		pci_read_config_byte (cards[i].pdev, 0x44, &r44);
-	
-		len += sprintf (page+len,
-			"40  AC97 Codec Ready: %s\n"
-			"    AC97 Codec Low-power: %s\n"
-			"    Secondary Codec Ready: %s\n"
-
-			"41  AC-Link Interface Enable: %s\n"
-
-			"42  Game port enabled: %s\n"
-			"    SoundBlaster enabled: %s\n"
-			"    FM enabled: %s\n"
-			"    MIDI enabled: %s\n"
-			
-			"44  AC-Link Interface Access: %s\n"
-			"    Secondary Codec Support: %s\n"
-			
-			"\n",
-			
-			YN (r40, VIA_CR40_AC97_READY),
-			YN (r40, VIA_CR40_AC97_LOW_POWER),
-			YN (r40, VIA_CR40_SECONDARY_READY),
-
-			YN (r41, VIA_CR41_ACLINK_ENABLE),
-
-			YN (r42, VIA_CR42_GAME_ENABLE),
-			YN (r42, VIA_CR42_SB_ENABLE),
-			YN (r42, VIA_CR42_FM_ENABLE),
-			YN (r42, VIA_CR42_MIDI_ENABLE),
+	memset (chan, 0, sizeof (*chan));
 
-			YN (r44, VIA_CR44_AC_LINK_ACCESS),
-			YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT)
-			
-			);
+	/* alloc DMA-able memory for scatter-gather table */
+	chan->sgtable = pci_alloc_consistent (card->pdev,
+		(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+		&chan->sgt_handle);
+	if (!chan->sgtable) {
+		printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
+		DPRINTK ("EXIT\n");
+		return -ENOMEM;
 	}
 	
-	DPRINTK("EXIT, returning %d\n", len);
-	return len;
+	memset ((void*)chan->sgtable, 0, 
+		(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS));
 
-#undef YN
-}
+	/* alloc DMA-able memory for scatter-gather buffers */
+	for (i = 0; i < VIA_DMA_BUFFERS; i++) {
+		chan->sgbuf[i].cpuaddr =
+			pci_alloc_consistent (card->pdev, VIA_DMA_BUF_SIZE,
+					      &chan->sgbuf[i].handle);
+
+		if (!chan->sgbuf[i].cpuaddr)
+			goto err_out_nomem;
+
+		if (i < (VIA_DMA_BUFFERS - 1))
+			chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);
+		else
+			chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);
+		chan->sgtable[i].addr = cpu_to_le32 (chan->sgbuf[i].handle);
 
+#ifndef VIA_NDEBUG
+		memset (chan->sgbuf[i].cpuaddr, 0xBC, VIA_DMA_BUF_SIZE);
+#endif
 
-/****************************************************************
- *
- * /proc/driver/via82cxxx
- *
- *
- */
+#if 1
+		DPRINTK ("dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)\n",
+			 i, (long)chan->sgbuf[i].handle,
+			 (long)chan->sgtable[i].addr,
+			 virt_to_phys(chan->sgbuf[i].cpuaddr),
+			 chan->sgbuf[i].cpuaddr);
+#endif
+	}
 
-static int __init via_init_proc (void)
-{
-	DPRINTK ("ENTER\n");
+	init_waitqueue_head (&chan->wait);
 
-	proc_mkdir ("driver/via_audio", 0);
-	create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL);
+	chan->pcm_fmt = VIA_PCM_FMT_MASK;
+	chan->iobase = card->baseaddr + chan_ofs;
 	
-	DPRINTK("EXIT\n");
+	spin_lock_irqsave (&card->lock, flags);
+
+	/* stop any existing channel output */
+	via_chan_clear (chan);
+	via_chan_status_clear (chan->iobase);
+	via_chan_pcm_fmt (card, chan, 1);
+
+	spin_unlock_irqrestore (&card->lock, flags);
+
+	/* set location of DMA-able scatter-gather info table */
+	DPRINTK("outl (0x%X, 0x%04lX)\n",
+		cpu_to_le32 (chan->sgt_handle),
+		card->baseaddr + chan_ofs + VIA_PCM_TABLE_ADDR);
+
+	via_ac97_wait_idle (card);
+	outl (cpu_to_le32 (chan->sgt_handle),
+	      card->baseaddr + chan_ofs + VIA_PCM_TABLE_ADDR);
+	udelay (20);
+	via_ac97_wait_idle (card);
+	
+	DPRINTK("inl (0x%lX) = %x\n",
+		chan->iobase + VIA_PCM_TABLE_ADDR,
+		inl(chan->iobase + VIA_PCM_TABLE_ADDR));
+
+	DPRINTK ("EXIT\n");
 	return 0;
-}
 
+err_out_nomem:
+	printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
+	via_chan_free (card, chan);
+	DPRINTK ("EXIT\n");
+	return -ENOMEM;
+}
 
 
-static void __exit via_cleanup_proc (void)
+static void via_chan_free (struct via_info *card, struct via_channel *chan)
 {
+	int i;
+	unsigned long flags;
+	
 	DPRINTK ("ENTER\n");
-	remove_proc_entry ("driver/via_audio/info", NULL);
-	remove_proc_entry ("driver/via_audio", NULL);
-	DPRINTK("EXIT\n");
+	
+	synchronize_irq();
+
+	spin_lock_irqsave (&card->lock, flags);
+
+	/* stop any existing channel output */
+	via_chan_stop (chan->iobase);
+	via_chan_status_clear (chan->iobase);
+	via_chan_pcm_fmt (card, chan, 1);
+
+	spin_unlock_irqrestore (&card->lock, flags);
+
+	/* zero location of DMA-able scatter-gather info table */
+	via_ac97_wait_idle(card);
+	outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
+
+	for (i = 0; i < VIA_DMA_BUFFERS; i++)
+		if (chan->sgbuf[i].cpuaddr) {
+			pci_free_consistent (card->pdev, VIA_DMA_BUF_SIZE,
+					     (void*)chan->sgbuf[i].cpuaddr,
+					     chan->sgbuf[i].handle);
+			chan->sgbuf[i].cpuaddr = NULL;
+			chan->sgbuf[i].handle = 0;
+		}
+
+	if (chan->sgtable) {
+		pci_free_consistent (card->pdev, 
+			(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+			(void*)chan->sgtable, chan->sgt_handle);
+		chan->sgtable = NULL;
+	}
+
+	DPRINTK ("EXIT\n");
 }
 
 
-#else
+static void via_chan_pcm_fmt (struct via_info *card,
+			      struct via_channel *chan, int reset)
+{
+	DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",
+		 chan->pcm_fmt, reset ? "yes" : "no");
 
-static inline int via_init_proc (void) { return 0; }
-static inline void via_cleanup_proc (void) {}
+	assert (card != NULL);
+	assert (chan != NULL);
 
-#endif /* CONFIG_PROC_FS */
+	if (reset)
+		/* reset to 8-bit mono mode */
+		chan->pcm_fmt = 0;
+	
+	/* enable interrupts on FLAG and EOL */
+	chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
+	
+	/* set interrupt select bits where applicable (PCM & FM out channels) */
+	if (chan == &card->ch_out)
+		chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
 
+	outb (chan->pcm_fmt, chan->iobase + 2);
 
-/****************************************************************
- *
- * Legacy SoundBlaster Pro, FM support via OSS
- *
- *
- */
+	DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
+		 chan->pcm_fmt,
+		 inb (chan->iobase + 2));
+}
 
-static void __init via_attach_sb(struct address_info *hw_config)
+
+static void via_chan_clear (struct via_channel *chan)
 {
-	DPRINTK ("ENTER\n");
+	via_chan_stop (chan->iobase);
+	atomic_set (&chan->state, sgd_stopped);
+	atomic_set (&chan->buf_in_use, 0);
+	atomic_set (&chan->next_buf, 0);
+}
 
-	if(!sb_dsp_init(hw_config))
-		hw_config->slots[0] = -1;
 
-	DPRINTK("EXIT\n");
+static int via_chan_set_speed (struct via_info *card,
+			       struct via_channel *chan, int val)
+{
+	DPRINTK ("ENTER, requested rate = %d\n", val);
+
+	via_chan_clear (chan);
+
+	val = via_set_rate (card, val, chan == &card->ch_in);	
+	
+	DPRINTK ("EXIT, returning %d\n", val);
+	return val;
 }
 
 
-static int __init via_probe_sb(struct address_info *hw_config)
+static int via_chan_set_fmt (struct via_info *card,
+			     struct via_channel *chan, int val)
 {
-	DPRINTK ("ENTER\n");
-
-	if (check_region(hw_config->io_base, 16))
-	{
-		printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
-		       hw_config->io_base);
-		return 0;
+	DPRINTK ("ENTER, val=%s\n",
+		 val == AFMT_U8 ? "AFMT_U8" :
+	 	 val == AFMT_S16_LE ? "AFMT_S16_LE" :
+		 "unknown");
+
+	via_chan_clear (chan);
+	
+	switch (val) {
+	case AFMT_U8:
+		chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;
+		via_chan_pcm_fmt (card, chan, 0);
+		break;
+	case AFMT_S16_LE:
+		chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
+		via_chan_pcm_fmt (card, chan, 0);
+		break;
+	default:
+		printk (KERN_WARNING PFX "unknown AFMT\n");
+		val = -EINVAL;
+		break;
 	}
-	DPRINTK("EXIT after sb_dsp_detect\n");
-	return sb_dsp_detect(hw_config, 0, 0, NULL);
+	
+	DPRINTK ("EXIT, returning %d\n", val);
+	return val;
 }
 
 
-static void __exit via_unload_sb(struct address_info *hw_config)
+static int via_chan_set_stereo (struct via_info *card,
+			        struct via_channel *chan, int val)
 {
-	DPRINTK ("ENTER\n");
+	DPRINTK ("ENTER, channels = %d\n", val);
 
-	if(hw_config->slots[0] != -1)
-		sb_dsp_unload(hw_config, 1);
+	via_chan_clear (chan);
+	
+	switch (val) {
 
-	DPRINTK("EXIT\n");
+	/* mono */
+	case 1:
+		chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
+		via_chan_pcm_fmt (card, chan, 0);
+		break;
+
+	/* stereo */
+	case 2:
+		chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
+		via_chan_pcm_fmt (card, chan, 0);
+		break;
+
+	/* unknown */
+	default:
+		printk (KERN_WARNING PFX "unknown number of channels\n");
+		val = -EINVAL;
+		break;
+	}
+	
+	DPRINTK ("EXIT, returning %d\n", val);
+	return val;
 }
 
 
-static const struct {
-	int sb_irq,
-	    sb_dma,
-	    midi_base,
-	    sb_io_base;
-} via_pnp_data[] __initdata = {
-	{ 5, 0, 0x300, 0x220 },
-	{ 7, 1, 0x310, 0x240 },
-	{ 9, 2, 0x320, 0x260 },
-	{ 10,3, 0x330, 0x280 },
-};
+#if 0
+static void via_chan_dump_bufs (struct via_channel *chan)
+{
+	int i;
+	
+	for (i = 0; i < VIA_DMA_BUFFERS; i++) {
+		DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
+			 i, chan->sgtable[i].addr,
+			 chan->sgtable[i].count & 0x00FFFFFF,
+			 chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
+			 chan->sgtable[i].count & VIA_EOL ? 1 : 0);
+	}
+	DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
+		 atomic_read (&chan->buf_in_use),
+		 atomic_read (&chan->next_buf));
+}
+#endif
 
 
 /****************************************************************
  *
- * Chip setup and kernel registration
+ * Interface to ac97-codec module
  *
  *
  */
-
-static int __init via82cxxx_install (struct pci_dev *pcidev)
+ 
+static u8 via_ac97_wait_idle (struct via_info *card)
 {
-	int sb_io_base;
-	int sb_irq;
-	int sb_dma;
-	int midi_base, rc;
 	u8 tmp8;
-	struct via_info *card = &cards[num_cards];
+	int counter = VIA_COUNTER_LIMIT;
 	
-	DPRINTK ("ENTER\n");
+	DPRINTK ("ENTER/EXIT\n");
 
-	card->pdev = pcidev;
-	card->have_ac97 = -1;
+	assert (card != NULL);
+	assert (card->pdev != NULL);
 	
-	/* turn off legacy features, if not already */
-	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
-	tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
-		  VIA_CR42_FM_ENABLE);
-	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+	do {
+		if (current->need_resched)
+			schedule ();
+		else
+			udelay (10);
+
+		spin_lock_irq (&card->lock);
+		tmp8 = inb (card->baseaddr + 0x83);
+		spin_unlock_irq (&card->lock);
+	} while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));
 
-	/* 
-	 * try to init AC97 mixer device
+	return tmp8;
+}
+
+
+static u32 via_ac97_wait_valid (struct via_info *card)
+{
+	u32 tmp;
+	int counter = VIA_COUNTER_LIMIT;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	assert (card->pdev != NULL);
+	
+	do {
+		if (current->need_resched)
+			schedule ();
+
+		spin_lock_irq (&card->lock);
+		tmp = inl (card->baseaddr + VIA_BASE0_AC97_CTRL);
+		spin_unlock_irq (&card->lock);
+		
+		udelay (10);
+
+		if (tmp & VIA_CR80_FIRST_CODEC_VALID) {
+			DPRINTK ("EXIT valid, tmp=0x%X, cnt=%d\n", tmp, counter);
+			return tmp;
+		}
+	} while ((tmp & VIA_CR80_BUSY) && (counter-- > 0));
+
+	DPRINTK ("EXIT, tmp=0x%X, cnt=%d%s\n", tmp, counter, 
+		 counter > 0 ? "" : ", counter limit reached");
+	return tmp;
+}
+
+
+static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
+{
+	u32 data;
+	struct via_info *card;
+	int counter;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (codec != NULL);
+	assert (codec->private_data != NULL);
+
+	card = codec->private_data;
+
+	data = (reg << 16) | VIA_CR80_READ;
+
+	outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
+	udelay (20);
+
+	for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
+		if (inl (card->baseaddr + 0x80) & VIA_CR80_VALID)
+			goto out;
+		udelay(10);
+		if (current->need_resched)
+			schedule ();
+	}
+
+	printk (KERN_WARNING PFX "timeout while reading AC97 codec\n");
+	goto err_out;
+
+out:
+	data = inl (card->baseaddr + 0x80);
+	outb (0x02, card->baseaddr + 0x83);
+
+	if (((data & 0x007F0000) >> 16) == reg) {
+		DPRINTK ("EXIT, success, data=0x%x, retval=0x%x\n",
+			 data, data & 0x0000FFFF);
+		return data & 0x0000FFFF;
+	}
+
+	DPRINTK ("WARNING: not our index: reg=0x%x, newreg=0x%x\n",
+		 reg, ((data & 0x007F0000) >> 16));
+
+err_out:
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
+{
+	u32 data;
+	struct via_info *card;
+	int counter;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (codec != NULL);
+	assert (codec->private_data != NULL);
+
+	card = codec->private_data;
+
+	data = (reg << 16) + value;
+	outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
+	udelay (20);
+
+	for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
+		if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)
+			goto out;
+		udelay(10);
+		if (current->need_resched)
+			schedule ();
+	}
+	
+	printk (KERN_WARNING PFX "timeout after AC97 codec write\n");
+
+out:
+	DPRINTK ("EXIT\n");
+}
+
+
+static int via_mixer_open (struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct via_info *card;
+	struct pci_dev *pdev;
+	struct pci_driver *drvr;
+	
+	DPRINTK ("ENTER\n");
+
+	MOD_INC_USE_COUNT;
+
+	pci_for_each_dev(pdev) {
+		drvr = pci_dev_driver (pdev);
+		if (drvr == &via_driver) {
+			assert (pdev->driver_data != NULL);
+			
+			card = pdev->driver_data;
+			if (card->ac97.dev_mixer == minor)
+				goto match;
+		}
+	}
+
+	DPRINTK ("EXIT, returning -ENODEV\n");
+	MOD_DEC_USE_COUNT;
+	return -ENODEV;
+
+match:
+	file->private_data = &card->ac97;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static int via_mixer_release (struct inode *inode, struct file *file)
+{
+	DPRINTK ("ENTER\n");
+
+	MOD_DEC_USE_COUNT;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct ac97_codec *codec = file->private_data;
+	int rc;
+
+	assert (codec != NULL);
+	
+	rc = codec->mixer_ioctl(codec, cmd, arg);
+	
+	return rc;
+}
+
+
+static loff_t via_llseek(struct file *file, loff_t offset, int origin)
+{
+	DPRINTK ("ENTER\n");
+
+	DPRINTK("EXIT, returning -ESPIPE\n");
+	return -ESPIPE;
+}
+
+
+static struct file_operations via_mixer_fops = {
+	open:		via_mixer_open,
+	release:	via_mixer_release,
+	llseek:		via_llseek,
+	ioctl:		via_mixer_ioctl,
+};
+
+
+static struct {
+	u8 reg;
+	u16 data;
+} mixer_init_vals[] __devinitdata = {
+	{ 0x2, 0x404 },
+	{ 0x4, 0x404 },
+	{ 0x6, 0x404 },
+	{ 0x18, 0x404 },
+	{ 0x10, 0x404 },
+	{ 0x1a, 0x404 },
+	{ 0x1c, 0x404 },
+	{ 0x1a, 0x404 },
+	{ 0x1c, 0xc0c },
+	{ 0x12, 0x808 },
+	{ 0x10, 0x808 },
+	{ 0xe, 0x2 },
+	{ 0x2, 0x808 },
+	{ 0x18, 0x808 },
+};
+
+
+static int __init via_ac97_reset (struct via_info *card)
+{
+	struct pci_dev *pdev = card->pdev;
+	u8 tmp8;
+	u16 tmp16;
+	size_t idx;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (pdev != NULL);
+	
+#ifndef NDEBUG
+	{
+		u8 r40,r41,r42,r43,r44,r48;
+		pci_read_config_byte (card->pdev, 0x40, &r40);
+		pci_read_config_byte (card->pdev, 0x41, &r41);
+		pci_read_config_byte (card->pdev, 0x42, &r42);
+		pci_read_config_byte (card->pdev, 0x43, &r43);
+		pci_read_config_byte (card->pdev, 0x44, &r44);
+		pci_read_config_byte (card->pdev, 0x48, &r48);
+		DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+			r40,r41,r42,r43,r44,r48);
+
+		spin_lock_irq (&card->lock);
+		DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
+			 inb (card->baseaddr + 0x00),
+			 inb (card->baseaddr + 0x01),
+			 inb (card->baseaddr + 0x02),
+			 inl (card->baseaddr + 0x04),
+			 inl (card->baseaddr + 0x0C),
+			 inl (card->baseaddr + 0x80),
+			 inl (card->baseaddr + 0x84));
+		spin_unlock_irq (&card->lock);
+		
+	}
+#endif
+
+#if 1
+
+        /*
+         * reset AC97 controller: enable, disable, enable
+         * pause after each command for good luck
+         */
+        pci_write_config_byte (pdev, VIA_ACLINK_CTRL, VIA_CR41_AC97_ENABLE |
+                               VIA_CR41_AC97_RESET | VIA_CR41_AC97_WAKEUP);
+        udelay (100);
+ 
+        pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
+        udelay (100);
+ 
+        pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
+			       VIA_CR41_AC97_ENABLE | VIA_CR41_PCM_ENABLE |
+                               VIA_CR41_VRA | VIA_CR41_AC97_RESET);
+        udelay (100);
+#endif
+
+#if 0
+	/*
+	 * reset AC97 controller
 	 */
-	rc = via_attach_ac97 (card);
+	pci_read_config_byte(pdev, 0x08, &tmp8);
+	if ((tmp8 & 0xff) >= 0x20 ) {
+		pci_read_config_byte(pdev, 0x42, &tmp8);
+		pci_write_config_byte(pdev, 0x42,(tmp8 & 0x3f));
+	}
+	udelay (100);
+
+	/* init other mixer defaults */
+	for (idx = 0; idx < arraysize(mixer_init_vals); idx++) {
+		via_ac97_write_reg (&card->ac97,
+				    mixer_init_vals[idx].reg,
+				    mixer_init_vals[idx].data);
+		udelay (20);
+	}
+	
+	pci_write_config_byte (pdev, 0x41, 0xc0);
+	udelay (10);
+	pci_read_config_byte (pdev, 0x41, &tmp8);
+	udelay (10);
+	pci_write_config_byte (pdev, 0x41, tmp8 | 0x0f);
+	udelay (10);
+
+#endif
+
+	/* disable legacy stuff */
+	pci_write_config_byte (pdev, 0x42, 0x00);
+	udelay(10);
+
+	/* route FM trap to IRQ, disable FM trap */
+	pci_write_config_byte (pdev, 0x48, 0x05);
+	udelay(10);
+	
+	/* disable all codec GPI interrupts */
+	outl (0, pci_resource_start (pdev, 0) + 0x8C);
+
+#if 0 /* ALSA */
+	via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, 0x0009);
+#if 0
+	via_ac97_write_reg (&card->ac97, AC97_POWER_CONTROL,
+		via_ac97_read_reg (&card->ac97, AC97_POWER_CONTROL) | 0x0300);
+#endif
+	via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS,
+		via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS) | 0xe800);
+#endif
+
+	/* enable variable rate */
+	tmp16 = via_ac97_read_reg (&card->ac97, 0x2A);
+	via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | 0x01);
+	
+	/* boost headphone vol if disabled */
+	tmp16 = via_ac97_read_reg (&card->ac97, AC97_HEADPHONE_VOL);
+	if (tmp16 == 0)
+		via_ac97_write_reg (&card->ac97, AC97_HEADPHONE_VOL, 0x1F1F);
+	
+	pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
+	if ((tmp8 & (VIA_CR41_AC97_ENABLE | VIA_CR41_AC97_RESET)) == 0) {
+		printk (KERN_ERR PFX "cannot enable AC97 controller, aborting\n");
+		DPRINTK ("EXIT, tmp8=%X, returning -ENODEV\n", tmp8);
+		return -ENODEV;
+	}
+	
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static int __init via_ac97_init (struct via_info *card)
+{
+	int rc;
+	u16 tmp16;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+
+	memset (&card->ac97, 0, sizeof (card->ac97));	
+	card->ac97.private_data = card;
+	card->ac97.codec_read = via_ac97_read_reg;
+	card->ac97.codec_write = via_ac97_write_reg;
+	
+	card->ac97.dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
+	if (card->ac97.dev_mixer < 0) {
+		printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
+		DPRINTK("EXIT, returning -EIO\n");
+		return -EIO;
+	}
+
+	rc = via_ac97_reset (card);
 	if (rc) {
-		printk (KERN_WARNING PFX
-			"AC97 init failed, SB legacy mode only\n");
+		printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
+		goto err_out;
+	}
+
+	if (ac97_probe_codec (&card->ac97) == 0) {
+		printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
+		rc = -EIO;
+		goto err_out;
+	}
+
+	tmp16 = via_ac97_read_reg (&card->ac97, 0x2A);
+	via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | 0x01);
+	
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out:
+	unregister_sound_mixer (card->ac97.dev_mixer);
+	DPRINTK("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+
+static void via_ac97_cleanup (struct via_info *card)
+{
+	DPRINTK("ENTER\n");
+	
+	assert (card != NULL);
+	assert (card->ac97.dev_mixer >= 0);
+	
+	unregister_sound_mixer (card->ac97.dev_mixer);
+
+	DPRINTK("EXIT\n");
+}
+
+
+
+/****************************************************************
+ *
+ * Interrupt-related code
+ *
+ */
+ 
+static inline void via_interrupt_write (struct via_channel *chan)
+{
+	assert (atomic_read(&chan->buf_in_use) <
+		atomic_read(&chan->next_buf));
+
+	/* XXX sanity check: read h/w counter to 
+	 * ensure no lost frames */
+
+	atomic_inc (&chan->buf_in_use);
+
+	/* if SG ptr catches up with userland ptr, stop playback */
+	if (atomic_read(&chan->buf_in_use) == atomic_read(&chan->next_buf)) {
+		atomic_set (&chan->state, sgd_stopped);
+		via_chan_stop (chan->iobase);
+	}
+
+	/* wake up anybody listening */
+	if (waitqueue_active (&chan->wait))
+		wake_up (&chan->wait);
+}
+
+
+
+static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct via_info *card = dev_id;
+	struct via_channel *chan;
+	u8 status;
+	int unhandled = 1;
+	static long intcount = 0;
+
+	assert (irq == card->pdev->irq);
+	
+	intcount++;
+	
+	status = inb (card->baseaddr + 0x00);
+	if (status) {
+		assert (card->open_mode & FMODE_WRITE);
+		
+		chan = &card->ch_out;
+		unhandled = 0;
+		
+		if (status & VIA_SGD_FLAG) {
+			assert ((status & VIA_SGD_EOL) == 0);
+			outb (VIA_SGD_FLAG, chan->iobase + 0x00);
+			DPRINTK("FLAG intr, status=0x%02X, intcount=%ld\n",
+				status, intcount);
+			via_interrupt_write (chan);
+		}
+		
+		if (status & VIA_SGD_EOL) {
+			assert ((status & VIA_SGD_FLAG) == 0);
+			outb (VIA_SGD_EOL, chan->iobase + 0x00);
+			DPRINTK("EOL intr, status=0x%02X, intcount=%ld\n",
+				status, intcount);
+			via_interrupt_write (chan);
+		}
+		
+		if (status & VIA_SGD_STOPPED) {
+			outb (VIA_SGD_STOPPED, chan->iobase + 0x00);
+			DPRINTK("STOPPED intr, status=0x%02X, intcount=%ld\n",
+				status, intcount);
+		}
+
+#if 0
+		via_chan_dump_bufs (&card->ch_out);
+#endif
+	}
+	
+	if (unhandled)
+		printk (KERN_WARNING PFX "unhandled interrupt, st=%02x, st32=%08x\n",
+			status, inl (card->baseaddr + 0x84));
+}
+
+
+static void via_interrupt_disable (struct via_info *card)
+{
+	u8 tmp8;
+	unsigned long flags;
+
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	
+	spin_lock_irqsave (&card->lock, flags);
+
+	pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
+	if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
+		tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
+		pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
+	}
+
+	outb (inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE) &
+	      VIA_INT_DISABLE_MASK,
+	      card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
+	outb (inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE) &
+	      VIA_INT_DISABLE_MASK,
+	      card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
+	outb (inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE) &
+	      VIA_INT_DISABLE_MASK,
+	      card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
+
+	spin_unlock_irqrestore (&card->lock, flags);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static int via_interrupt_init (struct via_info *card)
+{
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	assert (card->pdev != NULL);
+	
+	/* check for sane IRQ number. can this ever happen? */
+	if (card->pdev->irq < 2) {
+		printk (KERN_ERR PFX "insane IRQ %d, aborting\n",
+			card->pdev->irq);
+		DPRINTK ("EXIT, returning -EIO\n");
+		return -EIO;
+	}
+	
+	if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {
+		printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
+			card->pdev->irq);
+		DPRINTK ("EXIT, returning -EBUSY\n");
+		return -EBUSY;
+	}
+
+	/* we don't want interrupts until we're opened */
+	via_interrupt_disable (card);
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static void via_interrupt_cleanup (struct via_info *card)
+{
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	assert (card->pdev != NULL);
+
+	via_interrupt_disable (card);
+
+	free_irq (card->pdev->irq, card);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+/****************************************************************
+ *
+ * OSS DSP device
+ *
+ */
+ 
+static struct file_operations via_dsp_fops = {
+	open:		via_dsp_open,
+	release:	via_dsp_release,
+	read:		via_dsp_read,
+	write:		via_dsp_write,
+	poll:		via_dsp_poll,
+	llseek: 	via_llseek,
+	ioctl:		via_dsp_ioctl,
+};
+
+
+static int __init via_dsp_init (struct via_info *card)
+{
+	u8 tmp8;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+
+	/* turn off legacy features, if not already */
+	pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
+	tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+		  VIA_CR42_FM_ENABLE);
+	pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
+
+	via_stop_everything (card);
+
+	card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);
+	if (card->dev_dsp < 0) {
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		return -ENODEV;
+	}
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static void via_dsp_cleanup (struct via_info *card)
+{
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	assert (card->dev_dsp >= 0);
+
+	via_stop_everything (card);
+
+	unregister_sound_dsp (card->dev_dsp);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static ssize_t via_dsp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct via_info *card;
+
+	DPRINTK ("ENTER\n");
+	
+	assert (file != NULL);
+	assert (buffer != NULL);
+	card = file->private_data;
+	assert (card != NULL);
+
+	DPRINTK("EXIT, returning -EINVAL\n");
+	return -EINVAL;
+}
+
+
+
+#define sgcount(n) (sgtable[(n)].count & 0x00FFFFFF)
+#define NEXTBUF (atomic_read(&chan->next_buf) % VIA_DMA_BUFFERS)
+#define BUF_IN_USE (atomic_read(&chan->buf_in_use) % VIA_DMA_BUFFERS)
+#define STATE_STOPPED (atomic_read (state) == sgd_stopped)
+#define STATE_STARTED (atomic_read (state) == sgd_in_progress)
+static ssize_t via_dsp_do_write (struct via_info *card,
+				 const char *userbuf, size_t count,
+				 int non_blocking)
+{
+	const char *orig_userbuf = userbuf;
+	struct via_channel *chan = &card->ch_out;
+	volatile struct via_sgd_table *sgtable = chan->sgtable;
+	atomic_t *state = &chan->state;
+	size_t size;
+	int nextbuf, prevbuf, n, realcount;
+	ssize_t rc;
+	
+	while (count > 0) {
+		if (current->need_resched)
+			schedule ();
+
+		spin_lock_irq (&card->lock);
+		DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
+			 inb (card->baseaddr + 0x00),
+			 inb (card->baseaddr + 0x01),
+			 inb (card->baseaddr + 0x02),
+			 inl (card->baseaddr + 0x04),
+			 inl (card->baseaddr + 0x0C),
+			 inl (card->baseaddr + 0x80),
+			 inl (card->baseaddr + 0x84));
+		spin_unlock_irq (&card->lock);
+		
+		size = (count < VIA_DMA_BUF_SIZE) ? count : VIA_DMA_BUF_SIZE;
+
+		/* case 1: SGD not active, list is ours for the mangling */
+
+		if (STATE_STOPPED) {
+			DPRINTK ("case 1\n");
+
+			if (copy_from_user ((void*)chan->sgbuf[0].cpuaddr,
+					     userbuf, size))
+				return -EFAULT;
+
+			assert (sgtable[0].addr == cpu_to_le32 (chan->sgbuf[0].handle));
+			sgtable[0].count = size | VIA_FLAG;
+
+			atomic_set (state, sgd_in_progress);
+			atomic_set (&chan->buf_in_use, 0);
+			atomic_set (&chan->next_buf, 1);
+			
+			count -= size;
+			userbuf += size;
+
+			spin_lock_irq (&card->lock);
+			sg_begin (chan);
+			spin_unlock_irq (&card->lock);
+
+			continue;
+		}
+
+		nextbuf = NEXTBUF;
+		if (nextbuf)
+			prevbuf = nextbuf - 1;
+		else
+			prevbuf = VIA_DMA_BUFFERS - 1;
+
+		/* case 2: if final buffer is (a) a fragment, and (b) not
+		 * currently being consumed by the SGD engine, then append
+		 * as much data as possible to the fragment. */
+
+		realcount = sgcount(prevbuf);
+		if (STATE_STARTED && (prevbuf != BUF_IN_USE) &&
+		    (realcount < VIA_DMA_BUF_SIZE)) {
+			DPRINTK ("case 2\n");
+			DPRINTK ("st=%d, fb=%d -- nb=%d, pb=%d, n=%d, rc=%d\n",
+				 atomic_read (state),
+				 BUF_IN_USE,
+				 nextbuf,
+				 prevbuf,
+				 prevbuf /* n */,
+				 realcount);
+
+			n = prevbuf;
+
+			if ((VIA_DMA_BUF_SIZE - realcount) < size)
+				size = VIA_DMA_BUF_SIZE - realcount;
+
+			if (copy_from_user ((void*)(chan->sgbuf[n].cpuaddr +
+					     realcount),
+					     userbuf, size))
+				return -EFAULT;
+
+			/* slack way to try and prevent races */
+			if (prevbuf == BUF_IN_USE || !STATE_STARTED)
+				continue;
+
+			assert (sgtable[n].addr == cpu_to_le32 (chan->sgbuf[n].handle));
+			if (n == (VIA_DMA_BUFFERS - 1))
+				sgtable[n].count = (realcount + size) | VIA_EOL;
+			else
+				sgtable[n].count = (realcount + size) | VIA_FLAG;
+
+			count -= size;
+			userbuf += size;
+			continue;
+		}
+
+		/* case 3: if there are buffers left, use one
+		 * XXX needs more review for possible races */
+
+		else if (STATE_STARTED && !via_chan_full (chan)) {
+			DPRINTK ("case 3\n");
+			DPRINTK ("st=%d, fb=%d -- nb=%d, pb=%d, n=%d\n",
+				 atomic_read (state),
+				 BUF_IN_USE,
+				 nextbuf,
+				 prevbuf,
+				 nextbuf /* n */);
+
+			n = nextbuf;
+
+			if (copy_from_user ((void*)chan->sgbuf[n].cpuaddr,
+					     userbuf, size))
+				return -EFAULT;
+
+			if (n == (VIA_DMA_BUFFERS - 1))
+				sgtable[n].count = size | VIA_EOL;
+			else
+				sgtable[n].count = size | VIA_FLAG;
+
+			/* if SGD stopped during data copy or SG table update,
+			 * then loop back to the beginning without updating
+			 * any pointers.
+			 * ie. slack way to prevent race */
+			if (!STATE_STARTED)
+				continue;
+
+			atomic_inc (&chan->next_buf);
+
+			count -= size;
+			userbuf += size;
+			continue;
+		}
+
+		/* case 4, final SGT active case: no free buffers, wait for one */
+
+		else {
+			DPRINTK ("case 4\n");
+			DPRINTK ("st=%d, fb=%d -- nb=%d, pb=%d\n",
+				 atomic_read (state),
+				 BUF_IN_USE,
+				 nextbuf,
+				 prevbuf);
+
+			/* if playback stopped, no need to sleep */
+			if (!STATE_STARTED)
+				continue;
+			
+			/* if buffer free, no need to sleep */
+			if (!via_chan_full (chan))
+				continue;
+			
+			if (non_blocking) {
+				rc = userbuf - orig_userbuf;
+				if (rc == 0)
+					rc = -EAGAIN;
+				return rc;
+			}
+
+			DPRINTK ("sleeping\n");
+			interruptible_sleep_on (&chan->wait);
+			if (signal_pending (current))
+				return -ERESTARTSYS;
+		}
+	}
+
+#if 0
+	{
+		u8 r40,r41,r42,r43,r44,r48;
+		pci_read_config_byte (card->pdev, 0x40, &r40);
+		pci_read_config_byte (card->pdev, 0x41, &r41);
+		pci_read_config_byte (card->pdev, 0x42, &r42);
+		pci_read_config_byte (card->pdev, 0x43, &r43);
+		pci_read_config_byte (card->pdev, 0x44, &r44);
+		pci_read_config_byte (card->pdev, 0x48, &r48);
+		DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+			r40,r41,r42,r43,r44,r48);
+	}
+#endif
+
+	DPRINTK ("EXIT, returning %d\n",
+		 userbuf - orig_userbuf);
+	return userbuf - orig_userbuf;
+}
+#undef sgcount
+#undef NEXTBUF
+#undef BUF_IN_USE
+#undef STATE_STOPPED
+#undef STATE_STARTED
+
+
+static ssize_t via_dsp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct via_info *card;
+	ssize_t rc;
+
+	DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
+		 file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
+	
+	assert (file != NULL);
+	assert (buffer != NULL);
+	card = file->private_data;
+	assert (card != NULL);
+
+	if (ppos != &file->f_pos) {
+		DPRINTK ("EXIT, returning -ESPIPE\n");
+		return -ESPIPE;
+	}
+
+	rc = via_dsp_do_write (card, buffer, count, (file->f_flags & O_NONBLOCK));
+
+	DPRINTK("EXIT, returning %ld\n",(long) rc);
+	return rc;
+}
+
+
+static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct via_info *card;
+	unsigned int mask = 0;
+
+	DPRINTK ("ENTER\n");
+
+	assert (file != NULL);
+	assert (wait != NULL);
+	card = file->private_data;
+	assert (card != NULL);
+
+	if ((file->f_mode & FMODE_WRITE) &&
+	    (atomic_read (&card->ch_out.state) != sgd_stopped)) {
+		poll_wait(file, &card->ch_out.wait, wait);
+		
+		/* XXX is this correct */
+		if (atomic_read (&card->ch_out.buf_in_use) <
+		    atomic_read (&card->ch_out.next_buf))
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+	DPRINTK("EXIT, returning %u\n", mask);
+	return mask;
+}
+
+
+static int via_dsp_drain_dac (struct via_info *card, int non_block)
+{
+	DPRINTK ("ENTER, non_block = %d\n", non_block);
+
+	while (!via_chan_empty (&card->ch_out)) {
+		if (non_block) {
+			DPRINTK ("EXIT, returning -EBUSY\n");
+			return -EBUSY;
+		}
+		if (signal_pending (current)) {
+			DPRINTK ("EXIT, returning -ERESTARTSYS\n");
+			return -ERESTARTSYS;
+		}
+
+#ifndef NDEBUG
+	{
+		u8 r40,r41,r42,r43,r44,r48;
+		pci_read_config_byte (card->pdev, 0x40, &r40);
+		pci_read_config_byte (card->pdev, 0x41, &r41);
+		pci_read_config_byte (card->pdev, 0x42, &r42);
+		pci_read_config_byte (card->pdev, 0x43, &r43);
+		pci_read_config_byte (card->pdev, 0x44, &r44);
+		pci_read_config_byte (card->pdev, 0x48, &r48);
+		DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+			r40,r41,r42,r43,r44,r48);
+
+		spin_lock_irq (&card->lock);
+		DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
+			 inb (card->baseaddr + 0x00),
+			 inb (card->baseaddr + 0x01),
+			 inb (card->baseaddr + 0x02),
+			 inl (card->baseaddr + 0x04),
+			 inl (card->baseaddr + 0x0C),
+			 inl (card->baseaddr + 0x80),
+			 inl (card->baseaddr + 0x84));
+		spin_unlock_irq (&card->lock);
+		
+	}
+#endif
+
+		DPRINTK ("sleeping\n");		
+		interruptible_sleep_on (&card->ch_out.wait);
+	}
+	
+	DPRINTK ("EXIT\n");
+	return 0;
+}
+
+
+static int via_dsp_ioctl_space (struct via_info *card,
+				struct via_channel *chan,
+				void *arg)
+{
+	audio_buf_info info;
+	int n;
+
+	info.fragstotal = VIA_DMA_BUFFERS;
+	info.fragsize = VIA_DMA_BUF_SIZE;
+
+	/* number of full fragments we can read without blocking */
+	n = atomic_read (&chan->next_buf) - atomic_read (&chan->buf_in_use);
+	info.fragments = VIA_DMA_BUFFERS - n;
+
+	/* number of bytes that can be read or written immediately
+	 * without blocking.  FIXME: we are lazy and ignore partially-full
+	 * buffers.
+	 */
+	info.bytes = info.fragments * VIA_DMA_BUF_SIZE;
+
+	DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
+		info.fragstotal,
+		info.fragsize,
+		info.fragments,
+		info.bytes);
+
+	return copy_to_user (arg, &info, sizeof (info));
+}
+
+
+
+static int via_dsp_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int rc = -EINVAL, rd=0, wr=0, val=0;
+	struct via_info *card;
+
+	DPRINTK ("ENTER, cmd = 0x%08X\n", cmd);
+
+	assert (file != NULL);
+	card = file->private_data;
+	assert (card != NULL);
+
+	if (file->f_mode & FMODE_WRITE)
+		wr = 1;
+	if (file->f_mode & FMODE_READ)
+		rd = 1;
+	
+	switch (cmd) {
+
+	/* OSS API version.  XXX unverified */		
+	case OSS_GETVERSION:
+		DPRINTK("EXIT, returning SOUND_VERSION\n");
+		return put_user (SOUND_VERSION, (int *)arg);
+
+	/* list of supported PCM data formats */
+	case SNDCTL_DSP_GETFMTS:
+		DPRINTK("EXIT, returning AFMT U8|S16_LE\n");
+                return put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg);
+
+	/* query or set current channel's PCM data format */
+	case SNDCTL_DSP_SETFMT:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			rc = 0;
+
+			spin_lock_irq (&card->lock);
+			if (rc == 0 && rd)
+				rc = via_chan_set_fmt (card, &card->ch_in, val);
+			if (rc == 0 && wr)
+				rc = via_chan_set_fmt (card, &card->ch_out, val);
+			spin_unlock_irq (&card->lock);
+
+			if (rc <= 0)
+				return rc ? rc : -EINVAL;
+			val = rc;
+		} else {
+			spin_lock_irq (&card->lock);
+			if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
+			    (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))
+				val = AFMT_S16_LE;
+			else
+				val = AFMT_U8;
+			spin_unlock_irq (&card->lock);
+		}
+		DPRINTK("SETFMT EXIT, returning %d\n", val);
+                return put_user (val, (int *)arg);
+
+	/* query or set number of channels (1=mono, 2=stereo) */
+        case SNDCTL_DSP_CHANNELS:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			rc = 0;
+			spin_lock_irq (&card->lock);
+			if (rc == 0 && rd)
+				rc = via_chan_set_stereo (card, &card->ch_in, val);
+			if (rc == 0 && wr)
+				rc = via_chan_set_stereo (card, &card->ch_out, val);
+			spin_unlock_irq (&card->lock);
+			if (rc <= 0)
+				return rc ? rc : -EINVAL;
+			val = rc;
+		} else {
+			spin_lock_irq (&card->lock);
+			if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) ||
+			    (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_STEREO)))
+				val = 2;
+			else
+				val = 1;
+			spin_unlock_irq (&card->lock);
+		}
+		DPRINTK("CHANNELS EXIT, returning %d\n", val);
+                return put_user (val, (int *)arg);
+	
+	/* enable (val is not zero) or disable (val == 0) stereo */
+        case SNDCTL_DSP_STEREO:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		rc = 0;
+		spin_lock_irq (&card->lock);
+		if (rc == 0 && rd)
+			rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
+		if (rc == 0 && wr)
+			rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
+		spin_unlock_irq (&card->lock);
+		if (rc <= 0)
+			return rc ? rc : -EINVAL;
+		DPRINTK("STEREO EXIT, returning %d\n", val);
+                return 0;
+	
+	/* query or set sampling rate */
+        case SNDCTL_DSP_SPEED:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val < 0)
+			return -EINVAL;
+		if (val > 0) {
+			rc = 0;
+			spin_lock_irqsave (&card->lock, flags);
+			if (rc == 0 && rd)
+				rc = via_chan_set_speed (card, &card->ch_in, val);
+			if (rc == 0 && wr)
+				rc = via_chan_set_speed (card, &card->ch_out, val);
+			spin_unlock_irqrestore (&card->lock, flags);
+			if (rc <= 0)
+				return rc ? rc : -EINVAL;
+			val = rc;
+		} else {
+			spin_lock_irqsave (&card->lock, flags);
+			if (rd)
+				val = card->ch_in.rate;
+			else if (wr)
+				val = card->ch_out.rate;
+			else
+				val = 0;
+			spin_unlock_irqrestore (&card->lock, flags);
+		}
+		DPRINTK("SPEED EXIT, returning %d\n", val);
+                return put_user (val, (int *)arg);
+	
+	/* wait until all buffers have been played, and then stop device */
+	case SNDCTL_DSP_SYNC:
+		if (wr) {
+			DPRINTK("SYNC EXIT (after calling via_dsp_drain_dac)\n");
+			return via_dsp_drain_dac (card, file->f_flags & O_NONBLOCK);
+		}
+		break;
+
+	/* stop recording/playback immediately */
+        case SNDCTL_DSP_RESET:
+		if (rd) {
+			spin_lock_irqsave (&card->lock, flags);
+			via_chan_clear (&card->ch_in);
+			via_chan_pcm_fmt (card, &card->ch_in, 1);
+			spin_unlock_irqrestore (&card->lock, flags);
+		}
+		if (wr) {
+			spin_lock_irqsave (&card->lock, flags);
+			via_chan_clear (&card->ch_out);
+			via_chan_pcm_fmt (card, &card->ch_out, 1);
+			spin_unlock_irqrestore (&card->lock, flags);
+		}
+		DPRINTK("RESET EXIT, returning 0\n");
+		return 0;
+
+	/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
+	case SNDCTL_DSP_GETCAPS:
+		DPRINTK("GETCAPS EXIT\n");
+		return put_user(DSP_CAP_REVISION, (int *)arg);
+		
+	/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
+	case SNDCTL_DSP_GETBLKSIZE:
+		DPRINTK("GETBLKSIZE EXIT\n");
+		return put_user(VIA_DMA_BUF_SIZE, (int *)arg);
+		
+	/* obtain information about input buffering */
+	case SNDCTL_DSP_GETISPACE:
+		DPRINTK("GETISPACE EXIT\n");
+		return via_dsp_ioctl_space (card, &card->ch_in, (void*) arg);
+	
+	/* obtain information about output buffering */
+	case SNDCTL_DSP_GETOSPACE:
+		DPRINTK("GETOSPACE EXIT\n");
+		return via_dsp_ioctl_space (card, &card->ch_out, (void*) arg);
+
+	/* return number of bytes remaining to be played by DMA engine */
+	case SNDCTL_DSP_GETODELAY:
+		{
+		int n;
+		
+		n = atomic_read (&card->ch_out.next_buf) -
+		    atomic_read (&card->ch_out.buf_in_use);
+		assert (n >= 0);
+
+		if (n == 0)
+			val = 0;
+		else {
+			val = (n - 1) * VIA_DMA_BUF_SIZE;
+			val += inl (card->ch_out.iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);
+		}
+		
+		DPRINTK("GETODELAY EXIT, val = %d bytes\n", val);
+                return put_user (val, (int *)arg);
+		}
+
+	/* set fragment size.  implemented as a successful no-op for now */
+	case SNDCTL_DSP_SETFRAGMENT:
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
+			 val & 0xFFFF,
+			 val & 0xFFFF,
+			 (val >> 16) & 0xFFFF,
+			 (val >> 16) & 0xFFFF);
+
+		/* just to shut up some programs */
+		return 0;
+
+	/* inform device of an upcoming pause in input (or output).  not implemented */
+	case SNDCTL_DSP_POST:
+		DPRINTK("POST EXIT (null ioctl, returning -EINVAL)\n");
+                return -EINVAL;
+
+	/* not implemented */
+	default:
+		DPRINTK ("unhandled ioctl\n");
+		break;
 	}
+		
+	DPRINTK("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+
+static int via_dsp_open (struct inode *inode, struct file *file)
+{
+	int open_mode, rc = -EINVAL, minor = MINOR(inode->i_rdev);
+	int got_read_chan = 0, is_busy;
+	struct via_info *card;
+	struct pci_dev *pdev;
+	struct pci_driver *drvr;
+	unsigned long flags;
+
+	DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
 	
-	/* turn on legacy features */
-	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
-	tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
-		VIA_CR42_FM_ENABLE;
-	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
-
-	/* read legacy PNP info byte */
-	pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
-	pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
-	
-	sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq;
-	sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma;
-	midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base;
-	sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base;
+	MOD_INC_USE_COUNT;
+	
+	if (file->f_mode & FMODE_READ) /* no input ATM */
+		goto err_out;
 
-	udelay(100);
+	card = NULL;
+	pci_for_each_dev(pdev) {
+		drvr = pci_dev_driver (pdev);
+		if (drvr == &via_driver) {
+			assert (pdev->driver_data != NULL);
+			
+			card = pdev->driver_data;	
+			DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n",
+				 card->dev_dsp, minor,
+				 (card->dev_dsp ^ minor) & ~0xf);
+
+			if (((card->dev_dsp ^ minor) & ~0xf) == 0)
+				goto match;
+		}
+	}
 	
-	printk(KERN_INFO PFX "legacy "
-	       "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
-		midi_base, sb_io_base, sb_irq, sb_dma);
-		
-	card->sb_data.name = VIA_CARD_NAME;
-	card->sb_data.card_subtype = MDL_SBPRO;
-	card->sb_data.io_base = sb_io_base;
-	card->sb_data.irq = sb_irq;
-	card->sb_data.dma = sb_dma;
-	
-	/* register legacy SoundBlaster Pro */
-	if (!via_probe_sb (&card->sb_data)) {
-		printk (KERN_ERR PFX
-			"SB probe @ 0x%X failed, aborting\n",
-			sb_io_base);
-		DPRINTK ("EXIT, returning -1\n");
-		return -1;
-	}
-	via_attach_sb (&card->sb_data);
-
-	card->opl3_data.name = card->sb_data.name;
-	card->opl3_data.io_base = midi_base;
-	card->opl3_data.irq = -1;
-	
-	/* register legacy MIDI */
-	if (!probe_uart401 (&card->opl3_data)) {
-		printk (KERN_WARNING PFX
-			"MIDI probe @ 0x%X failed, continuing\n",
-			midi_base);
-		card->opl3_data.io_base = 0;
-	} else {
-		attach_uart401 (&card->opl3_data);
+	DPRINTK ("no matching %s found\n", card ? "minor" : "driver");
+	rc = -ENODEV;
+	goto err_out;
+
+match:
+	file->private_data = card;
+
+	/* wait for device to become free */
+	spin_lock_irqsave (&card->lock, flags);
+	open_mode = card->open_mode;
+	if (open_mode & file->f_mode)
+		is_busy = 1;
+	else {
+		is_busy = 0;
+		card->open_mode |= file->f_mode;
+		open_mode = card->open_mode;
+	}
+	spin_unlock_irqrestore (&card->lock, flags);
+	if (is_busy) {
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	DPRINTK("open_mode now 0x%x\n", open_mode);
+
+	/* handle input from analog source */
+	if (file->f_mode & FMODE_READ) {
+		rc = via_chan_init (card, &card->ch_in, 0x10);
+		if (rc)
+			goto err_out_clear_mode;
+			
+		got_read_chan = 1;
+		
+		/* why is this forced to 16-bit stereo in all drivers? */
+		card->ch_in.pcm_fmt =
+			VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
+
+		spin_lock_irqsave (&card->lock, flags);
+		via_chan_pcm_fmt (card, &card->ch_out, 0);
+		spin_unlock_irqrestore (&card->lock, flags);
+
+		via_set_adc_rate (card, 8000);
+	}
+
+	/* handle output to analog source */
+	if (file->f_mode & FMODE_WRITE) {
+		rc = via_chan_init (card, &card->ch_out, 0x00);
+		if (rc)
+			goto err_out_clear_mode;
+		
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			card->ch_out.pcm_fmt |= VIA_PCM_FMT_16BIT;
+
+		spin_lock_irqsave (&card->lock, flags);
+		via_chan_pcm_fmt (card, &card->ch_out, 0);
+		spin_unlock_irqrestore (&card->lock, flags);
+
+		via_set_dac_rate (card, 8000);
 	}
 
-	num_cards++;	
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
+
+err_out_clear_mode:
+	if (got_read_chan)
+		via_chan_free (card, &card->ch_in);
+	spin_lock_irqsave (&card->lock, flags);
+	card->open_mode &= ~file->f_mode;
+	spin_unlock_irqrestore (&card->lock, flags);
+err_out:
+	MOD_DEC_USE_COUNT;
+	DPRINTK("ERROR EXIT, returning %d\n", rc);
+	return rc;
 }
 
 
-/*
- * 	This loop walks the PCI configuration database and finds where
- *	the sound cards are.
+static int via_dsp_release(struct inode *inode, struct file *file)
+{
+	struct via_info *card;
+	unsigned long flags;
+
+	DPRINTK ("ENTER\n");
+	
+	assert (file != NULL);
+	card = file->private_data;
+	assert (card != NULL);
+	
+	if (file->f_mode & FMODE_READ)
+		via_chan_free (card, &card->ch_in);
+
+	if (file->f_mode & FMODE_WRITE) {
+		via_dsp_drain_dac (card, file->f_flags & O_NONBLOCK);
+		via_chan_free (card, &card->ch_out);
+	}
+			
+	spin_lock_irqsave (&card->lock, flags);
+	card->open_mode &= ~(file->f_mode);
+	spin_unlock_irqrestore (&card->lock, flags);
+
+ 	wake_up (&card->open_wait);
+	MOD_DEC_USE_COUNT;
+
+	DPRINTK("EXIT, returning 0\n");
+	return 0;
+}
+
+
+#ifdef VIA_PROC_FS
+
+/****************************************************************
+ *
+ * /proc/driver/via/info
  *
- *	Note - only a single PCI scan occurs, eliminating possibility
- *	of multiple audio chips
  *
  */
- 
-static int __init probe_via82cxxx (void)
+
+static int via_info_read_proc (char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
+#define ED(val,bit) (((val) & (bit)) ? "enable" : "disable")
+
+	int len = 0;
+	u8 r40, r41, r42, r44;
+	struct via_info *card = data;
+	u16 tmp16;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+	
+	len += sprintf (page+len, VIA_CARD_NAME "\n\n");
+	
+	pci_read_config_byte (card->pdev, 0x40, &r40);
+	pci_read_config_byte (card->pdev, 0x41, &r41);
+	pci_read_config_byte (card->pdev, 0x42, &r42);
+	pci_read_config_byte (card->pdev, 0x44, &r44);
+	
+	len += sprintf (page+len,
+		"Via 82Cxxx PCI registers:\n"
+		"\n"
+		"40  Codec Ready: %s\n"
+		"    Codec Low-power: %s\n"
+		"    Secondary Codec Ready: %s\n"
+		"\n"
+		"41  Interface Enable: %s\n"
+		"    De-Assert Reset: %s\n"
+		"    Force SYNC high: %s\n"
+		"    Force SDO high: %s\n"
+		"    Variable Sample Rate On-Demand Mode: %s\n"
+		"    SGD Read Channel PCM Data Out: %s\n"
+		"    FM Channel PCM Data Out: %s\n"
+		"    SB PCM Data Out: %s\n"
+		"\n"
+		"42  Game port enabled: %s\n"
+		"    SoundBlaster enabled: %s\n"
+		"    FM enabled: %s\n"
+		"    MIDI enabled: %s\n"
+		"\n"	
+		"44  AC-Link Interface Access: %s\n"
+		"    Secondary Codec Support: %s\n"
+			
+		"\n",
+			
+		YN (r40, VIA_CR40_AC97_READY),
+		YN (r40, VIA_CR40_AC97_LOW_POWER),
+		YN (r40, VIA_CR40_SECONDARY_READY),
+
+		ED (r41, VIA_CR41_AC97_ENABLE),
+		YN (r41, (1 << 6)),
+		YN (r41, (1 << 5)),
+		YN (r41, (1 << 4)),
+		ED (r41, (1 << 3)),
+		ED (r41, (1 << 2)),
+		ED (r41, (1 << 1)),
+		ED (r41, (1 << 0)),
+
+		YN (r42, VIA_CR42_GAME_ENABLE),
+		YN (r42, VIA_CR42_SB_ENABLE),
+		YN (r42, VIA_CR42_FM_ENABLE),
+		YN (r42, VIA_CR42_MIDI_ENABLE),
+
+		YN (r44, VIA_CR44_AC_LINK_ACCESS),
+		YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT)
+			
+		);
+
+	DPRINTK("EXIT, returning %d\n", len);
+	return len;
+
+#undef YN
+#undef ED
+}
+
+
+/****************************************************************
+ *
+ * /proc/driver/via/... setup and cleanup
+ *
+ *
+ */
+
+static int __init via_init_proc (void)
+{
+	DPRINTK ("ENTER\n");
+
+	if (!proc_mkdir ("driver/via", 0))
+		return -EIO;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static void via_cleanup_proc (void)
 {
-	struct pci_dev *pcidev = NULL;
+	DPRINTK ("ENTER\n");
+
+	remove_proc_entry ("driver/via", NULL);
+
+	DPRINTK ("EXIT\n");
+}
 
+
+static int __init via_card_init_proc (struct via_info *card)
+{
+	char s[32];
+	int rc;
+	
 	DPRINTK ("ENTER\n");
 
-	pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
-				  PCI_DEVICE_ID_VIA_82C686_5, NULL);
+	sprintf (s, "driver/via/%d", card->card_num);
+	if (!proc_mkdir (s, 0)) {
+		rc = -EIO;
+		goto err_out_none;
+	}
+	
+	sprintf (s, "driver/via/%d/info", card->card_num);
+	if (!create_proc_read_entry (s, 0, 0, via_info_read_proc, card)) {
+		rc = -EIO;
+		goto err_out_dir;
+	}
 
-	if (!pcidev || via82cxxx_install (pcidev) != 0) {
-		printk (KERN_ERR PFX "audio init failed\n");
-		DPRINTK ("EXIT, returning -1\n");
-		return -1;
+	sprintf (s, "driver/via/%d/ac97", card->card_num);
+	if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, &card->ac97)) {
+		rc = -EIO;
+		goto err_out_info;
 	}
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
+
+err_out_info:
+	sprintf (s, "driver/via/%d/info", card->card_num);
+	remove_proc_entry (s, NULL);
+
+err_out_dir:
+	sprintf (s, "driver/via/%d", card->card_num);
+	remove_proc_entry (s, NULL);
+
+err_out_none:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
 }
 
 
-/*
- *	This function is called when the user or kernel loads the 
- *	module into memory.
- */
+static void via_card_cleanup_proc (struct via_info *card)
+{
+	char s[32];
+
+	DPRINTK ("ENTER\n");
+
+	sprintf (s, "driver/via/%d/ac97", card->card_num);
+	remove_proc_entry (s, NULL);
+
+	sprintf (s, "driver/via/%d/info", card->card_num);
+	remove_proc_entry (s, NULL);
+
+	sprintf (s, "driver/via/%d", card->card_num);
+	remove_proc_entry (s, NULL);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+#else
+
+static inline int via_init_proc (void) { return 0; }
+static inline void via_cleanup_proc (void) {}
+static inline int via_card_init_proc (struct via_info *card) { return 0; }
+static inline void via_card_cleanup_proc (struct via_info *card) {}
+
+#endif /* VIA_PROC_FS */
 
 
-static int __init init_via82cxxx_module(void)
+/****************************************************************
+ *
+ * Chip setup and kernel registration
+ *
+ *
+ */
+
+static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
 {
+	int rc;
+	struct via_info *card;
 	u8 tmp;
-	int i;
-	const char *rev = "unknown!";
-	
-	memset (cards, 0, sizeof (cards));
+	static int printed_version = 0;
 	
 	DPRINTK ("ENTER\n");
+	
+	if (printed_version++ == 0)
+		printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n");
 
-	if (!pci_present ()) {
-		printk (KERN_DEBUG PFX "PCI not present, exiting\n");
-		DPRINTK ("EXIT, returning -ENODEV\n");
-		return -ENODEV;
+	if (!request_region (pci_resource_start (pdev, 0),
+	    		     pci_resource_len (pdev, 0),
+			     VIA_MODULE_NAME)) {
+		printk (KERN_ERR PFX "unable to obtain I/O resources, aborting\n");
+		rc = -EBUSY;
+		goto err_out;
 	}
 
-	if (probe_via82cxxx() != 0) {
-		printk(KERN_ERR PFX "probe failed, aborting\n");
-		/* XXX unload cards registered so far, if any */
-		DPRINTK ("EXIT, returning -ENODEV\n");
-		return -ENODEV;
+#if 0
+	/* chipset init copied from via */
+	pci_write_config_byte(pdev, 0x41,(0xc0));
+	udelay(10);
+	pci_read_config_byte(pdev, 0x41, &tmp);
+	udelay(10);
+	pci_write_config_byte(pdev, 0x41,(tmp | 0x0f));
+	udelay(10);
+	pci_read_config_byte(pdev, 0x42, &tmp);
+	udelay(10);
+	pci_write_config_byte(pdev, 0x42,(tmp | 0x3f));
+#endif
+
+	if (pci_enable_device (pdev)) {
+		rc = -EIO;
+		goto err_out_none;
+	}
+	
+#if 0
+	/* chipset init copied from ALSA */
+	pci_write_config_byte(pdev, 0x42, 0);
+	pci_write_config_byte(pdev, 0x41, 0x40);
+	udelay(100);
+	pci_write_config_byte(pdev, 0x41, 0x60);
+	udelay(10);
+	pci_write_config_byte(pdev, 0x41, 0xCC);
+	udelay(10);
+	
+	{
+	u32 data = ((AC97_POWER_CONTROL & 0x7F) << 16) | 0x0000;
+	udelay(100);
+	outl (data, pci_resource_start (pdev, 0) + VIA_BASE0_AC97_CTRL);
+	}
+#endif
+
+	card = kmalloc (sizeof (*card), GFP_KERNEL);
+	if (!card) {
+		printk (KERN_ERR PFX "out of memory, aborting\n");
+		rc = -ENOMEM;
+		goto err_out_none;
+	}
+
+	pdev->driver_data = card;
+
+	memset (card, 0, sizeof (*card));
+	card->pdev = pdev;
+	card->baseaddr = pci_resource_start (pdev, 0);
+	card->card_num = via_num_cards++;
+	spin_lock_init (&card->lock);
+	init_waitqueue_head(&card->open_wait);
+	
+	/* if BAR 2 is present, chip is Rev H or later,
+	 * which means it has a few extra features */
+	if (pci_resource_start (pdev, 2) > 0)
+		card->rev_h = 1;
+
+	if (pdev->irq < 1) {
+		printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
+		rc = -ENODEV;
+		goto err_out_kfree;
+	}
+
+	if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) {
+		printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n");
+		rc = -ENODEV;
+		goto err_out_kfree;
+	}
+	
+	/* 
+	 * init AC97 mixer and codec
+	 */
+	rc = via_ac97_init (card);
+	if (rc) {
+		printk (KERN_ERR PFX "AC97 init failed, aborting\n");
+		goto err_out_kfree;
 	}
 
-	pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp);
-	for (i = 0; i < arraysize(via_chip_revs); i++)
-		if (via_chip_revs[i].revision == tmp) {
-			rev = via_chip_revs[i].rev_name;
-			break;
-		}
-	printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
-	printk (KERN_INFO PFX "Chip rev %s.  Features: SBPro compat%s%s\n",
-		rev,
-		cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI",
-		cards[0].have_ac97 == -1 ? "" : ", AC97 mixer");
-	
-	if (via_init_proc () != 0) {
-		printk (KERN_WARNING PFX
-			"Unable to init experimental /proc, ignoring\n");
+	/*
+	 * init DSP device
+	 */
+	rc = via_dsp_init (card);
+	if (rc) {
+		printk (KERN_ERR PFX "DSP device init failed, aborting\n");
+		goto err_out_have_mixer;
+	}
+	
+	/*
+	 * per-card /proc info
+	 */	
+	rc = via_card_init_proc (card);
+	if (rc) {
+		printk (KERN_ERR PFX "card-specific /proc init failed, aborting\n");
+		goto err_out_have_dsp;
 	}
 
 	/*
-	 *	Binds us to the sound subsystem	
+	 * init and turn on interrupts, as the last thing we do
 	 */
-	SOUND_LOCK;
+	rc = via_interrupt_init (card);
+	if (rc) {
+		printk (KERN_ERR PFX "interrupt init failed, aborting\n");
+		goto err_out_have_proc;
+	}
+	
+	pci_read_config_byte (pdev, 0x3C, &tmp);
+	if ((tmp & 0x0F) != pdev->irq) {
+		printk (KERN_WARNING PFX "IRQ fixup, 0x3C==0x%02X\n", tmp);
+		tmp &= 0xF0;
+		tmp |= pdev->irq;
+		pci_write_config_byte (pdev, 0x3C, tmp);
+		DPRINTK("new 0x3c==0x%02x\n", tmp);
+	} else {
+		DPRINTK("IRQ reg 0x3c==0x%02x, irq==%d\n",
+			tmp, tmp & 0x0F);
+	}
+
+	printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
+		card->card_num + 1, card->baseaddr, pdev->irq);
+	
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
+
+err_out_have_proc:
+	via_card_cleanup_proc (card);
+
+err_out_have_dsp:
+	via_dsp_cleanup (card);
+
+err_out_have_mixer:
+	via_ac97_cleanup (card);
+
+err_out_kfree:
+#ifndef VIA_NDEBUG
+	memset (card, 0xAB, sizeof (*card)); /* poison memory */
+#endif
+	kfree (card);
+
+err_out_none:
+	release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));
+err_out:
+	pdev->driver_data = NULL;
+	DPRINTK ("EXIT - returning %d\n", rc);
+	return rc;
 }
 
-/*
- *	This is called when it is removed. It will only be removed 
- *	when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
- *	macros hide the entire work for this.
- */
- 
-static void __exit cleanup_via82cxxx_module(void)
+
+static void __exit via_remove_one (struct pci_dev *pdev)
 {
-	DPRINTK("ENTER\n");
+	struct via_info *card;
+	
+	DPRINTK ("ENTER\n");
+	
+	assert (pdev != NULL);
+	card = pdev->driver_data;
+	assert (card != NULL);
 	
-	if (cards[0].opl3_data.io_base)
-		unload_uart401 (&cards[0].opl3_data);
+	via_interrupt_cleanup (card);
+	via_card_cleanup_proc (card);
+	via_dsp_cleanup (card);
 
-	via_unload_sb (&cards[0].sb_data);
+	release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));
+
+#ifndef VIA_NDEBUG
+	memset (card, 0xAB, sizeof (*card)); /* poison memory */
+#endif
+	kfree (card);
+
+	pdev->driver_data = NULL;
 	
-	via_unload_ac97 (&cards[0]);
+	pci_set_power_state (pdev, 3); /* ...zzzzzz */
 
-	via_cleanup_proc ();
+	DPRINTK ("EXIT\n");
+	return;
+}
+
+
+/****************************************************************
+ *
+ * Driver initialization and cleanup
+ *
+ *
+ */
+
+static int __init init_via82cxxx_audio(void)
+{
+	int rc;
+
+	DPRINTK ("ENTER\n");
 	
-	/*
-	 *	Final clean up with the sound layer
-	 */
-	SOUND_LOCK_END;
+	MOD_INC_USE_COUNT;
+
+	rc = via_init_proc ();
+	if (rc) {
+		MOD_DEC_USE_COUNT;
+		DPRINTK ("EXIT, returning %d\n", rc);
+		return rc;
+	}
+
+	rc = pci_register_driver (&via_driver);
+	if (rc < 1) {
+		if (rc == 0)
+			pci_unregister_driver (&via_driver);
+		via_cleanup_proc ();
+		MOD_DEC_USE_COUNT;
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		return -ENODEV;
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+ 
+static void __exit cleanup_via82cxxx_audio(void)
+{
+	DPRINTK("ENTER\n");
+	
+	pci_unregister_driver (&via_driver);
+	via_cleanup_proc ();
 
 	DPRINTK("EXIT\n");
 }
 
-module_init(init_via82cxxx_module);
-module_exit(cleanup_via82cxxx_module);
 
+module_init(init_via82cxxx_audio);
+module_exit(cleanup_via82cxxx_audio);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.99-pre6/linux/drivers/usb/Config.in	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/Config.in	Thu May  4 11:35:13 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 Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT
          bool '    USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET
       fi
       bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.99-pre6/linux/drivers/usb/audio.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/audio.c	Fri Apr 28 22:53:09 2000
@@ -2159,10 +2159,10 @@
 		db = &as->usbin.dma;
 	} else
 		return -EINVAL;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,22)
+
 	if (vma->vm_pgoff != 0)
 		return -EINVAL;
-#endif
+
 	return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/hid.c linux/drivers/usb/hid.c
--- v2.3.99-pre6/linux/drivers/usb/hid.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/hid.c	Mon May  8 15:48:18 2000
@@ -78,7 +78,7 @@
 static struct {
 	__s32 x;
 	__s32 y;
-}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+}  hid_hat_to_axis[] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}, { 0, 0}};
 
 /*
  * Register a new report for a device.
@@ -948,7 +948,8 @@
 	hid_dump_input(usage, value);
 
 	if (usage->hat) {
-		if (usage->hat == 2) value = value * 2 - 1;
+		if (usage->hat == 2) value = value * 2;
+		if (value > 8) value = 8;
 		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
 		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y);
 		return;
@@ -1431,7 +1432,8 @@
 
 	printk(KERN_INFO "input%d: USB HID v%x.%02x %s\n",
 		hid->input.number, hid->version >> 8, hid->version & 0xff,
-		(hid->application & 0xffff) <= 8 ? hid_name[hid->application & 0xffff] : "device");
+		((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ?
+			hid_name[hid->application & 0xffff] : "device");
 
 	return hid;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.99-pre6/linux/drivers/usb/hub.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/hub.c	Tue May  2 13:15:41 2000
@@ -406,6 +406,7 @@
 
 	/* Run it through the hoops (find a driver, etc) */
 	if (usb_new_device(usb)) {
+		usb_disconnect(&hub->children[port]);
 		/* Woops, disable the port */
 		dbg("hub: disabling port %d", port + 1);
 		usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- v2.3.99-pre6/linux/drivers/usb/keybdev.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/keybdev.c	Tue May  2 15:01:24 2000
@@ -46,7 +46,7 @@
 	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-	 80, 81, 82, 83, 89, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+	 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
 	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
 	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
 	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c
--- v2.3.99-pre6/linux/drivers/usb/mousedev.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/mousedev.c	Tue May  2 15:01:24 2000
@@ -418,10 +418,8 @@
 
 	mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
 
-	if (mousedev_mix.open) {
+	if (mousedev_mix.open)
 		input_open_device(&mousedev->handle);
-		mousedev_mix.open++;
-	}
 
 	printk("mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
 
@@ -432,10 +430,8 @@
 {
 	struct mousedev *mousedev = handle->private;
 
-	if (mousedev->open || mousedev_mix.open) {
+	if (mousedev->open || mousedev_mix.open)
 		input_close_device(handle);
-		mousedev_mix.open--;
-	}
 
 	if (!--mousedev->used) {
 		input_unregister_minor(mousedev->devfs);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.3.99-pre6/linux/drivers/usb/ov511.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/ov511.c	Thu May 11 13:45:35 2000
@@ -1,23 +1,20 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
- * Copyright (c) 1999/2000 Mark W. McClelland
+ *
+ * Copyright (c) 1999-2000 Mark W. McClelland
  * Many improvements by Bret Wallach
  * Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
  * Snapshot code by Kevin Moore
  * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka, claudio@conectiva.com, 3/26/2000
  * 
- * Based on the Linux CPiA driver.
+ * Based on the Linux CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt.
  * 
- * Released under GPL v.2 license.
- *
- * Version: 1.11
- *
  * Please see the file: linux/Documentation/usb/ov511.txt 
- * and the website at:  http://alpha.dyndns.org/ov511 
+ * and the website at:  http://alpha.dyndns.org/ov511
  * for more 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
@@ -33,23 +30,28 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+static const char version[] = "1.13";
+
 #define __NO_VERSION__
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
 #include <linux/usb.h>
 #include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
 
 #include "ov511.h"
 
@@ -59,11 +61,10 @@
 #define MAX_FRAME_SIZE (640 * 480 * 3)
 #define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
 
-// FIXME - Should find a better way to do this.
 #define DEFAULT_WIDTH 640
 #define DEFAULT_HEIGHT 480
 
-// PARAMETER VARIABLES:
+/* PARAMETER VARIABLES: */
 static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
 
 /* 0=no debug messages
@@ -85,24 +86,61 @@
 /* Sensor detection override (global for all attached cameras) */
 static int sensor = 0;
 
+/* Increase this if you are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 5;
+
+/* For legal values, see the OV7610/7620 specs under register Common F,
+   upper nybble  (set to 0-F) */
+static int aperture = -1;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(fix_rgb_offset, "i");
 MODULE_PARM(snapshot, "i");
 MODULE_PARM(sensor, "i");
+MODULE_PARM(i2c_detect_tries, "i");
+MODULE_PARM(aperture, "i");
 
 MODULE_AUTHOR("Mark McClelland (and others)");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
 
 char kernel_version[] = UTS_RELEASE;
 
-/*******************************/
-/* Memory management functions */
-/*******************************/
+static struct usb_driver ov511_driver;
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+/**********************************************************************
+ * List of known OV511-based cameras
+ **********************************************************************/
+
+static struct cam_list clist[] = {
+	{   0, "generic model (no ID)" },
+	{   3, "D-Link DSB-C300" },
+	{   4, "generic OV511/OV7610" },
+	{   5, "Puretek PT-6007" },
+	{  21, "Creative Labs WebCam 3" },
+	{  36, "Koala-Cam" },
+	{  38, "Lifeview USB Life TV" },	/* No support yet! */
+	{ 100, "Lifeview RoboCam" },
+	{ 102, "AverMedia InterCam Elite" },
+	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
+	{  -1, NULL }
+};
 
-static struct usb_driver ov511_driver;
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the OV511 driver -claudio
+ **********************************************************************/
 
 /* Given PGD from the address space's page table, return the kernel
  * virtual mapping of the physical memory mapped at ADR.
@@ -119,31 +157,11 @@
 			ptep = pte_offset(pmd, adr);
 			pte = *ptep;
 			if (pte_present(pte))
-				ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
+				ret = page_address(pte_page(pte)) |
+				      (adr & (PAGE_SIZE-1));
 		}
 	}
-	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
@@ -158,7 +176,6 @@
 	va = VMALLOC_VMADDR(adr);
 	kva = uvirt_to_kva(pgd_offset_k(va), va);
 	ret = __pa(kva);
-	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
@@ -213,9 +230,269 @@
 	vfree(mem);
 }
 
+/**********************************************************************
+ * /proc interface
+ * Based on the CPiA driver version 0.7.4 -claudio
+ **********************************************************************/
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *ov511_proc_root = NULL;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int ov511_read_proc(char *page, char **start, off_t off,
+                          int count, int *eof, void *data)
+{
+	char *out = page;
+	int i, len;
+	struct usb_ov511 *ov511 = data;
+
+	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
+	 *            or we need to get more sophisticated. */
+
+	out += sprintf (out, "custom_id       : %d\n", ov511->customid);
+	out += sprintf (out, "model           : %s\n", ov511->desc ?
+		clist[ov511->desc].description : "unknown");
+	out += sprintf (out, "streaming       : %s\n", YES_NO (ov511->streaming));
+	out += sprintf (out, "grabbing        : %s\n", YES_NO (ov511->grabbing));
+	out += sprintf (out, "compress        : %s\n", YES_NO (ov511->compress));
+	out += sprintf (out, "subcapture      : %s\n", YES_NO (ov511->sub_flag));
+	out += sprintf (out, "sub_size        : %d %d %d %d\n",
+		ov511->subx, ov511->suby, ov511->subw, ov511->subh);
+	out += sprintf (out, "num_frames      : %d\n", OV511_NUMFRAMES);
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		out += sprintf (out, "frame           : %d\n", i);
+		out += sprintf (out, "  depth         : %d\n",
+			ov511->frame[i].depth);
+		out += sprintf (out, "  size          : %d %d\n",
+			ov511->frame[i].width, ov511->frame[i].height);
+		out += sprintf (out, "  hdr_size      : %d %d\n",
+			ov511->frame[i].hdrwidth, ov511->frame[i].hdrheight);
+		out += sprintf (out, "  format        : %d\n",
+			ov511->frame[i].format);
+		out += sprintf (out, "  segsize       : %d\n",
+			ov511->frame[i].segsize);
+#if 0
+		out += sprintf (out, "  curline       : %d\n",
+			ov511->frame[i].curline);
+		out += sprintf (out, "  segment       : %d\n",
+			ov511->frame[i].segment);
+		out += sprintf (out, "  scanlength    : %ld\n",
+			ov511->frame[i].scanlength);
+		out += sprintf (out, "  bytesread     : %ld\n",
+			ov511->frame[i].bytes_read);
+#endif
+	}
+	out += sprintf (out, "snap_enabled    : %s\n", YES_NO (ov511->snap_enabled));
+	out += sprintf (out, "bridge          : %d\n", ov511->bridge);
+	out += sprintf (out, "sensor          : %d\n", ov511->sensor);
+	out += sprintf (out, "packet_size     : %d\n", ov511->packet_size);
+	
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
+}
+
+static int ov511_write_proc(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+	int retval = -EINVAL;
+
+#if 0
+	/* struct cam_data *cam = data; */
+	struct usb_ov511 new_params;
+	int size = count;
+	int find_colon;
+	unsigned long val;
+	u32 command_flags = 0;
+	u8 new_mains;
+	
+	if (down_interruptible(&cam->param_lock))
+		return -ERESTARTSYS;
+	
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	
+	
+#define MATCH(x) \
+	({ \
+		int _len = strlen(x), _ret, _colon_found; \
+		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+		if (_ret) { \
+			buffer += _len; \
+			count -= _len; \
+			if (find_colon) { \
+				_colon_found = 0; \
+				while (count && (*buffer == ' ' || *buffer == '\t' || \
+				       (!_colon_found && *buffer == ':'))) { \
+					if (*buffer == ':')  \
+						_colon_found = 1; \
+					--count; \
+					++buffer; \
+				} \
+				if (!count || !_colon_found) \
+					retval = -EINVAL; \
+				find_colon = 0; \
+			} \
+		} \
+		_ret; \
+	})
+
+#define VALUE \
+	({ \
+		char *_p; \
+		unsigned long int _ret; \
+		_ret = simple_strtoul(buffer, &_p, 0); \
+		if (_p == buffer) \
+			retval = -EINVAL; \
+		else { \
+			count -= _p - buffer; \
+			buffer = _p; \
+		} \
+		_ret; \
+	})
+
+
+	retval = 0;
+	while (count && !retval) {
+		find_colon = 1;
+
+		if (MATCH("")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					/* ... = val */ ;
+				else
+					retval = -EINVAL;
+			}
+		} else {
+			DBG("No match found\n");
+			retval = -EINVAL;
+		}
+
+		if (!retval) {
+			while (count && isspace(*buffer) && *buffer != '\n') {
+				--count;
+				++buffer;
+			}
+			if (count) {
+				if (*buffer != '\n' && *buffer != ';')
+					retval = -EINVAL;
+				else {
+					--count;
+					++buffer;
+				}
+			}
+		}
+	}
+
+#undef MATCH	
+#undef FIRMWARE_VERSION
+#undef VALUE
+#undef FIND_VALUE
+#undef FIND_END
+	if (!retval) {
+		if (command_flags & COMMAND_SETCOLOURPARAMS) {
+			/* Adjust cam->vp to reflect these changes */
+			cam->vp.brightness =
+				new_params.colourParams.brightness*65535/100;
+			cam->vp.contrast =
+				new_params.colourParams.contrast*65535/100;
+			cam->vp.colour =
+				new_params.colourParams.saturation*65535/100;
+		}
+		
+		memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+		cam->mainsFreq = new_mains;
+		cam->cmd_queue |= command_flags;
+		retval = size;
+	} else
+		PDEBUG(3, "error: %d\n", retval);
+	
+	up(&cam->param_lock);
+#endif
+	
+	return retval;
+}
+
+static void create_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	struct proc_dir_entry *ent;
+	
+	PDEBUG (4, "***************");
+	if (!ov511_proc_root || !ov511)
+		return;
+
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "==== name: %s", name);
+	
+	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_root);
+	if (!ent)
+		return;
+
+	ent->data = ov511;
+	ent->read_proc = ov511_read_proc;
+	ent->write_proc = ov511_write_proc;
+	ent->size = 3626;	/* FIXME */
+	ov511->proc_entry = ent;
+}
+
+static void destroy_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	
+	if (!ov511 || !ov511->proc_entry)
+		return;
+	
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "==== name: %s", name);
+#if 0
+	remove_proc_entry(name, ov511_proc_root);
+	ov511->proc_entry = NULL;
+#endif
+}
+
+static void proc_ov511_create(void)
+{
+	ov511_proc_root = create_proc_entry("ov511", S_IFDIR, 0);
+
+	if (ov511_proc_root)
+		ov511_proc_root->owner = THIS_MODULE;
+	else
+		printk("Unable to initialise /proc/ov511\n");	/***********/
+}
+
+static void proc_ov511_destroy(void)
+{
+	remove_proc_entry("ov511", 0);
+}
+#endif /* CONFIG_PROC_FS */
+
+
+/**********************************************************************
+ *
+ * Camera interface
+ *
+ **********************************************************************/
+
 static int ov511_reg_write(struct usb_device *dev,
-                           unsigned char reg,
-                           unsigned char value)
+			   unsigned char reg,
+			   unsigned char value)
 {
 	int rc;
 
@@ -233,6 +510,7 @@
 	return rc;
 }
 
+
 /* returns: negative is error, pos or zero is data */
 static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
 {
@@ -247,24 +525,25 @@
                                
 	PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
 	
-	if(rc < 0) {
+	if (rc < 0) {
 		err("ov511_reg_read: error %d", rc);
 		return rc;
-	}
-	else
+	} else {
 		return buffer[0];	
+	}
 }
 
+
 static int ov511_i2c_write(struct usb_device *dev,
-                           unsigned char reg,
-                           unsigned char value)
+			   unsigned char reg,
+			   unsigned char value)
 {
 	int rc, retries;
 
 	PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg, value);
 
 	/* Three byte write cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
 		if (rc < 0) goto error;
@@ -278,10 +557,10 @@
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 #if 0
 		/* I2C abort */	
@@ -301,13 +580,14 @@
 	return rc;
 }
 
+
 /* returns: negative is error, pos or zero is data */
 static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
 {
 	int rc, value, retries;
 
 	/* Two byte write cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
 		if (rc < 0) goto error;
@@ -317,10 +597,10 @@
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
@@ -334,16 +614,16 @@
 	}
 
 	/* Two byte read cycle */
-	for(retries = OV511_I2C_RETRIES;;) {
+	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
 		if (rc < 0) goto error;
 
 		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
-		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
-		if((rc&2) == 0) /* Ack? */
+		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
@@ -363,7 +643,8 @@
 		
 	/* This is needed to make ov511_i2c_write() work */
 	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
-	if (rc < 0) goto error;
+	if (rc < 0)
+		goto error;
 	
 	return value;
 
@@ -372,12 +653,13 @@
 	return rc;
 }
 
+
 static int ov511_write_regvals(struct usb_device *dev,
 			       struct ov511_regvals * pRegvals)
 {
 	int rc;
 
-	while(pRegvals->bus != OV511_DONE_BUS) {
+	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
 			if ((rc = ov511_reg_write(dev, pRegvals->reg,
 			                           pRegvals->val)) < 0)
@@ -400,6 +682,7 @@
 	return rc;
 }
 
+
 #if 0
 static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
 {
@@ -411,12 +694,14 @@
 	}
 }
 
+
 static void ov511_dump_i2c_regs( struct usb_device *dev)
 {
 	PDEBUG(3, "I2C REGS");
 	ov511_dump_i2c_range(dev, 0x00, 0x38);
 }
 
+
 static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
 {
 	int i;
@@ -427,6 +712,7 @@
 	}
 }
 
+
 static void ov511_dump_regs( struct usb_device *dev)
 {
 	PDEBUG(1, "CAMERA INTERFACE REGS");
@@ -451,6 +737,7 @@
 }
 #endif
 
+
 static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
 	int rc;
@@ -465,6 +752,7 @@
 	return rc;
 }
 
+
 /* Temporarily stops OV511 from functioning. Must do this before changing
  * registers while the camera is streaming */
 static inline int ov511_stop(struct usb_device *dev)
@@ -473,6 +761,7 @@
 	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
 }
 
+
 /* Restarts OV511 after ov511_stop() is called */
 static inline int ov511_restart(struct usb_device *dev)
 {
@@ -480,6 +769,7 @@
 	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
 }
 
+
 static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
 {
 	int alt, mult;
@@ -487,7 +777,7 @@
 	if (ov511_stop(ov511->dev) < 0)
 		return -EIO;
 
-	mult = size / 32;
+	mult = size >> 5;
 
 	if (ov511->bridge == BRG_OV511) {
 		if (size == 0) alt = OV511_ALT_SIZE_0;
@@ -502,8 +792,7 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	}
-	else if (ov511->bridge == BRG_OV511PLUS) {
+	} else if (ov511->bridge == BRG_OV511PLUS) {
 		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
 		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
 		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
@@ -516,16 +805,14 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	}
-	else {
+	} else {
 		err("Set packet size: Invalid bridge type");
 		return -EINVAL;
 	}
 
 	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
 
-	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
-	                     mult) < 0)
+	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, mult) < 0)
 		return -ENOMEM;
 	
 	if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
@@ -545,8 +832,9 @@
 	return 0;
 }
 
-static inline int ov7610_set_picture(struct usb_ov511 *ov511,
-                                     struct video_picture *p)
+
+static inline int
+ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
 {
 	int ret;
 	struct usb_device *dev = ov511->dev;
@@ -556,10 +844,10 @@
 	if (ov511_stop(dev) < 0)
 		return -EIO;
 
-	if((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
 		return -EIO;
 #if 0
-	if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+	if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
 		return -EIO;
 #endif
 	if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE)
@@ -572,17 +860,18 @@
 
 		if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
 			return -EIO;
-	}		
-	else if ((ov511->sensor == SEN_OV7620) 
+	} else if ((ov511->sensor == SEN_OV7620) 
 	         || (ov511->sensor == SEN_OV7620AE)) {
-//		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
-//		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
-//	        // DEBUG_CODE
-//	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
-//	                                   ov511_i2c_read(dev, OV7610_REG_BRT)); 
-//
-//		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
-//			return -EIO;
+#if 0
+		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+	        // DEBUG_CODE
+	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+	         ov511_i2c_read(dev, OV7610_REG_BRT)); 
+
+		if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+			return -EIO;
+#endif
 	}
 
 	if (ov511_restart(dev) < 0)
@@ -591,8 +880,9 @@
 	return 0;
 }
 
-static inline int ov7610_get_picture(struct usb_ov511 *ov511,
-                                     struct video_picture *p)
+
+static inline int
+ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
 {
 	int ret;
 	struct usb_device *dev = ov511->dev;
@@ -613,7 +903,11 @@
 
 	p->hue = 0x8000;
 	p->whiteness = 105 << 8;
+#if 0
 	p->depth = 3;  /* Don't know if this is right */
+#else
+	p->depth = 24;
+#endif
 	p->palette = VIDEO_PALETTE_RGB24;
 
 	if (ov511_restart(dev) < 0)
@@ -622,15 +916,17 @@
 	return 0;
 }
 
-static int ov511_mode_init_regs(struct usb_ov511 *ov511,
-				int width, int height, int mode, int sub_flag)
+
+static int
+ov511_mode_init_regs(struct usb_ov511 *ov511,
+		     int width, int height, int mode, int sub_flag)
 {
 	int rc = 0;
 	struct usb_device *dev = ov511->dev;
-        int hwsbase = 0;
-        int hwebase = 0;
+	int hwsbase = 0;
+	int hwebase = 0;
 
-	PDEBUG(3, "ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)",
+	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
 	       width, height, mode, sub_flag);
 
 	if (ov511_stop(ov511->dev) < 0)
@@ -644,34 +940,39 @@
 			ov511_i2c_write(dev, 0x0e, 0x44);
 		}
 		ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
+
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x00);
 		ov511_reg_write(dev, 0x1f, 0x01);
 	} else {
 		ov511_reg_write(dev, 0x16, 0x01);
-	   	if (ov511->sensor == SEN_OV7610
+		if (ov511->sensor == SEN_OV7610
 		    || ov511->sensor == SEN_OV7620AE) {
-		   /* not valid on the OV7620 */
-		   ov511_i2c_write(dev, 0x0e, 0x04);
+			/* not valid on the OV7620 */
+			ov511_i2c_write(dev, 0x0e, 0x04);
 		}
 		ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
+
 		/* For snapshot */
 		ov511_reg_write(dev, 0x1e, 0x01);
 		ov511_reg_write(dev, 0x1f, 0x03);
 	}
 
 	/* The different sensor ICs handle setting up of window differently */
-        switch (ov511->sensor) {
-	 case SEN_OV7610:
-	 case SEN_OV7620AE:
-	   hwsbase = 0x38;
-	   hwebase = 0x3a; break;
-	 case SEN_OV7620:
-	   hwsbase = 0x2c;
-	   hwebase = 0x2d; break;
-	 default:
-	   hwsbase = 0;
-	   hwebase = 0; break;
+	switch (ov511->sensor) {
+	case SEN_OV7610:
+	case SEN_OV7620AE:
+		hwsbase = 0x38;
+		hwebase = 0x3a;
+		break;
+	case SEN_OV7620:
+		hwsbase = 0x2c;
+		hwebase = 0x2d;
+		break;
+	default:
+		hwsbase = 0;
+		hwebase = 0;
+		break;
 	}
 
 	if (width == 640 && height == 480) {
@@ -680,12 +981,12 @@
 			ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
 			/* horizontal window end */
 			ov511_i2c_write(dev, 0x18,
-					hwebase+((ov511->subx+ov511->subw)>>2));
+				hwebase+((ov511->subx+ov511->subw)>>2));
 			/* vertical window start */
-		   	ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+			ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
 			/* vertical window end */
-		    ov511_i2c_write(dev, 0x1a,
-					0x5+((ov511->suby+ov511->subh)>>1));
+			ov511_i2c_write(dev, 0x1a,
+				0x5+((ov511->suby+ov511->subh)>>1));
 			ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
 			ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
 			/* clock rate control */
@@ -762,255 +1063,267 @@
 	return rc;
 }
 
-	
-/*************************************************************
-
-Turn a YUV4:2:0 block into an RGB block
 
-Video4Linux seems to use the blue, green, red channel
-order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
-
-Color space conversion coefficients taken from the excellent
-http://www.inforamp.net/~poynton/ColorFAQ.html
-In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
-Y values are given for all 4 pixels, but the U (Pb)
-and V (Pr) are assumed constant over the 2x2 block.
+/**********************************************************************
+ *
+ * Color correction functions
+ *
+ **********************************************************************/
 
-To avoid floating point arithmetic, the color conversion
-coefficients are scaled into 16.16 fixed-point integers.
+/*
+ * Turn a YUV4:2:0 block into an RGB block
+ *
+ * Video4Linux seems to use the blue, green, red channel
+ * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
+ *
+ * Color space conversion coefficients taken from the excellent
+ * http://www.inforamp.net/~poynton/ColorFAQ.html
+ * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
+ * Y values are given for all 4 pixels, but the U (Pb)
+ * and V (Pr) are assumed constant over the 2x2 block.
+ *
+ * To avoid floating point arithmetic, the color conversion
+ * coefficients are scaled into 16.16 fixed-point integers.
+ */
 
-*************************************************************/
-// LIMIT: convert a 16.16 fixed-point value to a byte, with clipping.
+/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
-static inline void ov511_move_420_block(
-	                int yTL, int yTR, int yBL, int yBR,
-					int u, int v, 
-					int rowPixels, unsigned char * rgb)
-{
-	const double brightness=1.0;//0->black; 1->full scale
-	const double saturation=1.0;//0->greyscale; 1->full color
-	const double fixScale=brightness*256*256;
-	const int rvScale=(int)(1.402*saturation*fixScale);
-	const int guScale=(int)(-0.344136*saturation*fixScale);
-	const int gvScale=(int)(-0.714136*saturation*fixScale);
-	const int buScale=(int)(1.772*saturation*fixScale);
-	const int yScale=(int)(fixScale);	
-
-	int r    =               rvScale * v;
-	int g    = guScale * u + gvScale * v;
-	int b    = buScale * u;
+
+static inline void
+ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+	int rowPixels, unsigned char * rgb)
+{
+	const double brightness = 1.0; // 0->black; 1->full scale
+	const double saturation = 1.0; // 0->greyscale; 1->full color
+	const double fixScale = brightness * 256 * 256;
+	const int rvScale = (int)(1.402 * saturation * fixScale);
+	const int guScale = (int)(-0.344136 * saturation * fixScale);
+	const int gvScale = (int)(-0.714136 * saturation * fixScale);
+	const int buScale = (int)(1.772 * saturation * fixScale);
+	const int yScale = (int)(fixScale);	
+
+	int r = rvScale * v;
+	int g = guScale * u + gvScale * v;
+	int b = buScale * u;
 	yTL *= yScale; yTR *= yScale;
 	yBL *= yScale; yBR *= yScale;
 
 	//Write out top two pixels
-	rgb[0]=LIMIT(b+yTL); rgb[1]=LIMIT(g+yTL); rgb[2]=LIMIT(r+yTL);
-	rgb[3]=LIMIT(b+yTR); rgb[4]=LIMIT(g+yTR); rgb[5]=LIMIT(r+yTR);
-	rgb+=3*rowPixels;//Skip down to next line to write out bottom two pixels
-	rgb[0]=LIMIT(b+yBL); rgb[1]=LIMIT(g+yBL); rgb[2]=LIMIT(r+yBL);
-	rgb[3]=LIMIT(b+yBR); rgb[4]=LIMIT(g+yBR); rgb[5]=LIMIT(r+yBR);
-}
-
-
-/***************************************************************
+	rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
+	rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
 
-For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.  The
-first 64 bytes of each segment are U, the next 64 are V.  The U and
-V are arranged as follows:
-
-  0  1 ...  7
-  8  9 ... 15
-       ...   
- 56 57 ... 63
-
-U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
-
-The next 256 bytes are full resolution Y data and represent 4 
-squares of 8x8 pixels as follows:
-
-  0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
-  8  9 ... 15    72  73 ...  79        200 201 ... 207
-       ...              ...                    ...
- 56 57 ... 63   120 121     127        248 249 ... 255
+	//Skip down to next line to write out bottom two pixels
+	rgb += 3 * rowPixels;
+	rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
+	rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+}
 
-Note that the U and V data in one segment represents a 16 x 16 pixel
-area, but the Y data represents a 32 x 8 pixel area.
 
-If OV511_DUMPPIX is defined, _parse_data just dumps the
-incoming segments, verbatim, in order, into the frame.
-When used with vidcat -f ppm -s 640x480 this puts the data
-on the standard output and can be analyzed with the parseppm.c
-utility I wrote.  That's a much faster way for figuring out how
-this data is scrambled.
+/*
+ * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V.  The U and
+ * V are arranged as follows:
+ *
+ *      0  1 ...  7
+ *      8  9 ... 15
+ *           ...   
+ *     56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121     127        248 249 ... 255
+ *
+ * Note that the U and V data in one segment represents a 16 x 16 pixel
+ * area, but the Y data represents a 32 x 8 pixel area.
+ *
+ * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote.  That's a much faster way for figuring out how
+ * this data is scrambled.
+ */
 
-****************************************************************/ 
 #define HDIV 8
 #define WDIV (256/HDIV)
 
+#undef OV511_DUMPPIX
 
-static void ov511_parse_data_rgb24(unsigned char * pIn0,
-				   unsigned char * pOut0,
-				   int iOutY,
-				   int iOutUV,
-				   int iHalf,
-				   int iWidth)
- 			    			    
+static void
+ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
+		       int iOutY, int iOutUV, int iHalf, int iWidth)    			    
 {
 #ifndef OV511_DUMPPIX
-    int k, l, m;
-    unsigned char * pIn;
-    unsigned char * pOut, * pOut1;
-
-    /* Just copy the Y's if in the first stripe */
-    if (!iHalf) {
-	pIn = pIn0 + 128;
-	pOut = pOut0 + iOutY;
-	for(k=0; k<4; k++) {
-	    pOut1 = pOut;
-	    for(l=0; l<8; l++) {
-	      for(m=0; m<8; m++) {
-		*pOut1 = *pIn++;
-		pOut1 += 3;
-	      }
-	      pOut1 += (iWidth - 8) * 3;
-	    }
-	    pOut += 8 * 3;
-	}
-    }
-
-    /* Use the first half of VUs to calculate value */
-    pIn = pIn0;
-    pOut = pOut0 + iOutUV;
-    for(l=0; l<4; l++) {
-	for(m=0; m<8; m++) {
-	    int y00 = *(pOut);
-	    int y01 = *(pOut+3);
-	    int y10 = *(pOut+iWidth*3);
-	    int y11 = *(pOut+iWidth*3+3);
-	    int v   = *(pIn+64) - 128;
-	    int u   = *pIn++ - 128;
-	    ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut);
-	    pOut += 6;
-	}
-	pOut += (iWidth*2 - 16) * 3;
-    }
-
-    /* Just copy the other UV rows */
-    for(l=0; l<4; l++) {
-	for(m=0; m<8; m++) {
-	  *pOut++ = *(pIn + 64);
-	  *pOut = *pIn++;
-	  pOut += 5;
-	}
-	pOut += (iWidth*2 - 16) * 3;
-    }
-
-    /* Calculate values if it's the second half */
-    if (iHalf) {
-	pIn = pIn0 + 128;
-	pOut = pOut0 + iOutY;
-	for(k=0; k<4; k++) {
-	    pOut1 = pOut;
-	    for(l=0; l<4; l++) {
-	      for(m=0; m<4; m++) {
-		int y10 = *(pIn+8);
-		int y00 = *pIn++;
-		int y11 = *(pIn+8);
-		int y01 = *pIn++;
-		int v   = *pOut1 - 128;
-		int u   = *(pOut1+1) - 128;
-		ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1);
-		pOut1 += 6;
-	      }
-	      pOut1 += (iWidth*2 - 8) * 3;
-	      pIn += 8;
-	    }
-	    pOut += 8 * 3;
+	int k, l, m;
+	unsigned char * pIn;
+	unsigned char * pOut, * pOut1;
+
+	/* Just copy the Y's if in the first stripe */
+	if (!iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l = 0; l < 8; l++) {
+				for (m = 0; m < 8; m++) {
+					*pOut1 = *pIn++;
+					pOut1 += 3;
+				}
+				pOut1 += (iWidth - 8) * 3;
+			}
+			pOut += 8 * 3;
+		}
+	}
+
+	/* Use the first half of VUs to calculate value */
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV;
+	for (l = 0; l < 4; l++) {
+		for (m=0; m<8; m++) {
+			int y00 = *(pOut);
+			int y01 = *(pOut+3);
+			int y10 = *(pOut+iWidth*3);
+			int y11 = *(pOut+iWidth*3+3);
+			int v   = *(pIn+64) - 128;
+			int u   = *pIn++ - 128;
+			ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth,
+				pOut);
+			pOut += 6;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Just copy the other UV rows */
+	for (l = 0; l < 4; l++) {
+		for (m = 0; m < 8; m++) {
+			*pOut++ = *(pIn + 64);
+			*pOut = *pIn++;
+			pOut += 5;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Calculate values if it's the second half */
+	if (iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l=0; l<4; l++) {
+				for (m=0; m<4; m++) {
+					int y10 = *(pIn+8);
+					int y00 = *pIn++;
+					int y11 = *(pIn+8);
+					int y01 = *pIn++;
+					int v   = *pOut1 - 128;
+					int u   = *(pOut1+1) - 128;
+					ov511_move_420_block(y00, y01, y10,
+						y11, u, v, iWidth, pOut1);
+					pOut1 += 6;
+				}
+				pOut1 += (iWidth*2 - 8) * 3;
+				pIn += 8;
+			}
+			pOut += 8 * 3;
+		}
 	}
-    }
 
 #else
 	/* Just dump pix data straight out for debug */
-	int i;
-	pOut0 += iSegmentY * 384;
-	for(i=0; i<384; i++) {
-	  *pOut0++ = *pIn0++;
+	int i, j;
+
+	pOut0 += iOutY;
+	for (i = 0; i < HDIV; i++) {
+		for (j = 0; j < WDIV; j++) {
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+		}
+		pOut0 += (iWidth - WDIV) * 3;
 	}
 #endif
 }
 
-/***************************************************************
 
-For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
-The segments represent 4 squares of 8x8 pixels as
-follows:
-
-  0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
-  8  9 ... 15    72  73 ...  79        200 201 ... 207
-       ...              ...                    ...
- 56 57 ... 63   120 121     127        248 249 ... 255
-
-****************************************************************/ 
-static void ov511_parse_data_grey(unsigned char * pIn0,
-				  unsigned char * pOut0,
-				  int iOutY,
-				  int iWidth)
-			    
-{
-    int k, l, m;
-    unsigned char * pIn;
-    unsigned char * pOut, * pOut1;
-
-    pIn = pIn0;
-    pOut = pOut0 + iOutY;
-    for(k=0; k<4; k++) {
-      pOut1 = pOut;
-      for(l=0; l<8; l++) {
-	for(m=0; m<8; m++) {
-	  *pOut1++ = *pIn++;
-	}
-	pOut1 += iWidth - 8;
-      }
-      pOut += 8;
-    }
+/*
+ * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121     127        248 249 ... 255
+ *
+ */ 
+static void
+ov511_parse_data_grey(unsigned char * pIn0, unsigned char * pOut0,
+		      int iOutY, int iWidth)		    
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1++ = *pIn++;
+			}
+			pOut1 += iWidth - 8;
+		}
+		pOut += 8;
+	}
 }
 
 
-/**************************************************************
+/*
  * fixFrameRGBoffset--
  * My camera seems to return the red channel about 1 pixel
  * low, and the blue channel about 1 pixel high. After YUV->RGB
  * conversion, we can correct this easily. OSL 2/24/2000.
- *************************************************************/
+ */
 static void fixFrameRGBoffset(struct ov511_frame *frame)
 {
-  int x, y;
-  int rowBytes = frame->width*3, w = frame->width;
-  unsigned char *rgb = frame->data;
-  const int shift = 1;   //Distance to shift pixels by, vertically
-
-  if (frame->width < 400) 
-	   return;     //Don't bother with little images
-
-  //Shift red channel up
-  for (y = shift; y < frame->height; y++)
-  {
-    int lp = (y-shift)*rowBytes;     //Previous line offset
-    int lc = y*rowBytes;             //Current line offset
-    for (x = 0; x < w; x++)
-      rgb[lp+x*3+2] = rgb[lc+x*3+2]; //Shift red up
-  }
-
-  //Shift blue channel down
-  for (y=frame->height-shift-1; y >= 0; y--)
-  {
-    int ln = (y+shift)*rowBytes;   //Next line offset
-    int lc = y*rowBytes;           //Current line offset
-    for (x = 0; x < w; x++)
-      rgb[ln+x*3+0] = rgb[lc+x*3+0]; //Shift blue down
-  }
+	int x, y;
+	int rowBytes = frame->width*3, w = frame->width;
+	unsigned char *rgb = frame->data;
+	const int shift = 1;  /* Distance to shift pixels by, vertically */
+
+	/* Don't bother with little images */
+	if (frame->width < 400) 
+		return;
+
+	/* Shift red channel up */
+	for (y = shift; y < frame->height; y++)	{
+		int lp = (y-shift)*rowBytes;     /* Previous line offset */
+		int lc = y*rowBytes;             /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */
+	}
+
+	/* Shift blue channel down */
+	for (y = frame->height-shift-1; y >= 0; y--) {
+		int ln = (y + shift) * rowBytes;  /* Next line offset */
+		int lc = y * rowBytes;            /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */
+	}
 }
 
 
+/**********************************************************************
+ *
+ * OV511 data transfer, IRQ handler
+ *
+ **********************************************************************/
+
 static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
 {
 	unsigned char *cdata;
@@ -1175,6 +1488,7 @@
 	return totlen;
 }
 
+
 static void ov511_isoc_irq(struct urb *urb)
 {
 	int len;
@@ -1187,28 +1501,32 @@
 	if (!ov511->streaming) {
 		PDEBUG(2, "hmmm... not streaming, but got interrupt");
 		return;
+	} else {
+		PDEBUG(5, "streaming. got interrupt");
 	}
 	
 	sbuf = &ov511->sbuf[ov511->cursbuf];
 
 	/* Copy the data received into our scratch buffer */
-	if (ov511->curframe >= 0)
-	  len = ov511_move_data(ov511, urb);
-	else if (waitqueue_active(&ov511->wq))
-	  wake_up_interruptible(&ov511->wq);
-	
+	if (ov511->curframe >= 0) {
+		len = ov511_move_data(ov511, urb);
+	} else if (waitqueue_active(&ov511->wq)) {
+		wake_up_interruptible(&ov511->wq);
+	}
+
 	/* Move to the next sbuf */
 	ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
 
 	return;
 }
 
+
 static int ov511_init_isoc(struct usb_ov511 *ov511)
 {
 	urb_t *urb;
 	int fx, err;
 
-	PDEBUG(4, "ov511_init_isoc");
+	PDEBUG(3, "*** Initializing capture ***");
 
 	ov511->compress = 0;
 	ov511->curframe = -1;
@@ -1235,11 +1553,11 @@
 	urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
 	urb->transfer_flags = USB_ISO_ASAP;
 	urb->transfer_buffer = ov511->sbuf[0].data;
- 	urb->complete = ov511_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+	urb->complete = ov511_isoc_irq;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
 		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
@@ -1254,11 +1572,11 @@
 	urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
 	urb->transfer_flags = USB_ISO_ASAP;
 	urb->transfer_buffer = ov511->sbuf[1].data;
- 	urb->complete = ov511_isoc_irq;
- 	urb->number_of_packets = FRAMES_PER_DESC;
- 	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
- 	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- 		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+	urb->complete = ov511_isoc_irq;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
 		urb->iso_frame_desc[fx].length = ov511->packet_size;
 	}
 
@@ -1280,10 +1598,11 @@
 
 static void ov511_stop_isoc(struct usb_ov511 *ov511)
 {
-	PDEBUG(4, "ov511_stop_isoc");
 	if (!ov511->streaming || !ov511->dev)
 		return;
 
+	PDEBUG (3, "*** Stopping capture ***");
+
 	ov511_set_packet_size(ov511, 0);
 
 	ov511->streaming = 0;
@@ -1303,18 +1622,19 @@
 	}
 }
 
+
 static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
 {
 	struct ov511_frame *frame;
 	int width, height;
 
-	PDEBUG(4, "ov511_new_frame");
-
+	PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe,
+		framenum);
 	if (!ov511->dev)
 		return -1;
 
 	/* If we're not grabbing a frame right now and the other frame is */
-	/*  ready to be grabbed into, then use it instead */
+	/* ready to be grabbed into, then use it instead */
 	if (ov511->curframe == -1) {
 		if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY)
 			framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
@@ -1325,6 +1645,9 @@
 	width = frame->width;
 	height = frame->height;
 
+	PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, width,
+		height);
+
 	frame->grabstate = FRAME_GRABBING;
 	frame->scanstate = STATE_SCANNING;
 	frame->scanlength = 0;		/* accumulated in ov511_parse_data() */
@@ -1335,11 +1658,17 @@
 	/* Make sure it's not too big */
 	if (width > DEFAULT_WIDTH)
 		width = DEFAULT_WIDTH;
+#if 0
 	width = (width / 8) * 8;	/* Multiple of 8 */
+#endif
+	width &= ~7L;
 
 	if (height > DEFAULT_HEIGHT)
 		height = DEFAULT_HEIGHT;
+#if 0
 	height = (height / 4) * 4;	/* Multiple of 4 */
+#endif
+	width &= ~3L;
 
 //	/* We want a fresh frame every 30 we get */
 //	ov511->compress = (ov511->compress + 1) % 30;
@@ -1348,7 +1677,12 @@
 }
 
 
-/* Video 4 Linux API */
+/****************************************************************************
+ *
+ * V4L API
+ *
+ ***************************************************************************/
+
 static int ov511_open(struct video_device *dev, int flags)
 {
 	int err = -EBUSY;
@@ -1409,9 +1743,9 @@
 out_unlock:
 	up(&ov511->lock);
 	return err;
-
 }
 
+
 static void ov511_close(struct video_device *dev)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
@@ -1438,16 +1772,23 @@
 	}
 }
 
+
 static int ov511_init_done(struct video_device *dev)
 {
+#ifdef CONFIG_PROC_FS
+	create_proc_ov511_cam((struct usb_ov511 *)dev);
+#endif
+
 	return 0;
 }
 
+
 static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
 {
 	return -EINVAL;
 }
 
+
 static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
@@ -1458,311 +1799,313 @@
 		return -EIO;	
 
 	switch (cmd) {
-		case VIDIOCGCAP:
-		{
-			struct video_capability b;
-
-			strcpy(b.name, "OV511 USB Camera");
-			b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-			b.channels = 1;
-			b.audios = 0;
-			b.maxwidth = DEFAULT_WIDTH;
-			b.maxheight = DEFAULT_HEIGHT;
-			b.minwidth = 32;
-			b.minheight = 16;
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+
+		strcpy(b.name, "OV511 USB Camera");
+		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = DEFAULT_WIDTH;
+		b.maxheight = DEFAULT_HEIGHT;
+		b.minwidth = 32;
+		b.minheight = 16;
 
-			if (copy_to_user(arg, &b, sizeof(b)))
-				return -EFAULT;
+		if (copy_to_user(arg, &b, sizeof(b)))
+			return -EFAULT;
 				
-			return 0;
-		}
-		case VIDIOCGCHAN:
-		{
-			struct video_channel v;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if (v.channel != 0)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
 
-			v.flags = 0;
-			v.tuners = 0;
-			v.type = VIDEO_TYPE_CAMERA;
-			strcpy(v.name, "Camera");
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		if (v.channel != 0)
+			return -EINVAL;
 
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-				
-			return 0;
-		}
-		case VIDIOCSCHAN:
-		{
-			int v;
+		v.flags = 0;
+		v.tuners = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		strcpy(v.name, "Camera");
 
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
+		if (copy_to_user(arg, &v, sizeof(v)))
+			return -EFAULT;
+				
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		int v;
 
-			if (v != 0)
-				return -EINVAL;
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
 
-			return 0;
-		}
+		if (v != 0)
+			return -EINVAL;
 
-		case VIDIOCGPICT:
-		{
-			struct video_picture p;
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture p;
 
-			if (ov7610_get_picture(ov511, &p))
-				return -EIO;
+		if (ov7610_get_picture(ov511, &p))
+			return -EIO;
 							
-			if (copy_to_user(arg, &p, sizeof(p)))
-				return -EFAULT;
+		if (copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture p;
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
 
-			if (copy_from_user(&p, arg, sizeof(p)))
-				return -EFAULT;
+		if (copy_from_user(&p, arg, sizeof(p)))
+			return -EFAULT;
 			
-			if (ov7610_set_picture(ov511, &p))
-				return -EIO;
+		if (ov7610_set_picture(ov511, &p))
+			return -EIO;
 
-			return 0;
-		}
-		case VIDIOCGCAPTURE:
-		{
-			int vf;
-			if (copy_from_user(&vf, arg, sizeof(vf)))
-				return -EFAULT;
-			ov511->sub_flag = vf;
-			return 0;
-		}
-		case VIDIOCSCAPTURE:
-		{
-			struct video_capture vc;
-
-			if (copy_from_user(&vc, arg, sizeof(vc)))
-				return -EFAULT;
-			if (vc.flags)
-				return -EINVAL;
-			if (vc.decimation)
-				return -EINVAL;
-			vc.x /= 4;
-			vc.x *= 4;
-			vc.y /= 2;
-			vc.y *= 2;
-			vc.width /= 32;
-			vc.width *= 32;
-			if (vc.width == 0) vc.width = 32;
-			vc.height /= 16;
-			vc.height *= 16;
-			if (vc.height == 0) vc.height = 16;
-
-			ov511->subx = vc.x;
-			ov511->suby = vc.y;
-			ov511->subw = vc.width;
-			ov511->subh = vc.height;
-
-			return 0;
-		}
-		case VIDIOCSWIN:
-		{
-			struct video_window vw;
-
-			if (copy_from_user(&vw, arg, sizeof(vw)))
-				return -EFAULT;
-			if (vw.flags)
-				return -EINVAL;
-			if (vw.clipcount)
-				return -EINVAL;
-			if (vw.height != DEFAULT_HEIGHT)
-				return -EINVAL;
-			if (vw.width != DEFAULT_WIDTH)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCGCAPTURE:
+	{
+		int vf;
+		if (copy_from_user(&vf, arg, sizeof(vf)))
+			return -EFAULT;
+		ov511->sub_flag = vf;
+		return 0;
+	}
+	case VIDIOCSCAPTURE:
+	{
+		struct video_capture vc;
 
-			ov511->compress = 0;
+		if (copy_from_user(&vc, arg, sizeof(vc)))
+			return -EFAULT;
+		if (vc.flags)
+			return -EINVAL;
+		if (vc.decimation)
+			return -EINVAL;
+		vc.x /= 4;
+		vc.x *= 4;
+		vc.y /= 2;
+		vc.y *= 2;
+		vc.width /= 32;
+		vc.width *= 32;
+		if (vc.width == 0) vc.width = 32;
+		vc.height /= 16;
+		vc.height *= 16;
+		if (vc.height == 0) vc.height = 16;
+
+		ov511->subx = vc.x;
+		ov511->suby = vc.y;
+		ov511->subw = vc.width;
+		ov511->subh = vc.height;
 
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window vw;
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
 
-			vw.x = 0;
-			vw.y = 0;
-			vw.width = DEFAULT_WIDTH;
-			vw.height = DEFAULT_HEIGHT;
-			vw.chromakey = 0;
-			vw.flags = 30;
+		if (copy_from_user(&vw, arg, sizeof(vw)))
+			return -EFAULT;
+		if (vw.flags)
+			return -EINVAL;
+		if (vw.clipcount)
+			return -EINVAL;
+		if (vw.height != DEFAULT_HEIGHT)
+			return -EINVAL;
+		if (vw.width != DEFAULT_WIDTH)
+			return -EINVAL;
 
-			if (copy_to_user(arg, &vw, sizeof(vw)))
-				return -EFAULT;
+		ov511->compress = 0;
 
-			return 0;
-		}
-		case VIDIOCGMBUF:
-		{
-			struct video_mbuf vm;
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
 
-			memset(&vm, 0, sizeof(vm));
-			vm.size = 2 * MAX_DATA_SIZE;
-			vm.frames = 2;
-			vm.offsets[0] = 0;
-			vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+		vw.x = 0;
+		vw.y = 0;
+		vw.width = DEFAULT_WIDTH;
+		vw.height = DEFAULT_HEIGHT;
+		vw.chromakey = 0;
+		vw.flags = 30;
 
-			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-				return -EFAULT;
+		if (copy_to_user(arg, &vw, sizeof(vw)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCMCAPTURE:
-		{
-			struct video_mmap vm;
+		return 0;
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
 
-			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-				return -EFAULT;
+		memset(&vm, 0, sizeof(vm));
+		vm.size = 2 * MAX_DATA_SIZE;
+		vm.frames = 2;
+		vm.offsets[0] = 0;
+		vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
 
-			PDEBUG(4, "MCAPTURE");
-			PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
-				vm.frame, vm.width, vm.height, vm.format);
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			return -EFAULT;
 
-			if (vm.format != VIDEO_PALETTE_RGB24 &&
-			    vm.format != VIDEO_PALETTE_GREY)
-				return -EINVAL;
+		return 0;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
 
-			if ((vm.frame != 0) && (vm.frame != 1))
-				return -EINVAL;
+		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+			return -EFAULT;
+
+		PDEBUG(4, "MCAPTURE");
+		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
+			vm.frame, vm.width, vm.height, vm.format);
+
+		if (vm.format != VIDEO_PALETTE_RGB24 &&
+		    vm.format != VIDEO_PALETTE_GREY)
+			return -EINVAL;
+
+		if ((vm.frame != 0) && (vm.frame != 1))
+			return -EINVAL;
 				
-			if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
-				return -EBUSY;
+		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
+			return -EBUSY;
 
-			/* Don't compress if the size changed */
-			if ((ov511->frame[vm.frame].width != vm.width) ||
-			    (ov511->frame[vm.frame].height != vm.height) ||
-			    (ov511->frame[vm.frame].format != vm.format) ||
-			    (ov511->frame[vm.frame].sub_flag !=
-			     ov511->sub_flag)) {
-				/* If we're collecting previous frame wait
-				   before changing modes */
-				interruptible_sleep_on(&ov511->wq);
-				if (signal_pending(current)) return -EINTR;
-				ov511_mode_init_regs(ov511,
-						     vm.width, vm.height,
-						     vm.format, ov511->sub_flag);
-			}
+		/* Don't compress if the size changed */
+		if ((ov511->frame[vm.frame].width != vm.width) ||
+		    (ov511->frame[vm.frame].height != vm.height) ||
+		    (ov511->frame[vm.frame].format != vm.format) ||
+		    (ov511->frame[vm.frame].sub_flag !=
+		     ov511->sub_flag)) {
+			/* If we're collecting previous frame wait
+			   before changing modes */
+			interruptible_sleep_on(&ov511->wq);
+			if (signal_pending(current)) return -EINTR;
+			ov511_mode_init_regs(ov511,
+					     vm.width, vm.height,
+					     vm.format, ov511->sub_flag);
+		}
+
+		ov511->frame[vm.frame].width = vm.width;
+		ov511->frame[vm.frame].height = vm.height;
+		ov511->frame[vm.frame].format = vm.format;
+		ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
+		ov511->frame[vm.frame].segsize =
+		  vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256;
+		ov511->frame[vm.frame].depth =
+		  vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1;
+
+		/* Mark it as ready */
+		ov511->frame[vm.frame].grabstate = FRAME_READY;
+
+		return ov511_new_frame(ov511, vm.frame);
+	}
+	case VIDIOCSYNC:
+	{
+		int frame;
+
+		if (copy_from_user((void *)&frame, arg, sizeof(int)))
+			return -EFAULT;
+
+		PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
+		       ov511->frame[frame].grabstate);
 
-			ov511->frame[vm.frame].width = vm.width;
-			ov511->frame[vm.frame].height = vm.height;
-			ov511->frame[vm.frame].format = vm.format;
-			ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
-			ov511->frame[vm.frame].segsize =
-			  vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256;
-			ov511->frame[vm.frame].depth =
-			  vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1;
-
-			/* Mark it as ready */
-			ov511->frame[vm.frame].grabstate = FRAME_READY;
-
-			return ov511_new_frame(ov511, vm.frame);
-		}
-		case VIDIOCSYNC:
-		{
-			int frame;
-
-			if (copy_from_user((void *)&frame, arg, sizeof(int)))
-				return -EFAULT;
-
-			PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
-			       ov511->frame[frame].grabstate);
-
-			switch (ov511->frame[frame].grabstate) {
-				case FRAME_UNUSED:
-					return -EINVAL;
-				case FRAME_READY:
-				case FRAME_GRABBING:
-				case FRAME_ERROR:
+		switch (ov511->frame[frame].grabstate) {
+			case FRAME_UNUSED:
+				return -EINVAL;
+			case FRAME_READY:
+			case FRAME_GRABBING:
+			case FRAME_ERROR:
 redo:
-				if (!ov511->dev)
-					return -EIO;
+			if (!ov511->dev)
+				return -EIO;
 
-				do {
+			do {
 #if 0
-					init_waitqueue_head(&ov511->frame[frame].wq);
+				init_waitqueue_head(&ov511->frame[frame].wq);
 #endif
-					interruptible_sleep_on(&ov511->frame[frame].wq);
-					if (signal_pending(current))
-						return -EINTR;
-				} while (ov511->frame[frame].grabstate == FRAME_GRABBING);
-
-				if (ov511->frame[frame].grabstate == FRAME_ERROR) {
-					int ret;
-
-					if ((ret = ov511_new_frame(ov511, frame)) < 0)
-						return ret;
-					goto redo;
-				}				
-				case FRAME_DONE:
-					ov511->frame[frame].grabstate = FRAME_UNUSED;
-					break;
-			}
+				interruptible_sleep_on(&ov511->frame[frame].wq);
+				if (signal_pending(current))
+					return -EINTR;
+			} while (ov511->frame[frame].grabstate == FRAME_GRABBING);
+
+			if (ov511->frame[frame].grabstate == FRAME_ERROR) {
+				int ret;
+
+				if ((ret = ov511_new_frame(ov511, frame)) < 0)
+					return ret;
+				goto redo;
+			}				
+			case FRAME_DONE:
+				ov511->frame[frame].grabstate = FRAME_UNUSED;
+				break;
+		}
+
+		ov511->frame[frame].grabstate = FRAME_UNUSED;
+
+		/* Reset the hardware snapshot button */
+		/* FIXME - Is this the best place for this? */
+		if ((ov511->snap_enabled) &&
+		    (ov511->frame[frame].snapshot)) {
+			ov511->frame[frame].snapshot = 0;
+			ov511_reg_write(ov511->dev, 0x52, 0x01);
+			ov511_reg_write(ov511->dev, 0x52, 0x03);
+			ov511_reg_write(ov511->dev, 0x52, 0x01);
+		}
+
+		return 0;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer vb;
 
-			ov511->frame[frame].grabstate = FRAME_UNUSED;
+		memset(&vb, 0, sizeof(vb));
+		vb.base = NULL;	/* frame buffer not supported, not used */
 
-			/* Reset the hardware snapshot button */
-			/* FIXME - Is this the best place for this? */
-			if ((ov511->snap_enabled) &&
-			    (ov511->frame[frame].snapshot)) {
-				ov511->frame[frame].snapshot = 0;
-				ov511_reg_write(ov511->dev, 0x52, 0x01);
-				ov511_reg_write(ov511->dev, 0x52, 0x03);
-				ov511_reg_write(ov511->dev, 0x52, 0x01);
-			}
+		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+			return -EFAULT;
 
-			return 0;
-		}
-		case VIDIOCGFBUF:
-		{
-			struct video_buffer vb;
-
-			memset(&vb, 0, sizeof(vb));
-			vb.base = NULL;	/* frame buffer not supported, not used */
-
-			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-				return -EFAULT;
-
- 			return 0;
- 		}
-		case VIDIOCKEY:
-			return 0; 		
-		case VIDIOCCAPTURE:
-			return -EINVAL;
-		case VIDIOCSFBUF:
-			return -EINVAL;
-		case VIDIOCGTUNER:
-		case VIDIOCSTUNER:
-			return -EINVAL;			
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-			return -EINVAL;
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
-			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
+		return 0;
 	}
+	case VIDIOCKEY:
+		return 0; 		
+	case VIDIOCCAPTURE:
+		return -EINVAL;
+	case VIDIOCSFBUF:
+		return -EINVAL;
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+		return -EINVAL;			
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
+	}	/* End switch(cmd) */
+
 	return 0;
 }
 
+
 static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	int i;
 	int frmx = -1;
 	volatile struct ov511_frame *frame;
 
-	PDEBUG(4, "ov511_read: %ld bytes, noblock=%d", count, noblock);
+	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
 
 	if (!dev || !buf)
 		return -EFAULT;
@@ -1776,6 +2119,7 @@
 	else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
 		frmx = 1;
 
+	/* If nonblocking we return immediately */
 	if (noblock && (frmx == -1))
 		return -EAGAIN;
 
@@ -1794,19 +2138,26 @@
 
 	frame = &ov511->frame[frmx];
 
+	/* FIXME */
+	frame->segsize = frame->format == VIDEO_PALETTE_RGB24 ? 384 : 256;
+	frame->depth = frame->format == VIDEO_PALETTE_RGB24 ? 24 : 8;
+
 restart:
 	if (!ov511->dev)
 		return -EIO;
 
+	/* Wait while we're grabbing the image */
+	PDEBUG(4, "Waiting image grabbing");
 	while (frame->grabstate == FRAME_GRABBING) {
 		interruptible_sleep_on(&ov511->frame[frmx].wq);
 		if (signal_pending(current))
 			return -EINTR;
 	}
+	PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
 
 	if (frame->grabstate == FRAME_ERROR) {
 		frame->bytes_read = 0;
-		err("ov511_read: errored frame %d", ov511->curframe);
+		err("** ick! ** Errored frame %d", ov511->curframe);
 		if (ov511_new_frame(ov511, frmx))
 			err("ov511_read: ov511_new_frame error");
 		goto restart;
@@ -1814,14 +2165,21 @@
 
 
 	/* Repeat until we get a snapshot frame */
+	if (!ov511->snap_enabled) {
+		PDEBUG (4, "snap disabled");
+	} else {
+		PDEBUG (4, "Waiting snapshot frame");
+	}
 	if (ov511->snap_enabled && !frame->snapshot) {
 		frame->bytes_read = 0;
 		if (ov511_new_frame(ov511, frmx))
-			err("ov511_read: ov511_new_frame error");
+			err("ov511_new_frame error");
 		goto restart;
 	}
 
 	/* Clear the snapshot */
+	if (ov511->snap_enabled)
+		PDEBUG (4, "Clear snapshot");
 	if (ov511->snap_enabled && frame->snapshot) {
 		frame->snapshot = 0;
 		ov511_reg_write(ov511->dev, 0x52, 0x01);
@@ -1829,20 +2187,24 @@
 		ov511_reg_write(ov511->dev, 0x52, 0x01);
 	}
 
-	PDEBUG(4, "ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
+	PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
 		frame->bytes_read, frame->scanlength);
 
 	/* copy bytes to user space; we allow for partials reads */
 //	if ((count + frame->bytes_read) > frame->scanlength)
 //		count = frame->scanlength - frame->bytes_read;
+
 	/* FIXME - count hardwired to be one frame... */
-	count = frame->width * frame->height * frame->depth;
+	count = frame->width * frame->height * (frame->depth >> 3);
 
-	if (copy_to_user(buf, frame->data + frame->bytes_read, count))
+	PDEBUG(4, "Copy to user space: %ld bytes", count);
+	if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
+		PDEBUG(4, "Copy failed! %d bytes not copied", i);
 		return -EFAULT;
+	}
 
 	frame->bytes_read += count;
-	PDEBUG(4, "ov511_read: {copy} count used=%ld, new bytes_read=%ld",
+	PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
 		count, frame->bytes_read);
 
 	if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
@@ -1851,13 +2213,17 @@
 		/* Mark it as available to be used again. */
 		ov511->frame[frmx].grabstate = FRAME_UNUSED;
 		if (ov511_new_frame(ov511, frmx ? 0 : 1))
-			err("ov511_read: ov511_new_frame returned error");
+			err("ov511_new_frame returned error");
 	}
 
+	PDEBUG(4, "read finished, returning %ld (sweet)", count);
+
 	return count;
 }
 
-static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long size)
+
+static int ov511_mmap(struct video_device *dev, const char *adr,
+	unsigned long size)
 {
 	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
 	unsigned long start = (unsigned long)adr;
@@ -1888,6 +2254,7 @@
 	return 0;
 }
 
+
 static struct video_device ov511_template = {
 	name:		"OV511 USB Camera",
 	type:		VID_TYPE_CAPTURE,
@@ -1901,12 +2268,81 @@
 	initialize:	ov511_init_done,
 };
 
-static int ov7610_configure(struct usb_ov511 *ov511)
+
+/****************************************************************************
+ *
+ * OV511/OV7610 configuration
+ *
+ ***************************************************************************/
+
+static int ov76xx_configure(struct usb_ov511 *ov511)
 {
 	struct usb_device *dev = ov511->dev;
-	int tries;
+	int i, success;
 	int rc;
 
+	static struct ov511_regvals aRegvalsNorm7610[] =
+	{{OV511_I2C_BUS, 0x10, 0xff},
+	 {OV511_I2C_BUS, 0x16, 0x06},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x2b, 0xac},
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x06, 0x00},
+	 {OV511_I2C_BUS, 0x12, 0x00},
+	 {OV511_I2C_BUS, 0x38, 0x81},
+	 {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x0f, 0x05},
+	 {OV511_I2C_BUS, 0x15, 0x01},
+	 {OV511_I2C_BUS, 0x20, 0x1c},
+	 {OV511_I2C_BUS, 0x23, 0x2a},
+	 {OV511_I2C_BUS, 0x24, 0x10},
+	 {OV511_I2C_BUS, 0x25, 0x8a},
+	 {OV511_I2C_BUS, 0x27, 0xc2},
+	 {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
+	 {OV511_I2C_BUS, 0x2a, 0x04},
+	 {OV511_I2C_BUS, 0x2c, 0xfe},
+	 {OV511_I2C_BUS, 0x30, 0x71},
+	 {OV511_I2C_BUS, 0x31, 0x60},
+	 {OV511_I2C_BUS, 0x32, 0x26},
+	 {OV511_I2C_BUS, 0x33, 0x20},
+	 {OV511_I2C_BUS, 0x34, 0x48},
+	 {OV511_I2C_BUS, 0x12, 0x24},
+	 {OV511_I2C_BUS, 0x11, 0x01},
+	 {OV511_I2C_BUS, 0x0c, 0x24},
+	 {OV511_I2C_BUS, 0x0d, 0x24},
+	 {OV511_DONE_BUS, 0x0, 0x00},
+	};
+
+	static struct ov511_regvals aRegvalsNorm7620[] =
+	{{OV511_I2C_BUS, 0x10, 0xff},
+	 {OV511_I2C_BUS, 0x16, 0x06},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x2b, 0xac},
+	 {OV511_I2C_BUS, 0x12, 0x00},
+	 {OV511_I2C_BUS, 0x28, 0x24},
+	 {OV511_I2C_BUS, 0x05, 0x00},
+	 {OV511_I2C_BUS, 0x0f, 0x05},
+	 {OV511_I2C_BUS, 0x15, 0x01},
+	 {OV511_I2C_BUS, 0x23, 0x00},
+	 {OV511_I2C_BUS, 0x24, 0x10},
+	 {OV511_I2C_BUS, 0x25, 0x8a},
+	 {OV511_I2C_BUS, 0x27, 0xe2},
+	 {OV511_I2C_BUS, 0x29, 0x03},
+	 {OV511_I2C_BUS, 0x2a, 0x00},
+	 {OV511_I2C_BUS, 0x2c, 0xfe},
+	 {OV511_I2C_BUS, 0x30, 0x71},
+	 {OV511_I2C_BUS, 0x31, 0x60},
+	 {OV511_I2C_BUS, 0x32, 0x26},
+	 {OV511_I2C_BUS, 0x33, 0x20},
+	 {OV511_I2C_BUS, 0x34, 0x48},
+	 {OV511_I2C_BUS, 0x12, 0x24},
+	 {OV511_I2C_BUS, 0x11, 0x01},
+	 {OV511_I2C_BUS, 0x0c, 0x24},
+	 {OV511_I2C_BUS, 0x0d, 0x24},
+	 {OV511_DONE_BUS, 0x0, 0x00},
+	};
+
 	if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
 	                        OV7610_I2C_WRITE_ID) < 0)
 		return -1;
@@ -1918,64 +2354,90 @@
 	if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
 		return -1;
 	
-	/* Reset the 7610 and wait a bit for it to initialize */ 
+	/* Reset the 76xx */ 
 	if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
-	schedule_timeout (1 + 150 * HZ / 1000);
 
-	/* Dummy read to sync I2C */
-	if(ov511_i2c_read(dev, 0x00) < 0)
-		return -1;
- 
-	tries = 5;
-	while((tries > 0) &&
-	      ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) != 0x7F) ||
-	       (ov511_i2c_read(dev, OV7610_REG_ID_LOW) != 0xA2))) {
-		--tries;
+	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+		if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) &&
+		    (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2))
+			success = 1;
+
+		/* Dummy read to sync I2C */
+		if (ov511_i2c_read(dev, 0x00) < 0) return -1;
+		/* Wait for it to initialize */ 
+		schedule_timeout (1 + 150 * HZ / 1000);
 	}
-	
-	if (tries == 1) {
-		err("Failed to read sensor ID. You might not have an OV7610/20,");
+
+	if (success) {
+		PDEBUG(1, "I2C synced in %d attempt(s)", i);
+	} else {
+		err("Failed to read sensor ID. You might not have an OV76xx,");
 		err("or it may be not responding. Report this to");
 		err("mmcclelland@delphi.com");
 		return -1;
 	}
 
+	/* Detect sensor if user didn't use override param */
 	if (sensor == 0) {
 		rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
 
 		if (rc < 0) {
 			err("Error detecting sensor type");
 			return -1;
-		}
-		else if((rc & 3) == 3) {
+		} else if((rc & 3) == 3) {
 			printk("ov511: Sensor is an OV7610\n");
 			ov511->sensor = SEN_OV7610;
-		}
-		else if((rc & 3) == 1) {
+		} else if((rc & 3) == 1) {
 			printk("ov511: Sensor is an OV7620AE\n");
 			ov511->sensor = SEN_OV7620AE;
-		}
-		else if((rc & 3) == 0) {
+		} else if((rc & 3) == 0) {
 			printk("ov511: Sensor is an OV7620\n");
 			ov511->sensor = SEN_OV7620;
-		}
-		else {
+		} else {
 			err("Unknown image sensor version: %d", rc & 3);
 			return -1;
 		}
-	}
-	else {  /* sensor != 0; user overrode detection */
+	} else {	/* sensor != 0; user overrode detection */
 		ov511->sensor = sensor;
 		printk("ov511: Sensor set to type %d\n", ov511->sensor);
 	}
 
+	if (ov511->sensor == SEN_OV7620) {
+		if (ov511_write_regvals(dev, aRegvalsNorm7620))
+			return -1;
+	} else {
+		if (ov511_write_regvals(dev, aRegvalsNorm7610))
+			return -1;
+	}
+
+	if (aperture < 0) {          /* go with the default */
+		if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1;
+	} else if (aperture <= 0xf) {  /* user overrode default */
+		if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0)
+			return -1;
+	} else {
+		err("Invalid setting for aperture; legal value: 0 - 15");
+		return -1;
+	}
+
+	if (autoadjust) {
+		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1;
+	} else {
+		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1;
+		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
+	}
+
 	return 0;
 }
 
+
 static int ov511_configure(struct usb_ov511 *ov511)
 {
 	struct usb_device *dev = ov511->dev;
-	int rc;
 
 	static struct ov511_regvals aRegvalsInit[] =
 	{{OV511_REG_BUS,  OV511_REG_SYSTEM_RESET, 0x7f},
@@ -1988,7 +2450,7 @@
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
 
-	static struct ov511_regvals aRegvalsNorm7610[] =
+	static struct ov511_regvals aRegvalsNorm511[] =
 	{{OV511_REG_BUS, 0x20, 0x01},
 	 {OV511_REG_BUS, 0x52, 0x02},
 	 {OV511_REG_BUS, 0x52, 0x00},
@@ -2003,85 +2465,6 @@
 	 {OV511_REG_BUS, 0x77, 0x01},
 	 {OV511_REG_BUS, 0x78, 0x06},
 	 {OV511_REG_BUS, 0x79, 0x03},
-
-	 {OV511_I2C_BUS, 0x10, 0xff},
-	 {OV511_I2C_BUS, 0x16, 0x06},
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x2b, 0xac},
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x06, 0x00},
-
-	 {OV511_I2C_BUS, 0x12, 0x00},
-	 {OV511_I2C_BUS, 0x38, 0x81},
-	 {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x0f, 0x05},
-	 {OV511_I2C_BUS, 0x15, 0x01},
-	 {OV511_I2C_BUS, 0x20, 0x1c},
-	 {OV511_I2C_BUS, 0x23, 0x2a},
-	 {OV511_I2C_BUS, 0x24, 0x10},
-	 {OV511_I2C_BUS, 0x25, 0x8a},
-	 {OV511_I2C_BUS, 0x26, 0x90},
-	 {OV511_I2C_BUS, 0x27, 0xc2},
-	 {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
-	 {OV511_I2C_BUS, 0x2a, 0x04},
-	 {OV511_I2C_BUS, 0x2c, 0xfe},
-	 {OV511_I2C_BUS, 0x30, 0x71},
-	 {OV511_I2C_BUS, 0x31, 0x60},
-	 {OV511_I2C_BUS, 0x32, 0x26},
-	 {OV511_I2C_BUS, 0x33, 0x20},
-	 {OV511_I2C_BUS, 0x34, 0x48},
-	 {OV511_I2C_BUS, 0x12, 0x24},
-	 {OV511_I2C_BUS, 0x11, 0x01},
-	 {OV511_I2C_BUS, 0x0c, 0x24},
-	 {OV511_I2C_BUS, 0x0d, 0x24},
-	 {OV511_DONE_BUS, 0x0, 0x00},
-	};
-
-	static struct ov511_regvals aRegvalsNorm7620[] =
-	{{OV511_REG_BUS, 0x20, 0x01},
-	 {OV511_REG_BUS, 0x52, 0x02},
-	 {OV511_REG_BUS, 0x52, 0x00},
-	 {OV511_REG_BUS, 0x31, 0x1f},
-	 {OV511_REG_BUS, 0x70, 0x3f},
-	 {OV511_REG_BUS, 0x71, 0x3f},
-	 {OV511_REG_BUS, 0x72, 0x01},
-	 {OV511_REG_BUS, 0x73, 0x01},
-	 {OV511_REG_BUS, 0x74, 0x01},
-	 {OV511_REG_BUS, 0x75, 0x01},
-	 {OV511_REG_BUS, 0x76, 0x01},
-	 {OV511_REG_BUS, 0x77, 0x01},
-	 {OV511_REG_BUS, 0x78, 0x06},
-	 {OV511_REG_BUS, 0x79, 0x03},
-
-	 {OV511_I2C_BUS, 0x10, 0xff},
-	 {OV511_I2C_BUS, 0x16, 0x06},
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x2b, 0xac},
-
-	 {OV511_I2C_BUS, 0x12, 0x00},
-
-	 {OV511_I2C_BUS, 0x28, 0x24},
-	 {OV511_I2C_BUS, 0x05, 0x00},
-	 {OV511_I2C_BUS, 0x0f, 0x05},
-	 {OV511_I2C_BUS, 0x15, 0x01},
-	 {OV511_I2C_BUS, 0x23, 0x00},
-	 {OV511_I2C_BUS, 0x24, 0x10},
-	 {OV511_I2C_BUS, 0x25, 0x8a},
-	 {OV511_I2C_BUS, 0x26, 0xa2},
-	 {OV511_I2C_BUS, 0x27, 0xe2},
-	 {OV511_I2C_BUS, 0x29, 0x03},
-	 {OV511_I2C_BUS, 0x2a, 0x00},
-	 {OV511_I2C_BUS, 0x2c, 0xfe},
-	 {OV511_I2C_BUS, 0x30, 0x71},
-	 {OV511_I2C_BUS, 0x31, 0x60},
-	 {OV511_I2C_BUS, 0x32, 0x26},
-	 {OV511_I2C_BUS, 0x33, 0x20},
-	 {OV511_I2C_BUS, 0x34, 0x48},
-	 {OV511_I2C_BUS, 0x12, 0x24},
-	 {OV511_I2C_BUS, 0x11, 0x01},
-	 {OV511_I2C_BUS, 0x0c, 0x24},
-	 {OV511_I2C_BUS, 0x0d, 0x24},
 	 {OV511_DONE_BUS, 0x0, 0x00},
 	};
 
@@ -2096,54 +2479,36 @@
 		return -EBUSY;
 	}
 
-	if ((rc = ov511_write_regvals(dev, aRegvalsInit)))
-		return rc;
-
-	if(ov7610_configure(ov511) < 0) {
-		err("failed to configure OV7610");
- 		goto error;	
-	}
+	if (ov511_write_regvals(dev, aRegvalsInit)) goto error;
+	if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
 
 	ov511_set_packet_size(ov511, 0);
 
-	/* Disable compression */
-	if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0)
-		goto error;
-
 	ov511->snap_enabled = snapshot;	
 
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
 	 * (using read() instead). */
 	ov511->frame[0].width = DEFAULT_WIDTH;
 	ov511->frame[0].height = DEFAULT_HEIGHT;
+	ov511->frame[0].depth = 24;		/**************/
 	ov511->frame[0].bytes_read = 0;
+	ov511->frame[0].segment = 0;
 	ov511->frame[1].width = DEFAULT_WIDTH;
 	ov511->frame[1].height = DEFAULT_HEIGHT;
+	ov511->frame[1].depth = 24;
 	ov511->frame[1].bytes_read = 0;
+	ov511->frame[1].segment = 0;
 
 	/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
 
-	if (ov511->sensor == SEN_OV7620) {
-		if (ov511_write_regvals(dev, aRegvalsNorm7620)) goto error;
-	}
-	else {
-		if (ov511_write_regvals(dev, aRegvalsNorm7610)) goto error;
+	if(ov76xx_configure(ov511) < 0) {
+		err("failed to configure OV76xx");
+ 		goto error;	
 	}
 
 	if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
-				       VIDEO_PALETTE_RGB24, 0) < 0) goto error;
-
-	if (autoadjust) {
-		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) goto error;
-		if (ov511_i2c_write(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) goto error;
-	}
-	else {
-		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) goto error;
-		if (ov511_i2c_write(dev, 0x2d, 
-		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) goto error;
-		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
-	}
+				 VIDEO_PALETTE_RGB24, 0) < 0)
+		goto error;
 
 	return 0;
 	
@@ -2158,11 +2523,18 @@
 	return -EBUSY;	
 }
 
+
+/****************************************************************************
+ *
+ *  USB routines
+ *
+ ***************************************************************************/
+
 static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_ov511 *ov511;
-	int rc;
+	int i;
 
 	PDEBUG(1, "probing for device...");
 
@@ -2191,79 +2563,58 @@
 	}
 
 	memset(ov511, 0, sizeof(*ov511));
-	
+
 	ov511->dev = dev;
 	ov511->iface = interface->bInterfaceNumber;
 
-	if (dev->descriptor.idProduct == 0x0511) {
+	switch (dev->descriptor.idProduct) {
+	case 0x0511:
 		info("USB OV511 camera found");
 		ov511->bridge = BRG_OV511;
-	}
-	else if (dev->descriptor.idProduct == 0xA511) {
+		break;
+	case 0xA511:
 		info("USB OV511+ camera found");
 		ov511->bridge = BRG_OV511PLUS;
+		break;
 	}
 
-	rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
-	if (rc < 0) {
+	ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
+	if (ov511->customid < 0) {
 		err("Unable to read camera bridge registers");
 		goto error;
 	}
-	
-	switch(ov511->customid = rc) {
-	case 0: /* This also means that no custom ID was set */
-		printk("ov511: Camera is a generic model (no ID)\n");
-		break;
-	case 3:
-		printk("ov511: Camera is a D-Link DSB-C300\n");
-		break;
-	case 4:
-		printk("ov511: Camera is a generic OV511/OV7610\n");
-		break;
-	case 5:
-		printk("ov511: Camera is a Puretek PT-6007\n");
-		break;
-	case 21:
-		printk("ov511: Camera is a Creative Labs WebCam 3\n");
-		break;
-	case 36:
-		printk("ov511: Camera is a Koala-Cam\n");
-		break;
-	case 38:
-		printk("ov511: Camera is a Lifeview USB Life TV\n");
-		printk("ov511: This device is not supported, exiting...\n");
-		goto error;
-		break;
-	case 100:
-		printk("ov511: Camera is a Lifeview RoboCam\n");
-		break;
-	case 102:
-		printk("ov511: Camera is a AverMedia InterCam Elite\n");
-		break;
-	case 112: /* The OmniVision OV7110 evaluation kit uses this too */
-		printk("ov511: Camera is a MediaForte MV300\n");
-		break;
-	default:
-		err("Specific camera type (%d) not recognized", rc);
+
+	ov511->desc = -1;
+	PDEBUG (4, "CustomID = %d", ov511->customid);
+	for (i = 0; clist[i].id >= 0; i++) {
+		if (ov511->customid == clist[i].id) {
+			printk ("Camera: %s\n", clist[i].description);
+			ov511->desc = i;
+			break;
+		}
+	}
+
+	/* Lifeview USB Life TV not supported */
+	if (clist[i].id == 38) {
+		err("This device is not supported yet.");
+		return NULL;
+	}
+
+	if (clist[i].id == -1) {
+		err("Camera type (%d) not recognized", ov511->customid);
 		err("Please contact mmcclelland@delphi.com to request");
 		err("support for your camera.");
 	}
 
-//	if (ov511->bridge == BRG_OV511PLUS) {
-//		err("Sorry, the OV511+ chip is not supported yet");
-//		goto error;
-//	}
-
 	if (!ov511_configure(ov511)) {
-		ov511->user=0;
+		ov511->user = 0;
 		init_MUTEX(&ov511->lock);	/* to 1 == available */
 		return ov511;
-	}
-	else {
+	} else {
 		err("Failed to configure camera");
 		goto error;
 	}
-    	
+
      	return ov511;
 
 error:
@@ -2272,12 +2623,12 @@
 		ov511 = NULL;
 	}
 
-	return NULL;	
+	return NULL;
 }
 
+
 static void ov511_disconnect(struct usb_device *dev, void *ptr)
 {
-
 	struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
 
 //	video_unregister_device(&ov511->vdev);
@@ -2318,6 +2669,11 @@
 		ov511->sbuf[0].urb = NULL;
 	}
 
+#ifdef CONFIG_PROC_FS
+        PDEBUG(3, "destroying /proc/ov511/video%d", ov511->vdev.minor);
+        destroy_proc_ov511_cam(ov511);
+#endif
+
 	/* Free the memory */
 	if (!ov511->user) {
 		kfree(ov511);
@@ -2332,18 +2688,35 @@
 	{ NULL, NULL }
 };
 
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
 static int __init usb_ov511_init(void)
 {
+#ifdef CONFIG_PROC_FS
+	PDEBUG(3, "creating /proc/ov511");
+        proc_ov511_create();
+#endif
+
 	if (usb_register(&ov511_driver) < 0)
 		return -1;
 
-	info("ov511 driver registered");
+	info("ov511 driver version %s registered", version);
 
 	return 0;
 }
 
 static void __exit usb_ov511_exit(void)
 {
+#ifdef CONFIG_PROC_FS
+	PDEBUG(3, "destroying /proc/ov511");
+        proc_ov511_destroy();
+#endif 
+
 	usb_deregister(&ov511_driver);
 	info("ov511 driver deregistered");
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- v2.3.99-pre6/linux/drivers/usb/ov511.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/ov511.h	Thu May 11 13:45:35 2000
@@ -1,34 +1,38 @@
 #ifndef __LINUX_OV511_H
 #define __LINUX_OV511_H
 
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
 #define OV511_DEBUG	/* Turn on debug messages */
 
 #ifdef OV511_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) printk("ov511: " fmt "\n" , ## args)
+if (debug >= level) printk("ov511: [" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LINE__ , ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
 
 /* Camera interface register numbers */
-#define OV511_REG_CAMERA_DELAY_MODE			0x10
-#define OV511_REG_CAMERA_EDGE_MODE			0x11
+#define OV511_REG_CAMERA_DELAY_MODE		0x10
+#define OV511_REG_CAMERA_EDGE_MODE		0x11
 #define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM	0x12
 #define OV511_REG_CAMERA_CLAMPED_LINE_NUM	0x13
 #define OV511_REG_CAMERA_PIXEL_DIVISOR		0x14
 #define OV511_REG_CAMERA_LINE_DIVISOR		0x15
 #define OV511_REG_CAMERA_DATA_INPUT_SELECT	0x16
 #define OV511_REG_CAMERA_RESERVED_LINE_MODE	0x17
-#define OV511_REG_CAMERA_BITMASK			0x18
+#define OV511_REG_CAMERA_BITMASK		0x18
 
 /* Snapshot mode camera interface register numbers */
 #define OV511_REG_SNAP_CAPTURED_FRAME		0x19
 #define OV511_REG_SNAP_CLAMPED_PIXEL_NUM	0x1A
 #define OV511_REG_SNAP_CLAMPED_LINE_NUM		0x1B
 #define OV511_REG_SNAP_PIXEL_DIVISOR		0x1C
-#define OV511_REG_SNAP_LINE_DIVISOR			0x1D
+#define OV511_REG_SNAP_LINE_DIVISOR		0x1D
 #define OV511_REG_SNAP_DATA_INPUT_SELECT	0x1E
-#define OV511_REG_SNAP_BITMASK				0x1F
+#define OV511_REG_SNAP_BITMASK			0x1F
 
 /* DRAM register numbers */
 #define OV511_REG_DRAM_ENABLE_FLOW_CONTROL	0x20
@@ -37,21 +41,21 @@
 #define OV511_REG_DRAM_REFRESH_COUNTER		0x23
 
 /* ISO FIFO register numbers */
-#define OV511_REG_FIFO_PACKET_SIZE			0x30
-#define OV511_REG_FIFO_BITMASK				0x31
+#define OV511_REG_FIFO_PACKET_SIZE		0x30
+#define OV511_REG_FIFO_BITMASK			0x31
 
 /* PIO register numbers */
-#define OV511_REG_PIO_BITMASK				0x38
-#define OV511_REG_PIO_DATA_PORT				0x39
-#define OV511_REG_PIO_BIST					0x3E
+#define OV511_REG_PIO_BITMASK			0x38
+#define OV511_REG_PIO_DATA_PORT			0x39
+#define OV511_REG_PIO_BIST			0x3E
 
 /* I2C register numbers */
-#define OV511_REG_I2C_CONTROL				0x40
+#define OV511_REG_I2C_CONTROL			0x40
 #define OV511_REG_I2C_SLAVE_ID_WRITE		0x41
 #define OV511_REG_I2C_SUB_ADDRESS_3_BYTE	0x42
 #define OV511_REG_I2C_SUB_ADDRESS_2_BYTE	0x43
-#define OV511_REG_I2C_SLAVE_ID_READ			0x44
-#define OV511_REG_I2C_DATA_PORT				0x45
+#define OV511_REG_I2C_SLAVE_ID_READ		0x44
+#define OV511_REG_I2C_DATA_PORT			0x45
 #define OV511_REG_I2C_CLOCK_PRESCALER		0x46
 #define OV511_REG_I2C_TIME_OUT_COUNTER		0x47
 
@@ -60,39 +64,39 @@
 #define OV511_REG_I2C_SNAP_DATA_PORT		0x49
 
 /* System control register numbers */
-#define OV511_REG_SYSTEM_RESET				0x50
-#define 	OV511_RESET_UDC				0x01
-#define 	OV511_RESET_I2C				0x02
-#define 	OV511_RESET_FIFO			0x04
-#define 	OV511_RESET_OMNICE			0x08
+#define OV511_REG_SYSTEM_RESET			0x50
+#define 	OV511_RESET_UDC			0x01
+#define 	OV511_RESET_I2C			0x02
+#define 	OV511_RESET_FIFO		0x04
+#define 	OV511_RESET_OMNICE		0x08
 #define 	OV511_RESET_DRAM_INTF		0x10
 #define 	OV511_RESET_CAMERA_INTF		0x20
-#define		OV511_RESET_OV511			0x40
-#define		OV511_RESET_NOREGS			0x3F	/* All but OV511 & regs */
-#define 	OV511_RESET_ALL				0x7F
+#define 	OV511_RESET_OV511		0x40
+#define 	OV511_RESET_NOREGS		0x3F /* All but OV511 & regs */
+#define 	OV511_RESET_ALL			0x7F
 #define OV511_REG_SYSTEM_CLOCK_DIVISOR		0x51
-#define OV511_REG_SYSTEM_SNAPSHOT			0x52
+#define OV511_REG_SYSTEM_SNAPSHOT		0x52
 #define OV511_REG_SYSTEM_INIT         		0x53
-#define OV511_REG_SYSTEM_PWR_CLK      		0x54    /* OV511+ only */
-#define OV511_REG_SYSTEM_LED_CTL      		0x55    /* OV511+ only */
+#define OV511_REG_SYSTEM_PWR_CLK		0x54	/* OV511+ only */
+#define OV511_REG_SYSTEM_LED_CTL		0x55	/* OV511+ only */
 #define OV511_REG_SYSTEM_USER_DEFINED		0x5E
-#define OV511_REG_SYSTEM_CUSTOM_ID			0x5F
+#define OV511_REG_SYSTEM_CUSTOM_ID		0x5F
 
 /* OmniCE register numbers */
-#define OV511_OMNICE_PREDICTION_HORIZ_Y	0x70
+#define OV511_OMNICE_PREDICTION_HORIZ_Y		0x70
 #define OV511_OMNICE_PREDICTION_HORIZ_UV	0x71
 #define OV511_OMNICE_PREDICTION_VERT_Y		0x72
-#define OV511_OMNICE_PREDICTION_VERT_UV	0x73
+#define OV511_OMNICE_PREDICTION_VERT_UV		0x73
 #define OV511_OMNICE_QUANTIZATION_HORIZ_Y	0x74
 #define OV511_OMNICE_QUANTIZATION_HORIZ_UV	0x75
 #define OV511_OMNICE_QUANTIZATION_VERT_Y	0x76
 #define OV511_OMNICE_QUANTIZATION_VERT_UV	0x77
-#define OV511_OMNICE_ENABLE					0x78
-#define OV511_OMNICE_LUT_ENABLE				0x79		
-#define OV511_OMNICE_Y_LUT_BEGIN			0x80
-#define OV511_OMNICE_Y_LUT_END				0x9F
-#define OV511_OMNICE_UV_LUT_BEGIN			0xA0
-#define OV511_OMNICE_UV_LUT_END				0xBF
+#define OV511_OMNICE_ENABLE			0x78
+#define OV511_OMNICE_LUT_ENABLE			0x79		
+#define OV511_OMNICE_Y_LUT_BEGIN		0x80
+#define OV511_OMNICE_Y_LUT_END			0x9F
+#define OV511_OMNICE_UV_LUT_BEGIN		0xA0
+#define OV511_OMNICE_UV_LUT_END			0xBF
 
 /* Alternate numbers for various max packet sizes (OV511 only) */
 #define OV511_ALT_SIZE_992	0
@@ -114,7 +118,7 @@
 #define OV511PLUS_ALT_SIZE_769	6
 #define OV511PLUS_ALT_SIZE_961	7
 
-/* ov7610 registers */
+/* OV7610 registers */
 #define OV7610_REG_GAIN          0x00
 #define OV7610_REG_BLUE          0x01
 #define OV7610_REG_RED           0x02
@@ -163,12 +167,12 @@
 
 #define SCRATCH_BUF_SIZE 384
 
-#define FRAMES_PER_DESC		10  /* FIXME - What should this be? */
+#define FRAMES_PER_DESC		10	/* FIXME - What should this be? */
 #define FRAME_SIZE_PER_DESC	993	/* FIXME - Deprecated */
-#define MAX_FRAME_SIZE_PER_DESC	993  /* For statically allocated stuff */
+#define MAX_FRAME_SIZE_PER_DESC	993	/* For statically allocated stuff */
 
 // FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
-#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
+#define OV511_ENDPOINT_ADDRESS 0x81	/* Address of isoc endpoint */
 
 // CAMERA SPECIFIC
 // FIXME - these can vary between specific models
@@ -213,7 +217,7 @@
 	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
 	FRAME_READY,		/* Ready to start grabbing */
 	FRAME_GRABBING,		/* In the process of being grabbed into */
-	FRAME_DONE,			/* Finished grabbing, but not been synced yet */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
 	FRAME_ERROR,		/* Something bad happened while processing */
 };
 
@@ -238,7 +242,7 @@
 	int hdrheight;		/* Height */
 
 	int sub_flag;		/* Sub-capture mode for this frame? */
-	int format;			/* Format for this frame */
+	int format;		/* Format for this frame */
 	int segsize;		/* How big is each segment from the camera? */
 
 	volatile int grabstate;	/* State of grabbing */
@@ -253,7 +257,7 @@
 
 	wait_queue_head_t wq;	/* Processes waiting */
 
-	int snapshot;			/* True if frame was a snapshot */
+	int snapshot;		/* True if frame was a snapshot */
 };
 
 #define OV511_NUMFRAMES	2
@@ -261,23 +265,28 @@
 
 struct usb_ov511 {
 	struct video_device vdev;
-	
+
 	/* Device structure */
 	struct usb_device *dev;
 
+#if 0
 	unsigned char customid; /* Type of camera */
+#else
+	int customid;
+	int desc;
+#endif
 
 	unsigned char iface;
-	
+
 	struct semaphore lock;
-	int user;			/* user count for exclusive use */
+	int user;		/* user count for exclusive use */
 
 	int streaming;		/* Are we streaming Isochronous? */
 	int grabbing;		/* Are we grabbing? */
 
 	int compress;		/* Should the next frame be compressed? */
 
-	char *fbuf;			/* Videodev buffer area */
+	char *fbuf;		/* Videodev buffer area */
 
 	int sub_flag;		/* Pix Array subcapture on flag */
 	int subx;		/* Pix Array subcapture x offset */
@@ -297,12 +306,22 @@
 
 	wait_queue_head_t wq;	/* Processes waiting */
 
-	int snap_enabled;   /* Snapshot mode enabled */
+	int snap_enabled;	/* Snapshot mode enabled */
 	
-	int bridge;         /* Type of bridge (OV511 or OV511+) */
-	int sensor;         /* Type of image sensor chip */
+	int bridge;		/* Type of bridge (OV511 or OV511+) */
+	int sensor;		/* Type of image sensor chip */
+
+	int packet_size;	/* Frame size per isoc desc */
+
+				/* proc interface */
+	struct semaphore param_lock;	/* params lock for this camera */
+	struct proc_dir_entry *proc_entry;	/* /proc/ov511/videoX */
+};
+
 
-	int packet_size;    /* Frame size per isoc desc */
+struct cam_list {
+	int id;
+	char *description;
 };
 
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.3.99-pre6/linux/drivers/usb/pegasus.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/pegasus.c	Mon May  8 15:48:18 2000
@@ -24,7 +24,7 @@
 #define	SROM_WRITE		0x01
 #define	SROM_READ		0x02
 #define	PEGASUS_TX_TIMEOUT	(HZ*5)
-#define	ALIGN(x)		x __attribute__((aligned(16)))
+#define	ALIGN(x)		x __attribute__((aligned(L1_CACHE_BYTES)))
 
 struct pegasus {
 	struct usb_device	*usb;
@@ -64,6 +64,8 @@
 	{"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL},
 	{"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL},
 	{"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
+	{"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL},
+	{"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL},
 	{NULL, 0, 0, NULL}
 };
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c
--- v2.3.99-pre6/linux/drivers/usb/plusb.c	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/plusb.c	Thu May  4 11:31:21 2000
@@ -465,8 +465,7 @@
 	if(!s->opened && s->net_dev.name) {
 		dbg("unregistering netdev: %s",s->net_dev.name);
 		unregister_netdev(&s->net_dev);
-		kfree(s->net_dev.name);
-		s->net_dev.name=NULL;
+		s->net_dev.name[0] = '\0';
 	}
 	
 	dbg("plusb_disconnect: finished");
@@ -524,22 +523,15 @@
 		return NULL;
 	}
 
-	if(!s->net_dev.name) {
-		s->net_dev.name=kmalloc(16, GFP_KERNEL);
-
-		if(!s->net_dev.name || dev_alloc_name(&s->net_dev,"plusb%d")<0)	{
-			err("alloc name failed\n");
-			return NULL;
-		}
-
+	if(!s->net_dev.name[0]) {
+		strcpy(s->net_dev.name, "plusb%d");
 		s->net_dev.init=plusb_net_init;
 		s->net_dev.priv=s;
 		if(!register_netdev(&s->net_dev))
 			info("registered: %s", s->net_dev.name);
 		else {
 			err("register_netdev failed");
-			kfree(s->net_dev.name);
-			s->net_dev.name=NULL;
+			s->net_dev.name[0] = '\0';
 		}
 	}
 		
@@ -598,11 +590,9 @@
 	dbg("plusb_cleanup");
 	for (u = 0; u < NRPLUSB; u++) {
 		plusb_t *s = &plusb[u];
-		if(s->net_dev.name) {
+		if(s->net_dev.name[0]) {
 			dbg("unregistering netdev: %s",s->net_dev.name);
 			unregister_netdev(&s->net_dev);
-			kfree(s->net_dev.name);
-			s->net_dev.name=NULL;
 		}
 	}
 	usb_deregister (&plusb_driver);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.3.99-pre6/linux/drivers/usb/scanner.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/scanner.c	Tue May  2 13:49:18 2000
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.3.99-pre3-7)
+ * Driver for USB Scanners (linux-2.3.99-pre6-3)
  *
  * Copyright (C) 1999, 2000 David E. Nelson
  *
@@ -54,7 +54,7 @@
  *    - Removed unnessesary #include's
  *    - Scanner model now reported via syslog INFO after being detected 
  *      *and* configured.
- *    - Added user specified verdor:product USB ID's which can be passed 
+ *    - Added user specified vendor:product USB ID's which can be passed 
  *      as module parameters.
  *
  *
@@ -168,6 +168,32 @@
  *      -EINTR.
  *
  *
+ * 0.4.3  4/30/2000
+ *
+ *    - Added Umax Astra 2200 ID.  Thanks to Flynn Marquardt 
+ *      <flynn@isr.uni-stuttgart.de>.
+ *    - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
+ *    - Added access time update for the device file courtesy of Paul
+ *      Mackerras <paulus@linuxcare.com>.  This allows a user space daemon
+ *      to turn the lamp off for a Umax 1220U scanner after a prescribed
+ *      time.
+ *    - Fixed HP S20 ID's.  Thanks to Ruud Linders <rlinders@xs4all.nl>.
+ *    - Added Acer ScanPrisa 620U ID. Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
+ *    - Fixed bug in read_scanner for copy_to_user() function.  The returned
+ *      value should be 'partial' not 'this_read'.
+ *    - Fixed bug in read_scanner. 'count' should be decremented 
+ *      by 'this_read' and not by 'partial'.  This resulted in twice as many
+ *      calls to read_scanner() for small amounts of data and possibly
+ *      unexpected returns of '0'.  Thanks to Karl Heinz 
+ *      Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
+ *      for discovering this.
+ *    - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
+ *      scanner lookup/ident table. Thanks Randy.
+ *    - Documentation updates.
+ *    - Added wait queues to read_scanner().
+ *
+ *
  *  TODO
  *
  *    - Performance
@@ -186,7 +212,9 @@
  *    - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
  *      issue with HP-4100 and uhci.
  *    - Adolfo Montero for his assistance.
- *    - And anybody else who chimed in with reports and suggestions.
+ *    - All the folks who chimed in with reports and suggestions.
+ *    - All the developers that are working on USB SANE backends or other
+ *      applications to use USB scanners.
  *
  *  Performance:
  *
@@ -196,16 +224,19 @@
  *       8 Bit Gray  ~ 17 secs - 4.2 Mbit/sec
  */
 
+/* 
+ * Scanner definitions, macros, module info, 
+ * debug/ioctl/data_dump enable, and other constants.
+ */ 
 #include "scanner.h"
 
-
 static void
 irq_scanner(struct urb *urb)
 {
 
 /*
  * For the meantime, this is just a placeholder until I figure out what
- * all I want to do with it.
+ * all I want to do with it -- or somebody else for that matter.
  */
 
 	struct scn_usb_data *scn = urb->context;
@@ -234,7 +265,7 @@
 	dbg("open_scanner: scn_minor:%d", scn_minor);
 
 	if (!p_scn_table[scn_minor]) {
-		err("open_scanner(%d): invalid scn_minor", scn_minor);
+		err("open_scanner(%d): Unable to access minor data", scn_minor);
 		return -ENODEV;
 	}
 
@@ -243,17 +274,22 @@
 	dev = scn->scn_dev;
 
 	if (!dev) {
+		err("open_scanner(%d): Scanner device not present", scn_minor);
 		return -ENODEV;
 	}
 
 	if (!scn->present) {
+		err("open_scanner(%d): Scanner is not present", scn_minor);
 		return -ENODEV;
 	}
 
 	if (scn->isopen) {
+		err("open_scanner(%d): Scanner device is already open", scn_minor);
 		return -EBUSY;
 	}
 
+	init_waitqueue_head(&scn->rd_wait_q);
+
 	scn->isopen = 1;
 
 	file->private_data = scn; /* Used by the read and write metheds */
@@ -316,6 +352,8 @@
 
 	dev = scn->scn_dev;
 
+	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+
 	while (count > 0) {
 
 		if (signal_pending(current)) {
@@ -365,7 +403,6 @@
 			bytes_written += partial;
 		} else { /* No data written */
 			ret = 0;
-			bytes_written = 0;
 			break;
 		}
 	}
@@ -388,6 +425,7 @@
 	int partial;		/* Number of bytes successfully read */
 	int this_read;		/* Max number of bytes to read */
 	int result;
+	int rd_expire = RD_EXPIRE;
 
 	char *ibuf;
 
@@ -402,7 +440,12 @@
 	bytes_read = 0;
 	ret = 0;
 
-	while (count) {
+	file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
+                                                            atime of
+                                                            the device
+                                                            node */
+
+	while (count > 0) {
 		if (signal_pending(current)) {
 			ret = -EINTR;
 			break;
@@ -410,13 +453,34 @@
 
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 		
-		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 120*HZ);
-		dbg("read stats(%d): result:%d this_read:%d partial:%d", scn_minor, result, this_read, partial);
+		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT);
+		dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
 
-		if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
-			warn("read_scanner(%d): NAK received", scn_minor);
-			ret = -ETIME;
-			break;
+/* 
+ * Scanners are sometimes inheriently slow since they are mechanical
+ * in nature.  USB bulk reads tend to timeout while the scanner is
+ * positioning, resetting, warming up the lamp, etc if the timeout is
+ * set too low.  A very long timeout parameter for bulk reads was used
+ * to overcome this limitation, but this sometimes resulted in folks
+ * having to wait for the timeout to expire after pressing Ctrl-C from
+ * an application. The user was sometimes left with the impression
+ * that something had hung or crashed when in fact the USB read was
+ * just waiting on data.  So, the below code retains the same long
+ * timeout period, but splits it up into smaller parts so that
+ * Ctrl-C's are acted upon in a reasonable amount of time. 
+ */
+
+		if (result == USB_ST_TIMEOUT && !partial) { /* Timeout
+                                                               and no
+                                                               data */
+			if (--rd_expire <= 0) {
+				warn("read_scanner(%d): excessive NAK's received", scn_minor);
+				ret = -ETIME;
+				break;
+			} else {
+				interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT);
+				continue;
+			}
 		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
 			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
 			ret = -EIO;
@@ -436,19 +500,17 @@
 #endif
 
 		if (partial) { /* Data returned */
-			if (copy_to_user(buffer, ibuf, this_read)) {
+			if (copy_to_user(buffer, ibuf, partial)) {
 				ret = -EFAULT;
 				break;
 			}
-			count -= partial;
-			bytes_read += partial;
+			count -= this_read; /* Compensate for short reads */
+			bytes_read += partial; /* Keep tally of what actually was read */
 			buffer += partial;
-			
 		} else {
 			ret = 0;
 			break;
 		}
-		
 	}
 	
 	return ret ? ret : bytes_read;
@@ -462,6 +524,7 @@
 	struct usb_endpoint_descriptor *endpoint;
 	
 	int ep_cnt;
+	int ix;
 
 	kdev_t scn_minor;
 
@@ -497,120 +560,20 @@
  * Until we detect a device which is pleasing, we silently punt.
  */
 
-	do {
-		if (dev->descriptor.idVendor == 0x03f0) {          /* Hewlett Packard */
-			if (dev->descriptor.idProduct == 0x0205 || /* 3300C */
-			    dev->descriptor.idProduct == 0x0101 || /* 4100C */
-			    dev->descriptor.idProduct == 0x0105 || /* 4200C */
-			    dev->descriptor.idProduct == 0x0202 || /* PhotoSmart S20 */
-			    dev->descriptor.idProduct == 0x0401 || /* 5200C */
-			    dev->descriptor.idProduct == 0x0201 || /* 6200C */
-			    dev->descriptor.idProduct == 0x0601) { /* 6300C */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x06bd) {	   /* Agfa */
-		    	if (dev->descriptor.idProduct == 0x0001 || /* SnapScan 1212U */
-		    	    dev->descriptor.idProduct == 0x2061 || /* Another SnapScan 1212U (?) */
-		    	    dev->descriptor.idProduct == 0x0100) { /* SnapScan Touch */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x1606) {          /* Umax */
-			if (dev->descriptor.idProduct == 0x0010 || /* Astra 1220U */
-			    dev->descriptor.idProduct == 0x0030 || /* Astra 2000U */
-			    dev->descriptor.idProduct == 0x0002) { /* Astra 1236U */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x04b8)	{          /* Seiko/Epson Corp. */
-			if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636U and 636Photo */
-			    dev->descriptor.idProduct == 0x0103 || /* Perfection 610 */
-			    dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U and 1200Photo */
-				valid_device = 1;
-				break;
-			}
-		}
-
-		if (dev->descriptor.idVendor == 0x055f)	{          /* Mustek */
-			if (dev->descriptor.idProduct == 0x0001) { /* 1200 CU */
-				valid_device = 1;
-				break;
-			}
-		}
-
-		if (dev->descriptor.idVendor == 0x05da) {          /* Microtek */
-			if (dev->descriptor.idProduct == 0x0099 || /* ScanMaker X6 - X6U */
-			    dev->descriptor.idProduct == 0x0094 || /* Phantom 336CX - C3 */
-			    dev->descriptor.idProduct == 0x00a0 || /* Phantom 336CX - C3 #2 */
-			    dev->descriptor.idProduct == 0x009a || /* Phantom C6 */
-			    dev->descriptor.idProduct == 0x00a3 || /* ScanMaker V6USL */
-			    dev->descriptor.idProduct == 0x80a3 || /* ScanMaker V6USL #2 */
-			    dev->descriptor.idProduct == 0x80ac) { /* ScanMaker V6UL - SpicyU */
-				valid_device = 1;
-				break;
-			}
-		}
-
-		if (dev->descriptor.idVendor == 0x0461) {          /* Primax/Colorado */
-			if (dev->descriptor.idProduct == 0x0300 || /* G2-300 #1 */
-			    dev->descriptor.idProduct == 0x0380 || /* G2-600 #1 */
-			    dev->descriptor.idProduct == 0x0301 || /* G2E-300 */
-			    dev->descriptor.idProduct == 0x0381 || /* ReadyScan 636i */
-			    dev->descriptor.idProduct == 0x0302 || /* G2-300 #2 */
-			    dev->descriptor.idProduct == 0x0382 || /* G2-600 #2 */
-			    dev->descriptor.idProduct == 0x0303 || /* G2E-300 */
-			    dev->descriptor.idProduct == 0x0383 || /* G2E-600 */
-			    dev->descriptor.idProduct == 0x0340 || /* Colorado USB 9600 */
-			    dev->descriptor.idProduct == 0x0360 || /* Colorado USB 19200 */
-			    dev->descriptor.idProduct == 0x0341 || /* Colorado 600u */
-			    dev->descriptor.idProduct == 0x0361) { /* Colorado 1200u */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x04a7) {          /* Visioneer */
-			if (dev->descriptor.idProduct == 0x0221 || /* OneTouch 5300 */
-			    dev->descriptor.idProduct == 0x0221 || /* OneTouch 7600 */
-			    dev->descriptor.idProduct == 0x0231) { /* 6100 */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x0458) {          /* Genius */
-			if(dev->descriptor.idProduct == 0x2001) { /* ColorPage-Vivid Pro */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == 0x04a5) {          /* Acer */
-			if(dev->descriptor.idProduct == 0x2060) { /* Prisa Acerscan 620U */
-				valid_device = 1;
-				break;
-			}
-		}
-		
-		if (dev->descriptor.idVendor == vendor &&   /* User specified */
-		    dev->descriptor.idProduct == product) { /* User specified */
+	for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct scanner_device); ix++) {
+		if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
+		    (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
 			valid_device = 1;
 			break;
-		}
-		
-		
-	} while (0);
+                }
+	}
+	if (dev->descriptor.idVendor == vendor &&   /* User specified */
+	    dev->descriptor.idProduct == product) { /* User specified */
+		valid_device = 1;
+	}
 	
-	if (!valid_device)	
-		return NULL;	/* We didn't find anything pleasing */
-
+        if (!valid_device)
+                return NULL;    /* We didn't find anything pleasing */
 
 /*
  * After this point we can be a little noisy about what we are trying to
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.3.99-pre6/linux/drivers/usb/scanner.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/scanner.h	Tue May  2 13:49:18 2000
@@ -1,3 +1,26 @@
+/*
+ * Driver for USB Scanners (linux-2.3.99-pre6-3)
+ *
+ * Copyright (C) 1999, 2000 David E. Nelson
+ *
+ * David E. Nelson (dnelson@jump.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */ 
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -6,16 +29,28 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/ioctl.h>
+#include <linux/sched.h>
 
 // #define DEBUG
 
+#include <linux/usb.h>
+
+static __s32 vendor=-1, product=-1;
+
+MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
+MODULE_DESCRIPTION("USB Scanner Driver");
+
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+
 /* Enable to activate the ioctl interface.  This is mainly meant for */
 /* development purposes until an ioctl number is officially registered */
 // #define SCN_IOCTL
 
-#include <linux/usb.h>
-// #include "usb.h"
-
 /* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
 // #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
@@ -36,9 +71,12 @@
 #define IBUF_SIZE 32768
 #define OBUF_SIZE 4096
 
+/* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
+#define RD_NAK_TIMEOUT (10*HZ)	/* Number of X seconds to wait */
+#define RD_EXPIRE 12		/* Number of attempts to wait X seconds */
 
-/* FIXME: These are NOT registered ioctls()'s */
 
+/* FIXME: These are NOT registered ioctls()'s */
 #define PV8630_IOCTL_INREQUEST 69
 #define PV8630_IOCTL_OUTREQUEST 70
 
@@ -55,19 +93,74 @@
 	char present;		/* Not zero if device is present */
 	char *obuf, *ibuf;	/* transfer buffers */
 	char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
+	wait_queue_head_t rd_wait_q; /* read timeouts */
 };
 
 static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
 
-MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
-MODULE_DESCRIPTION("USB Scanner Driver");
-
-static __s32 vendor=-1, product=-1;
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
+/* table of scanners that may work with this driver */
+static const struct scanner_device {
+	__u16		idVendor;
+	__u16		idProduct;
+} scanner_device_ids [] = {
+	/* Acer */
+		{ 0x04a5, 0x2060 },	/* Prisa Acerscan 620U & 640U (!) */
+		{ 0x04a5, 0x2040 },	/* Prisa AcerScan 620U (!) */
+	/* Agfa */
+		{ 0x06bd, 0x0001 },	/* SnapScan 1212U */
+		{ 0x06bd, 0x2061 },	/* Another SnapScan 1212U (?) */
+		{ 0x06bd, 0x0100 },	/* SnapScan Touch */
+	/* Colorado -- See Primax/Colorado below */
+	/* Epson -- See Seiko/Epson below */
+	/* Genius */
+		{ 0x0458, 0x2001 },	/* ColorPage-Vivid Pro */
+	/* Hewlett Packard */
+		{ 0x03f0, 0x0205 },	/* 3300C */
+		{ 0x03f0, 0x0101 },	/* 4100C */
+		{ 0x03f0, 0x0105 },	/* 4200C */
+		{ 0x03f0, 0x0202 },	/* PhotoSmart S20 */
+		{ 0x03f0, 0x0401 },	/* 5200C */
+		{ 0x03f0, 0x0201 },	/* 6200C */
+		{ 0x03f0, 0x0601 },	/* 6300C */
+	/* iVina */
+		{ 0x0638, 0x0268 },     /* 1200U */
+	/* Microtek */
+		{ 0x05da, 0x0099 },	/* ScanMaker X6 - X6U */
+		{ 0x05da, 0x0094 },	/* Phantom 336CX - C3 */
+		{ 0x05da, 0x00a0 },	/* Phantom 336CX - C3 #2 */
+		{ 0x05da, 0x009a },	/* Phantom C6 */
+		{ 0x05da, 0x00a3 },	/* ScanMaker V6USL */
+		{ 0x05da, 0x80a3 },	/* ScanMaker V6USL #2 */
+		{ 0x05da, 0x80ac },	/* ScanMaker V6UL - SpicyU */
+	/* Mustek */
+		{ 0x055f, 0x0001 },	/* 1200 CU */
+	/* Primax/Colorado */
+		{ 0x0461, 0x0300 },	/* G2-300 #1 */
+		{ 0x0461, 0x0380 },	/* G2-600 #1 */
+		{ 0x0461, 0x0301 },	/* G2E-300 #1 */
+		{ 0x0461, 0x0381 },	/* ReadyScan 636i */
+		{ 0x0461, 0x0302 },	/* G2-300 #2 */
+		{ 0x0461, 0x0382 },	/* G2-600 #2 */
+		{ 0x0461, 0x0303 },	/* G2E-300 #2 */
+		{ 0x0461, 0x0383 },	/* G2E-600 */
+		{ 0x0461, 0x0340 },	/* Colorado USB 9600 */
+		{ 0x0461, 0x0360 },	/* Colorado USB 19200 */
+		{ 0x0461, 0x0341 },	/* Colorado 600u */
+		{ 0x0461, 0x0361 },	/* Colorado 1200u */
+	/* Seiko/Epson Corp. */
+		{ 0x04b8, 0x0101 },	/* Perfection 636U and 636Photo */
+		{ 0x04b8, 0x0103 },	/* Perfection 610 */
+		{ 0x04b8, 0x0104 },	/* Perfection 1200U and 1200Photo */
+	/* Umax */
+		{ 0x1606, 0x0010 },	/* Astra 1220U */
+		{ 0x1606, 0x0002 },	/* Astra 1236U */
+		{ 0x1606, 0x0030 },	/* Astra 2000U */
+		{ 0x1606, 0x0230 },	/* Astra 2200U */
+	/* Visioneer */
+		{ 0x04a7, 0x0221 },	/* OneTouch 5300 */
+		{ 0x04a7, 0x0221 },	/* OneTouch 7600 duplicate ID (!) */
+		{ 0x04a7, 0x0231 },	/* 6100 */
+};
 
 /* Forward declarations */
 static struct usb_driver scanner_driver;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- v2.3.99-pre6/linux/drivers/usb/serial/Makefile	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/Makefile	Thu May  4 11:35:13 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 omninet.o
+O_OBJS		:= usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o digi_acceleport.o
 MOD_LIST_NAME	:= USB_SERIAL_MODULES
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.3.99-pre6/linux/drivers/usb/serial/digi_acceleport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/digi_acceleport.c	Thu May  4 11:35:14 2000
@@ -0,0 +1,975 @@
+/*
+*  Digi AccelePort USB-4 Serial Converter
+*
+*  Copyright 2000 by Digi International
+*
+*  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.
+*
+*  Shamelessly based on Brian Warner's keyspan_pda.c and Greg Kroah-Hartman's
+*  usb-serial driver.
+*
+*  Peter Berger (pberger@brimson.com)
+*  Al Borchers (borchers@steinerpoint.com)
+*
+*  (5/3/2000) pberger and borchers
+*  First alpha version of the driver--many known limitations and bugs.
+*
+*  $Id: digi_acceleport.c,v 1.28 2000/05/04 01:47:08 root Exp root $
+*/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+
+/* Defines */
+
+/* port buffer length -- must be <= transfer buffer length - 2 */
+/* so we can be sure to send the full buffer in one urb */
+#define DIGI_PORT_BUF_LEN			16
+
+/* AccelePort USB Defines */
+
+/* ids */
+#define DIGI_VENDOR_ID				0x05c5
+#define DIGI_ID					0x0004
+
+/* commands */
+#define DIGI_CMD_SET_BAUD_RATE			0
+#define DIGI_CMD_SET_WORD_SIZE			1
+#define DIGI_CMD_SET_PARITY			2
+#define DIGI_CMD_SET_STOP_BITS			3
+#define DIGI_CMD_SET_INPUT_FLOW_CONTROL		4
+#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL	5
+#define DIGI_CMD_SET_DTR_SIGNAL			6
+#define DIGI_CMD_SET_RTS_SIGNAL			7
+#define DIGI_CMD_RECEIVE_ENABLE			10
+#define DIGI_CMD_BREAK_CONTROL			11
+#define DIGI_CMD_LOCAL_LOOPBACK			12
+#define DIGI_CMD_TRANSMIT_IDLE			13
+#define DIGI_CMD_WRITE_UART_REGISTER		15
+#define DIGI_CMD_AND_UART_REGISTER		16
+#define DIGI_CMD_OR_UART_REGISTER		17
+#define DIGI_CMD_SEND_DATA			18
+
+/* baud rates */
+#define DIGI_BAUD_50				0
+#define DIGI_BAUD_75				1
+#define DIGI_BAUD_110				2
+#define DIGI_BAUD_150				3
+#define DIGI_BAUD_200				4
+#define DIGI_BAUD_300				5
+#define DIGI_BAUD_600				6
+#define DIGI_BAUD_1200				7
+#define DIGI_BAUD_1800				8
+#define DIGI_BAUD_2400				9
+#define DIGI_BAUD_4800				10
+#define DIGI_BAUD_7200				11
+#define DIGI_BAUD_9600				12
+#define DIGI_BAUD_14400				13
+#define DIGI_BAUD_19200				14
+#define DIGI_BAUD_28800				15
+#define DIGI_BAUD_38400				16
+#define DIGI_BAUD_57600				17
+#define DIGI_BAUD_76800				18
+#define DIGI_BAUD_115200			19
+#define DIGI_BAUD_153600			20
+#define DIGI_BAUD_230400			21
+#define DIGI_BAUD_460800			22
+
+/* flow control arguments */
+#define DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL	1
+#define DIGI_ENABLE_RTS_CTS_FLOW_CONTROL	2
+#define DIGI_ENABLE_DTR_DSR_FLOW_CONTROL	4
+
+/* macros */
+#define MAX(a,b)	(((a)>(b))?(a):(b))
+#define MIN(a,b)	(((a)<(b))?(a):(b))
+
+
+/* Structures */
+
+typedef struct digi_private {
+	spinlock_t dp_port_lock;
+	int dp_buf_len;
+	char dp_buf[32];
+} digi_private_t;
+
+struct s_digiusb {
+	u8 opcode;
+	u8 length;
+	u8 val;
+	u8 pad;
+};
+
+
+/* Local Function Declarations */
+
+static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
+	int length, int val );
+static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 );
+static void digi_rx_throttle (struct usb_serial_port *port);
+static void digi_rx_unthrottle (struct usb_serial_port *port);
+static int digi_setbaud( struct usb_serial_port *port, int baud );
+static void digi_set_termios( struct usb_serial_port *port, 
+	struct termios *old_termios );
+static void digi_break_ctl( struct usb_serial_port *port, int break_state );
+static int digi_get_modem_info( struct usb_serial *serial,
+	unsigned char *value );
+static int digi_set_modem_info( struct usb_serial *serial,
+	unsigned char value );
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg );
+static int digi_write( struct usb_serial_port *port, int from_user,
+	const unsigned char *buf, int count );
+static void digi_write_bulk_callback( struct urb *urb );
+static int digi_write_room( struct usb_serial_port *port );
+static int digi_chars_in_buffer( struct usb_serial_port *port );
+static int digi_open( struct usb_serial_port *port, struct file *filp );
+static void digi_close( struct usb_serial_port *port, struct file *filp );
+static int digi_startup (struct usb_serial *serial);
+static void digi_shutdown( struct usb_serial *serial );
+static void digi_read_bulk_callback( struct urb *urb );
+
+
+/* Statics */
+
+/* device info needed for the Digi serial converter */
+static __u16	digi_vendor_id		= DIGI_VENDOR_ID;
+static __u16	digi_product_id		= DIGI_ID;
+
+/* out of band port */
+static int oob_port_num;					/* index of out-of-band port */
+static struct usb_serial_port *oob_port;	/* out-of-band control port */
+static int oob_read_started = 0;
+
+/* config lock -- used to protect digi statics and globals, like oob vars */
+spinlock_t config_lock;
+
+
+/* Globals */
+
+struct usb_serial_device_type digi_acceleport_device = {
+	name:			"Digi USB",
+	idVendor:		&digi_vendor_id,
+	idProduct:		&digi_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	0,
+	num_bulk_in:		5,
+	num_bulk_out:		5,
+	num_ports:		4,
+	open:			digi_open,
+	close:			digi_close,
+	write:			digi_write,
+	write_room:		digi_write_room,
+	write_bulk_callback:	digi_write_bulk_callback,
+	read_bulk_callback:	digi_read_bulk_callback,
+	chars_in_buffer:	digi_chars_in_buffer,
+	throttle:		digi_rx_throttle,
+	unthrottle:		digi_rx_unthrottle,
+	ioctl:			digi_ioctl,
+	set_termios:		digi_set_termios,
+	break_ctl:		digi_break_ctl,
+	startup:		digi_startup,
+	shutdown:		digi_shutdown,
+};
+
+
+/* Functions */
+
+/* Send message on the out-of-Band endpoint */
+static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 )
+{
+	int ret;
+	struct s_digiusb digiusb;
+	digi_private_t *priv = (digi_private_t *)(oob_port->private);
+
+
+dbg( "digi_send_oob: TOP: from '%s', opcode: %d, linenum:%d, data1: %d, data2: %d", mes, opcode, linenum, data1, data2 );
+
+	digiusb.opcode = (u8)opcode;
+	digiusb.length = (u8)linenum;
+	digiusb.val = (u8)data1;
+	digiusb.pad = (u8)data2;
+
+	spin_lock( &priv->dp_port_lock );
+
+	while (oob_port->write_urb->status == -EINPROGRESS) {
+dbg( "digi_send_oob: opcode:%d already writing...", opcode );
+		spin_unlock( &priv->dp_port_lock );
+		interruptible_sleep_on(&oob_port->write_wait);
+		if (signal_pending(current)) {
+			return;
+		}
+		spin_lock( &priv->dp_port_lock );
+	}
+
+	memcpy( oob_port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
+	oob_port->write_urb->transfer_buffer_length = sizeof(digiusb);
+	if( (ret=usb_submit_urb(oob_port->write_urb)) != 0 ) {
+		dbg(
+		"digi_send_oob: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
+		opcode, ret );
+	}
+
+	spin_unlock( &priv->dp_port_lock );
+
+dbg( "digi_send_oob: opcode %d done", opcode );
+
+}
+
+
+static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
+	int length, int val )
+{
+
+	int ret;
+	struct s_digiusb digiusb;
+	digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_send_cmd: TOP: from '%s', opcode: %d, val: %d", mes, opcode, val );
+
+	digiusb.opcode = (u8)opcode;
+	digiusb.length = (u8)length;
+	digiusb.val = (u8)val;
+	digiusb.pad = 0;
+
+	spin_lock( &priv->dp_port_lock );
+
+	while( port->write_urb->status == -EINPROGRESS ) {
+dbg( "digi_send_cmd: opcode=%d already writing...", opcode );
+		spin_unlock( &priv->dp_port_lock );
+		interruptible_sleep_on( &port->write_wait );
+		if( signal_pending(current) ) {
+			return;
+		}
+		spin_lock( &priv->dp_port_lock );
+	}
+
+	memcpy( port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
+	port->write_urb->transfer_buffer_length = sizeof(digiusb);
+	if( (ret=usb_submit_urb(port->write_urb)) != 0 )
+		dbg(
+		"digi_send_cmd: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
+		opcode, ret );
+
+dbg( "digi_send_cmd: opcode %d done", opcode );
+
+	spin_unlock( &priv->dp_port_lock );
+
+}
+
+
+static void digi_rx_throttle( struct usb_serial_port *port )
+{
+
+dbg( "digi_rx_throttle: TOP: port=%d", port->number );
+
+	/* stop receiving characters. We just turn off the URB request, and
+	   let chars pile up in the device. If we're doing hardware
+	   flowcontrol, the device will signal the other end when its buffer
+	   fills up. If we're doing XON/XOFF, this would be a good time to
+	   send an XOFF, although it might make sense to foist that off
+	   upon the device too. */
+
+	// usb_unlink_urb(port->interrupt_in_urb);
+
+}
+
+
+static void digi_rx_unthrottle( struct usb_serial_port *port )
+{
+
+dbg( "digi_rx_unthrottle: TOP: port=%d", port->number );
+
+	/* just restart the receive interrupt URB */
+	//if (usb_submit_urb(port->interrupt_in_urb))
+	//	dbg( "digi_rx_unthrottle: usb_submit_urb(read urb) failed" );
+
+}
+
+
+static int digi_setbaud( struct usb_serial_port *port, int baud )
+{
+
+	int bindex;
+
+
+dbg( "digi_setbaud: TOP: port=%d", port->number );
+
+	switch( baud ) {
+		case 50: bindex = DIGI_BAUD_50; break;
+		case 75: bindex = DIGI_BAUD_75; break;
+		case 110: bindex = DIGI_BAUD_110; break;
+		case 150: bindex = DIGI_BAUD_150; break;
+		case 200: bindex = DIGI_BAUD_200; break;
+		case 300: bindex = DIGI_BAUD_300; break;
+		case 600: bindex = DIGI_BAUD_600; break;
+		case 1200: bindex = DIGI_BAUD_1200; break;
+		case 1800: bindex = DIGI_BAUD_1800; break;
+		case 2400: bindex = DIGI_BAUD_2400; break;
+		case 4800: bindex = DIGI_BAUD_4800; break;
+		case 7200: bindex = DIGI_BAUD_7200; break;
+		case 9600: bindex = DIGI_BAUD_9600; break;
+		case 14400: bindex = DIGI_BAUD_14400; break;
+		case 19200: bindex = DIGI_BAUD_19200; break;
+		case 28800: bindex = DIGI_BAUD_28800; break;
+		case 38400: bindex = DIGI_BAUD_38400; break;
+		case 57600: bindex = DIGI_BAUD_57600; break;
+		case 76800: bindex = DIGI_BAUD_76800; break;
+		case 115200: bindex = DIGI_BAUD_115200; break;
+		case 153600: bindex = DIGI_BAUD_153600; break;
+		case 230400: bindex = DIGI_BAUD_230400; break;
+		case 460800: bindex = DIGI_BAUD_460800; break;
+		default:
+			dbg( "digi_setbaud: can't handle requested baud rate %d", baud );
+			return( -EINVAL );
+			break;
+	}
+
+	digi_send_cmd( "digi_setbaud:", port, DIGI_CMD_SET_BAUD_RATE, 2, bindex );
+
+	return( 0 );	/* FIX -- send_cmd should return a value??, return it */
+
+}
+
+
+static void digi_set_termios( struct usb_serial_port *port, 
+	struct termios *old_termios )
+{
+
+	unsigned int iflag = port->tty->termios->c_iflag;
+	unsigned int old_iflag = old_termios->c_iflag;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int old_cflag = old_termios->c_cflag;
+	int arg;
+
+
+dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", port->number, iflag, old_iflag, cflag, old_cflag );
+
+	/* set baud rate */
+	/* if( (cflag&CBAUD) != (old_cflag&CBAUD) ) */ {
+		switch( (cflag&CBAUD) ) {
+			case B50: digi_setbaud(port, 50); break;
+			case B75: digi_setbaud(port, 75); break;
+			case B110: digi_setbaud(port, 110); break;
+			case B150: digi_setbaud(port, 150); break;
+			case B200: digi_setbaud(port, 200); break;
+			case B300: digi_setbaud(port, 300); break;
+			case B600: digi_setbaud(port, 600); break;
+			case B1200: digi_setbaud(port, 1200); break;
+			case B1800: digi_setbaud(port, 1800); break;
+			case B2400: digi_setbaud(port, 2400); break;
+			case B4800: digi_setbaud(port, 4800); break;
+			case B9600: digi_setbaud(port, 9600); break;
+			case B19200: digi_setbaud(port, 19200); break;
+			case B38400: digi_setbaud(port, 38400); break;
+			case B57600: digi_setbaud(port, 57600); break;
+			case B115200: digi_setbaud(port, 115200); break;
+			default:
+				dbg( "digi_set_termios: can't handle baud rate 0x%x",
+					(cflag&CBAUD) );
+				break;
+		}
+	}
+
+	/* set input flow control */
+	/* if( (iflag&IXOFF) != (old_iflag&IXOFF)
+	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+
+		arg = 0;
+
+		if( (iflag&IXOFF) )
+			arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+		if( (cflag&CRTSCTS) )
+			arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+
+		digi_send_cmd( "digi_termios: set input flow control:", port,
+			DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, arg );
+
+	}
+
+	/* set output flow control */
+	/* if( (iflag&IXON) != (old_iflag&IXON)
+	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+
+		arg = 0;
+
+		if( (iflag&IXON) )
+			arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+		if( (cflag&CRTSCTS) )
+			arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+
+		digi_send_cmd( "digi_set_termios: set output flow control:", port,
+			DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, arg );
+
+	}
+
+}
+
+
+static void digi_break_ctl( struct usb_serial_port *port, int break_state )
+{
+dbg( "digi_break_ctl: TOP: port=%d", port->number );
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled;
+   DCD, RI, DSR, CTS are inputs and can be read */
+
+static int digi_get_modem_info( struct usb_serial *serial,
+	unsigned char *value )
+{
+dbg( "digi_get_modem_info: TOP" );
+	return( 0 );
+}
+
+
+static int digi_set_modem_info( struct usb_serial *serial,
+	unsigned char value )
+{
+dbg( "digi_set_modem_info: TOP" );
+	return( 0 );
+}
+
+
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg )
+{
+	struct usb_serial *serial = port->serial;
+	int rc;
+	unsigned int value;
+	unsigned char status, mask;
+
+dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", port->number, cmd );
+return( -ENOIOCTLCMD );
+
+	switch (cmd) {
+	case TIOCMGET: /* get modem pins state */
+		rc = digi_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		value =
+			((status & (1<<7)) ? TIOCM_DTR : 0) |
+			((status & (1<<6)) ? TIOCM_CAR : 0) |
+			((status & (1<<5)) ? TIOCM_RNG : 0) |
+			((status & (1<<4)) ? TIOCM_DSR : 0) |
+			((status & (1<<3)) ? TIOCM_CTS : 0) |
+			((status & (1<<2)) ? TIOCM_RTS : 0);
+		if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case TIOCMSET: /* set a state as returned by MGET */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		status =
+			((value & TIOCM_DTR) ? (1<<7) : 0) |
+			((value & TIOCM_CAR) ? (1<<6) : 0) |
+			((value & TIOCM_RNG) ? (1<<5) : 0) |
+			((value & TIOCM_DSR) ? (1<<4) : 0) |
+			((value & TIOCM_CTS) ? (1<<3) : 0) |
+			((value & TIOCM_RTS) ? (1<<2) : 0);
+		rc = digi_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMBIS: /* set bits in bitmask <arg> */
+	case TIOCMBIC: /* clear bits from bitmask <arg> */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		rc = digi_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		mask =
+			((value & TIOCM_RTS) ? (1<<2) : 0) |
+			((value & TIOCM_DTR) ? (1<<7) : 0);
+		if (cmd == TIOCMBIS)
+			status |= mask;
+		else
+			status &= ~mask;
+		rc = digi_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		return 0; /* TODO */
+	}
+	
+	return -ENOIOCTLCMD;
+}
+
+
+static int digi_write( struct usb_serial_port *port, int from_user,
+	const unsigned char *buf, int count )
+{
+
+	int i,ret,data_len,new_len;
+	digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",
+port->number, count, from_user, in_interrupt() );
+
+	/* be sure only one write proceeds at a time */
+	/* there are races on the port private buffer */
+	/* and races to check write_urb->status */
+	spin_lock( &priv->dp_port_lock );
+
+	/* wait for urb status clear to submit another urb */
+	if( port->write_urb->status == -EINPROGRESS ) {
+
+dbg( "digi_write: -EINPROGRESS set" );
+
+		/* buffer the data if possible */
+		new_len = MIN( count, DIGI_PORT_BUF_LEN-priv->dp_buf_len );
+		memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
+		priv->dp_buf_len += new_len;
+
+		/* unlock and return number of bytes buffered */
+		spin_unlock( &priv->dp_port_lock );
+dbg( "digi_write: buffering, return %d", new_len );
+		return( new_len );
+
+	}
+
+	/* allow space for any buffered data and for new data, up to */
+	/* transfer buffer size - 2 (for command and length bytes) */
+	new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
+	data_len = new_len + priv->dp_buf_len;
+
+dbg( "digi_write: counts: new data %d, buf data %d, total data %d (max %d)", new_len, priv->dp_buf_len, data_len, port->bulk_out_size-2 );
+
+	/* nothing to send */
+	if( data_len == 0 ) {
+		spin_unlock( &priv->dp_port_lock );
+		return( 0 );
+	}
+
+	/* set command and length bytes */
+	*((u8 *)(port->write_urb->transfer_buffer)) = (u8)DIGI_CMD_SEND_DATA;
+	*((u8 *)(port->write_urb->transfer_buffer)+1) = (u8)data_len;
+
+	/* set total transfer buffer length */
+	port->write_urb->transfer_buffer_length = data_len+2;
+
+	/* copy in buffered data first */
+	memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
+		priv->dp_buf_len );
+
+	/* copy in new data */
+	if( from_user ) {
+		copy_from_user( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
+			buf, new_len );
+	}
+	else {
+		memcpy( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
+			buf, new_len );
+	}  
+
+#ifdef DEBUG
+	printk( KERN_DEBUG __FILE__ ": digi_write: length=%d, data=",
+		port->write_urb->transfer_buffer_length );
+	for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
+		printk( "%.2x ",
+			((unsigned char *)port->write_urb->transfer_buffer)[i] );
+	}
+	printk( "\n" );
+#endif
+
+	/* submit urb */
+	if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+		/* submit successful, return length of new data written */
+		ret = new_len;
+		/* clear buffer */
+		priv->dp_buf_len = 0;
+	}
+	else {
+		dbg( "digi_write: usb_submit_urb(write bulk) failed, ret=%d", ret );
+		/* no bytes written - should we return the error code or 0? */
+		ret = 0;
+	}
+
+	/* return length of new data written, or error */
+dbg( "digi_write: returning %d", ret );
+	spin_unlock( &priv->dp_port_lock );
+	return( ret );
+
+} 
+
+
+static void digi_write_bulk_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+	struct tty_struct *tty = port->tty;
+	digi_private_t *priv = (digi_private_t *)(port->private);
+	int ret;
+
+
+dbg( "digi_write_bulk_callback: TOP: port=%d", port->number );
+
+	/* handle callback on out-of-band port */
+	if( port->number == oob_port_num ) {
+		dbg( "digi_write_bulk_callback: oob callback" );
+		wake_up_interruptible( &port->write_wait );
+		return;
+	}
+
+	/* sanity checks */
+	if( port_paranoia_check( port, "digi_write_bulk_callback" )
+	|| serial_paranoia_check( serial, "digi_write_bulk_callback" ) ) {
+		return;
+	}
+
+	/* try to send any buffered data on this port */
+	spin_lock( &priv->dp_port_lock );
+	if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) {
+
+		/* set command and length bytes */
+		*((u8 *)(port->write_urb->transfer_buffer))
+			= (u8)DIGI_CMD_SEND_DATA;
+		*((u8 *)(port->write_urb->transfer_buffer)+1)
+			= (u8)priv->dp_buf_len;
+
+		/* set total transfer buffer length */
+		port->write_urb->transfer_buffer_length = priv->dp_buf_len+2;
+
+		/* copy in buffered data */
+		memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
+			priv->dp_buf_len );
+
+		/* submit urb */
+dbg( "digi_write_bulk_callback: submit urb to write buffer, data len=%d",
+priv->dp_buf_len );
+		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+			/* successful, clear buffer */
+			priv->dp_buf_len = 0;
+		}
+		else {
+			dbg( "digi_write_bulk_callback: usb_submit_urb(write bulk) failed, ret=%d", ret );
+		}
+
+	}
+	spin_unlock( &priv->dp_port_lock );
+
+	/* wake up port processes */
+	wake_up_interruptible( &port->write_wait );
+
+	/* wake up line discipline */
+	tty = port->tty;
+	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup )
+		(tty->ldisc.write_wakeup)(tty);
+
+	/* wake up other tty processes */
+	wake_up_interruptible( &tty->write_wait );
+
+}
+
+
+static int digi_write_room( struct usb_serial_port *port )
+{
+
+	int room;
+	digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_write_room: TOP: port=%d", port->number );
+
+	spin_lock( &priv->dp_port_lock );
+
+	if( port->write_urb->status == -EINPROGRESS )
+		room = 0;
+	else
+		room = port->bulk_out_size - 2 - priv->dp_buf_len;
+
+	spin_unlock( &priv->dp_port_lock );
+
+dbg( "digi_write_room: return room=%d", room );
+	return( room );
+
+}
+
+
+static int digi_chars_in_buffer( struct usb_serial_port *port )
+{
+
+	digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_chars_in_buffer: TOP: port=%d", port->number );
+
+	if( port->write_urb->status == -EINPROGRESS ) {
+dbg( "digi_chars_in_buffer: return=%d", port->bulk_out_size );
+		return( port->bulk_out_size );
+	}
+	else {
+dbg( "digi_chars_in_buffer: return=%d", priv->dp_buf_len );
+		return( priv->dp_buf_len );
+	}
+
+}
+
+
+static int digi_open( struct usb_serial_port *port, struct file *filp )
+{
+
+	int ret;
+	digi_private_t *priv = (digi_private_t *)(port->private);
+
+
+dbg( "digi_open: TOP: port %d", port->number );
+
+	/* if port is already open, just return */
+	/* be sure exactly one open succeeds */
+	spin_lock( &priv->dp_port_lock );
+	if( port->active ) {
+		return( 0 );
+	}
+	port->active = 1;
+	spin_unlock( &priv->dp_port_lock );
+ 
+	/* start reading from the out-of-band port for the device */
+	/* be sure this happens exactly once */
+	spin_lock( &config_lock );
+	if( !oob_read_started ) {
+		if( (ret=usb_submit_urb(oob_port->read_urb)) != 0 ) {
+			dbg( "digi_open: usb_submit_urb(read bulk) for oob failed, ret=%d",
+				ret );
+			spin_unlock( &config_lock );
+			return( -ENXIO );
+		}
+		else {
+dbg( "digi_open: usb_submit_urb(read bulk) for oob succeeded" );
+			oob_read_started = 1;
+		}
+	}
+	spin_unlock( &config_lock );
+
+	/* initialize port */
+dbg( "digi_open: init..." );
+	/* set 9600, 8N1, DTR, RTS, RX enable, no input or output flow control */
+	digi_setbaud( port, 9600 );
+	digi_send_cmd( "digi_open: wordsize", port, DIGI_CMD_SET_WORD_SIZE, 2, 3 );
+	digi_send_cmd( "digi_open: parity", port, DIGI_CMD_SET_PARITY, 2, 0 );
+	digi_send_cmd( "digi_open: stopbits", port, DIGI_CMD_SET_STOP_BITS, 2, 0 );
+	digi_send_cmd( "digi_open: DTR on", port, DIGI_CMD_SET_DTR_SIGNAL, 2, 1 );
+	digi_send_cmd( "digi_open: RTS on", port, DIGI_CMD_SET_RTS_SIGNAL, 2, 1 );
+	digi_send_cmd( "digi_open: RX enable on", port, DIGI_CMD_RECEIVE_ENABLE, 2,
+		1 );
+	digi_send_cmd( "digi_open: input flow control off", port,
+		DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, 0 );
+	digi_send_cmd( "digi_open: output flow control off", port,
+		DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, 0 );
+
+	/* start reading from the device */
+	if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+		dbg( "digi_open: usb_submit_urb(read bulk) failed, ret=%d", ret );
+		return( -ENXIO );
+	}
+
+dbg( "digi_open: done" );
+	return( 0 );
+
+}
+
+
+static void digi_close( struct usb_serial_port *port, struct file *filp )
+{
+
+dbg( "digi_close: TOP: port %d", port->number );
+	
+	/* Need to change the control lines here */
+	/* TODO */
+dbg( "digi_close: wanna clear DTR and RTS..." );
+
+//digi_send_cmd( "digi_close DTR off", port, 6, 2, 0);	// clear DTR
+//digi_send_cmd( "digi_close RTS off", port, 7, 2, 0);	// clear RTS
+//digi_send_cmd( "digi_close RX disable", port, 10, 2, 0);	// Rx Disable
+
+digi_send_oob( "digi_close RTS off", DIGI_CMD_SET_RTS_SIGNAL,
+	port->number, 0, 0 );	// clear RTS
+digi_send_oob( "digi_close DTR off", DIGI_CMD_SET_DTR_SIGNAL,
+	port->number, 0, 0 );	// clear DTR
+
+	while( oob_port->write_urb->status == -EINPROGRESS ) {
+dbg ("digi_close: waiting for final writes to complete on oob port %d...", oob_port->number );
+		interruptible_sleep_on( &oob_port->write_wait );
+		if( signal_pending(current) ) {
+			break;
+		}
+	}
+	
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+
+	port->active = 0;
+
+}
+
+
+static int digi_startup (struct usb_serial *serial)
+{
+
+	int i;
+	digi_private_t *priv;
+
+
+dbg( "digi_startup: TOP" );
+
+	/* initialize config lock */
+	spin_lock_init( &config_lock );
+
+	/* allocate the private data structures for all ports */
+	/* number of regular ports + 1 for the out-of-band port */
+	for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+
+		/* allocate private structure */
+		priv = serial->port[i].private =
+			(digi_private_t *)kmalloc( sizeof(struct digi_private),
+			GFP_KERNEL );
+		if( priv == (digi_private_t *)0 )
+			return( 1 );				/* error */
+
+		/* initialize private structure */
+		priv->dp_buf_len = 0;
+		spin_lock_init( &priv->dp_port_lock );
+
+		/* initialize write wait queue for this port */
+		init_waitqueue_head(&serial->port[i].write_wait);
+
+	}
+
+	/* initialize out of band port info */
+	oob_port_num = digi_acceleport_device.num_ports;
+	oob_port = &serial->port[oob_port_num];
+	oob_read_started = 0;
+
+	return( 0 );
+
+}
+
+
+static void digi_shutdown( struct usb_serial *serial )
+{
+
+	int i;
+
+
+dbg( "digi_shutdown: TOP" );
+
+	/* stop writing and reading from the out-of-band port */
+	usb_unlink_urb( oob_port->write_urb );
+	usb_unlink_urb( oob_port->read_urb );
+	oob_read_started = 0;
+
+	/* free the private data structures for all ports */
+	/* number of regular ports + 1 for the out-of-band port */
+	for( i=0; i<digi_acceleport_device.num_ports+1; i++ )
+		kfree( serial->port[i].private );
+
+}
+
+
+static void digi_read_bulk_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+	struct tty_struct *tty = port->tty;
+	unsigned char *data = urb->transfer_buffer;
+	int ret,i;
+
+
+dbg( "digi_read_bulk_callback: TOP: port=%d", port->number );
+
+	/* handle oob callback */
+	if( port->number == oob_port_num ) {
+dbg( "digi_read_bulk_callback: oob_port callback, opcode=%d, line=%d, status=%d, ret=%d", data[0], data[1], data[2], data[3] );
+		if( urb->status ) {
+			dbg( "digi_read_bulk_callback: nonzero read bulk status on oob: %d",
+				urb->status );
+		}
+		if( (ret=usb_submit_urb(urb)) != 0 ) {
+			dbg( "digi_read_bulk_callback: failed resubmitting oob urb, ret=%d",
+				ret );
+		}
+		return;
+	}
+
+	/* sanity checks */
+	if( port_paranoia_check( port, "digi_read_bulk_callback" )
+	|| serial_paranoia_check( serial, "digi_read_bulk_callback" ) ) {
+		return;
+	}
+
+	/* check status */
+	if( urb->status ) {
+		dbg( "digi_read_bulk_callback: nonzero read bulk status: %d",
+			urb->status );
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: length=%d, data=",
+			urb->actual_length );
+		for( i=0; i<urb->actual_length; ++i ) {
+			printk( "%.2x ", data[i] );
+		}
+		printk( "\n" );
+	}
+#endif
+
+	/* Digi read packets are:												 */
+	/* 0         1      2         3       4    ...     3+length-1 == 2+length*/
+	/* opcode, length, status, data[0], data[1]...data[length-2]			 */
+	if( urb->actual_length > 3 ) {
+		for( i=3; i<2+data[1]; ++i ) {
+			 tty_insert_flip_char(tty, data[i], 0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue trying to read */
+	if( (ret=usb_submit_urb(urb)) != 0 )
+		dbg( "digi_read_bulk_callback: failed resubmitting read urb, ret=%d",
+			ret );
+
+}
+
+#endif	/* CONFIG_USB_SERIAL_DIGI_ACCELEPORT */
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/ezusb_convert.pl linux/drivers/usb/serial/ezusb_convert.pl
--- v2.3.99-pre6/linux/drivers/usb/serial/ezusb_convert.pl	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/ezusb_convert.pl	Fri May  5 13:41:30 2000
@@ -16,8 +16,8 @@
     # ':' <len> <addr> <type> <len-data> <crc> '\r'
     #  len, type, crc are 2-char hex, addr is 4-char hex. type is 00 for
     # normal records, 01 for EOF
-    my($lenstring, $addrstring, $typestring, $reststring) =
-      /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)$/;
+    my($lenstring, $addrstring, $typestring, $reststring, $doscrap) =
+      /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)(\r?)$/;
     die "malformed line: $_" unless $reststring;
     last if $typestring eq '01';
     my($len) = hex($lenstring);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.3.99-pre6/linux/drivers/usb/serial/ftdi_sio.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/ftdi_sio.c	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB FTDI SIO driver
  *
- * 	(C) Copyright (C) 1999, 2000
+ * 	Copyright (C) 1999, 2000
  * 	    Greg Kroah-Hartman (greg@kroah.com)
  *          Bill Ryder (bryder@sgi.com)
  *
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.3.99-pre6/linux/drivers/usb/serial/keyspan_pda.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/keyspan_pda.c	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB Keyspan PDA Converter driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.3.99-pre6/linux/drivers/usb/serial/omninet.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/omninet.c	Fri May  5 13:41:30 2000
@@ -8,6 +8,8 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * Please report both successes and troubles to the author at omninet@kroah.com
+ *
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h
--- v2.3.99-pre6/linux/drivers/usb/serial/usb-serial.h	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/usb-serial.h	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
 #include <linux/config.h>
 
 #define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
-#define SERIAL_TTY_MINORS	16	/* Actually we are allowed 255, but this is good for now */
+#define SERIAL_TTY_MINORS	255	/* loads of devices :) */
 
 #define MAX_NUM_PORTS		8	/* The maximum number of ports one device can grab at once */
 
@@ -123,6 +123,7 @@
 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;
+extern struct usb_serial_device_type digi_acceleport_device;
 
 
 /* determine if we should include the EzUSB loader functions */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.3.99-pre6/linux/drivers/usb/serial/usbserial.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/serial/usbserial.c	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -14,6 +14,16 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/03/2000) gkh
+ *	Added the Digi Acceleport driver from Al Borchers and Peter Berger.
+ * 
+ * (05/02/2000) gkh
+ *	Changed devfs and tty register code to work properly now. This was based on
+ *	the ACM driver changes by Vojtech Pavlik.
+ *
+ * (04/27/2000) Ryan VanderBijl
+ * 	Put calls to *_paranoia_checks into one function.
+ * 
  * (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.
@@ -282,15 +292,13 @@
 #ifdef CONFIG_USB_SERIAL_OMNINET
 	&zyxel_omninet_device,
 #endif
+#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+	&digi_acceleport_device,
+#endif
 	NULL
 };
 
 
-/* variables needed for the tty_driver structure */
-static char *driver_name	= "usb";
-static char *tty_driver_name	= "usb/tty/%d";
-
-
 /* local function prototypes */
 static int  serial_open (struct tty_struct *tty, struct file * filp);
 static void serial_close (struct tty_struct *tty, struct file * filp);
@@ -312,12 +320,27 @@
 };
 
 static int			serial_refcount;
+static struct tty_driver	serial_tty_driver;
 static struct tty_struct *	serial_tty[SERIAL_TTY_MINORS];
 static struct termios *		serial_termios[SERIAL_TTY_MINORS];
 static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
 static struct usb_serial	*serial_table[SERIAL_TTY_MINORS] = {NULL, };
 
 
+static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) 
+{ 
+	/* if no port was specified, or it fails a paranoia check */
+	if (!port || 
+		port_paranoia_check (port, function) ||
+		serial_paranoia_check (port->serial, function)) {
+		/* then say that we dont have a valid usb_serial thing, which will
+		 * end up genrating -ENODEV return values */ 
+		return NULL;
+	}
+
+	return port->serial;
+}
+
 
 static struct usb_serial *get_serial_by_minor (int minor)
 {
@@ -357,7 +380,7 @@
 		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
 			serial_table[i] = serial;
 		return serial;
-		}
+	}
 	return NULL;
 }
 
@@ -454,16 +477,9 @@
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
+	struct usb_serial *serial = get_usb_serial (port, "serial_close");
 
-	dbg("serial_close");
-
-	if (port_paranoia_check (port, "serial_close")) {
-		return;
-	}
-
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_close")) {
+	if (!serial) {
 		return;
 	}
 
@@ -486,16 +502,9 @@
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_write");
+	struct usb_serial *serial = get_usb_serial (port, "serial_write");
 	
-	if (port_paranoia_check (port, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_write")) {
+	if (!serial) {
 		return -ENODEV;
 	}
 	
@@ -518,26 +527,19 @@
 static int serial_write_room (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_write_room");
-	
-	if (port_paranoia_check (port, "serial_write")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_write")) {
+	struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+
+	if (!serial) {
 		return -ENODEV;
 	}
-	
+
 	dbg("serial_write_room port %d", port->number);
 	
 	if (!port->active) {
 		dbg ("port not open");
 		return -EINVAL;
 	}
-	
+
 	/* pass on to the driver specific version of this function if it is available */
 	if (serial->type->write_room) {
 		return (serial->type->write_room(port));
@@ -550,24 +552,17 @@
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_chars_in_buffer");
-	
-	if (port_paranoia_check (port, "serial_chars_in_buffer")) {
-		return -ENODEV;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+	struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+
+	if (!serial) {
 		return -ENODEV;
 	}
-	
+
 	if (!port->active) {
 		dbg ("port not open");
 		return -EINVAL;
 	}
-	
+
 	/* pass on to the driver specific version of this function if it is available */
 	if (serial->type->chars_in_buffer) {
 		return (serial->type->chars_in_buffer(port));
@@ -580,21 +575,14 @@
 static void serial_throttle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_throttle");
-	
-	if (port_paranoia_check (port, "serial_throttle")) {
-		return;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_throttle")) {
+	struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+
+	if (!serial) {
 		return;
 	}
-	
+
 	dbg("serial_throttle port %d", port->number);
-	
+
 	if (!port->active) {
 		dbg ("port not open");
 		return;
@@ -612,21 +600,14 @@
 static void serial_unthrottle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_unthrottle");
-	
-	if (port_paranoia_check (port, "serial_unthrottle")) {
-		return;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_unthrottle")) {
+	struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+
+	if (!serial) {
 		return;
 	}
-	
+
 	dbg("serial_unthrottle port %d", port->number);
-	
+
 	if (!port->active) {
 		dbg ("port not open");
 		return;
@@ -644,21 +625,14 @@
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_ioctl");
-	
-	if (port_paranoia_check (port, "serial_ioctl")) {
-		return -ENODEV;
-	}
+	struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_ioctl")) {
+	if (!serial) {
 		return -ENODEV;
 	}
-	
+
 	dbg("serial_ioctl port %d", port->number);
-	
+
 	if (!port->active) {
 		dbg ("port not open");
 		return -ENODEV;
@@ -676,16 +650,9 @@
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_set_termios");
-	
-	if (port_paranoia_check (port, "serial_set_termios")) {
-		return;
-	}
+	struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_set_termios")) {
+	if (!serial) {
 		return;
 	}
 
@@ -708,16 +675,9 @@
 static void serial_break (struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial;
-	
-	dbg("serial_break");
-	
-	if (port_paranoia_check (port, "serial_break")) {
-		return;
-	}
+	struct usb_serial *serial = get_usb_serial (port, "serial_break");
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "serial_break")) {
+	if (!serial) {
 		return;
 	}
 
@@ -861,22 +821,15 @@
 static void generic_read_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-       	unsigned char *data = urb->transfer_buffer;
+	struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
 	int i;
 
-	dbg("generic_read_bulk_callback");
-
-	if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+	if (!serial) {
 		return;
 	}
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
-		return;
-	}
-	
 	if (urb->status) {
 		dbg("nonzero read bulk status received: %d", urb->status);
 		return;
@@ -911,20 +864,13 @@
 static void generic_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-       	struct tty_struct *tty;
-
-	dbg("generic_write_bulk_callback");
+	struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+	struct tty_struct *tty;
 
-	if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+	if (!serial) {
 		return;
 	}
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
-		return;
-	}
-	
 	if (urb->status) {
 		dbg("nonzero write bulk status received: %d", urb->status);
 		return;
@@ -940,48 +886,6 @@
 }
 
 
-static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
-{
-	struct tty_driver *serial_tty_driver;
-
-	if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
-		err("Out of memory");
-		return NULL;
-	}
-
-	memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
-
-	/* initialize the entries that we don't want to be NULL */
-	serial_tty_driver->magic		= TTY_DRIVER_MAGIC;
-	serial_tty_driver->driver_name		= driver_name;
-	serial_tty_driver->name			= tty_driver_name;
-	serial_tty_driver->major		= SERIAL_TTY_MAJOR;
-	serial_tty_driver->minor_start		= serial->minor;
-	serial_tty_driver->num			= serial->num_ports;
-	serial_tty_driver->type			= TTY_DRIVER_TYPE_SERIAL;
-	serial_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
-	serial_tty_driver->flags		= TTY_DRIVER_REAL_RAW;
-	serial_tty_driver->refcount		= &serial_refcount;
-	serial_tty_driver->table		= serial_tty;
-	serial_tty_driver->termios		= serial_termios;
-	serial_tty_driver->termios_locked	= serial_termios_locked;
-	serial_tty_driver->open			= serial_open;
-	serial_tty_driver->close		= serial_close;
-	serial_tty_driver->write		= serial_write;
-	serial_tty_driver->write_room		= serial_write_room;
-	serial_tty_driver->ioctl		= serial_ioctl;
-	serial_tty_driver->set_termios		= serial_set_termios;
-	serial_tty_driver->throttle		= serial_throttle;
-	serial_tty_driver->unthrottle		= serial_unthrottle;
-	serial_tty_driver->break_ctl		= serial_break;
-	serial_tty_driver->chars_in_buffer	= serial_chars_in_buffer;
-	serial_tty_driver->init_termios		= tty_std_termios;
-	serial_tty_driver->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
-	return serial_tty_driver;
-}
-
-
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_serial *serial = NULL;
@@ -1101,18 +1005,6 @@
 	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)) {
@@ -1196,14 +1088,16 @@
 	max_endpoints = MAX(max_endpoints, num_interrupt_in);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
-		port->number = i;
+		port->number = i + serial->minor;
 		port->serial = serial;
 		port->magic = USB_SERIAL_PORT_MAGIC;
 	}
 	
+	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
 	for (i = 0; i < serial->num_ports; ++i) {
-		info("%s converter now attached to ttyUSB%d", 
-		     type->name, serial->minor + i);
+		tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
+		info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", 
+		     type->name, serial->port[i].number, serial->port[i].number);
 	}
 	
 	return serial; /* success */
@@ -1235,13 +1129,6 @@
 	/* 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;
@@ -1291,18 +1178,13 @@
 		}
 
 		for (i = 0; i < serial->num_ports; ++i) {
-			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+			tty_unregister_devfs (&serial_tty_driver, serial->port[i].number);
+			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number);
 		}
 
 		/* 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);
 
@@ -1314,6 +1196,35 @@
 }
 
 
+static struct tty_driver serial_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"usb-serial",
+	name:			"usb/tts/%d",
+	major:			SERIAL_TTY_MAJOR,
+	minor_start:		0,
+	num:			SERIAL_TTY_MINORS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+	
+	refcount:		&serial_refcount,
+	table:			serial_tty,
+	termios:		serial_termios,
+	termios_locked:		serial_termios_locked,
+	
+	open:			serial_open,
+	close:			serial_close,
+	write:			serial_write,
+	write_room:		serial_write_room,
+	ioctl:			serial_ioctl,
+	set_termios:		serial_set_termios,
+	throttle:		serial_throttle,
+	unthrottle:		serial_unthrottle,
+	break_ctl:		serial_break,
+	chars_in_buffer:	serial_chars_in_buffer,
+};
+
+
 int usb_serial_init(void)
 {
 	int i;
@@ -1336,9 +1247,18 @@
 	if (!something)
 		info ("USB Serial driver is not configured for any devices!");
 
+	/* register the tty driver */
+	serial_tty_driver.init_termios          = tty_std_termios;
+	serial_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	if (tty_register_driver (&serial_tty_driver)) {
+		err("failed to register tty driver");
+		return -1;
+	}
+
 	/* register the USB driver */
 	result = usb_register(&usb_serial_driver);
 	if (result < 0) {
+		tty_unregister_driver(&serial_tty_driver);
 		err("usb_register failed for the usb-serial driver. Error number %d", result);
 		return -1;
 	}
@@ -1350,6 +1270,7 @@
 void usb_serial_exit(void)
 {
 	usb_deregister(&usb_serial_driver);
+	tty_unregister_driver(&serial_tty_driver);
 }
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.3.99-pre6/linux/drivers/usb/serial/visor.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/visor.c	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (04/27/2000) Ryan VanderBijl
+ * 	Fixed memory leak in visor_close
+ *
  * (03/26/2000) gkh
  *	Split driver up into device specific pieces.
  * 
@@ -110,6 +113,7 @@
 		/* send a shutdown message to the device */
 		usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
 				0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+		kfree (transfer_buffer);
 	}
 
 	/* shutdown our bulk reads and writes */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- v2.3.99-pre6/linux/drivers/usb/serial/visor.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/visor.h	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.3.99-pre6/linux/drivers/usb/serial/whiteheat.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/whiteheat.c	Fri May  5 13:41:30 2000
@@ -1,7 +1,7 @@
 /*
  * USB ConnectTech WhiteHEAT driver
  *
- *	(C) Copyright (C) 1999, 2000
+ *	Copyright (C) 1999, 2000
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (05/04/2000) gkh
+ *	First cut at open and close commands. Data can flow through the ports at
+ *	default speeds now.
+ *
  * (03/26/2000) gkh
  *	Split driver up into device specific pieces.
  * 
@@ -45,6 +49,7 @@
 
 #include "whiteheat_fw.h"		/* firmware for the ConnectTech WhiteHEAT device */
 
+#include "whiteheat.h"			/* WhiteHEAT specific commands */
 
 #define CONNECT_TECH_VENDOR_ID		0x0710
 #define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001
@@ -57,6 +62,7 @@
 static void whiteheat_throttle		(struct usb_serial_port *port);
 static void whiteheat_unthrottle	(struct usb_serial_port *port);
 static int  whiteheat_startup		(struct usb_serial *serial);
+static void whiteheat_shutdown		(struct usb_serial *serial);
 
 /* All of the device info needed for the Connect Tech WhiteHEAT */
 static __u16	connecttech_vendor_id			= CONNECT_TECH_VENDOR_ID;
@@ -91,14 +97,124 @@
 	throttle:		whiteheat_throttle,
 	unthrottle:		whiteheat_unthrottle,
 	set_termios:		whiteheat_set_termios,
+	shutdown:		whiteheat_shutdown,
+};
+
+struct whiteheat_private {
+	__u8			command_finished;
+	wait_queue_head_t	wait_command;	/* for handling sleeping while waiting for a command to finish */
 };
 
 
+#define COMMAND_PORT		4
+#define COMMAND_TIMEOUT		(2*HZ)	/* 2 second timeout for a command */
+
 /*****************************************************************************
  * Connect Tech's White Heat specific driver functions
  *****************************************************************************/
+static void command_port_write_callback (struct urb *urb)
+{
+	unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+	int i;
+#endif
+
+	dbg ("command_port_write_callback");
+
+	if (urb->status) {
+		dbg ("nonzero urb status: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	return;
+}
+
+
+static void command_port_read_callback (struct urb *urb)
+{
+	struct whiteheat_private *info = (struct whiteheat_private *)urb->context;
+	unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+	int i;
+#endif
+
+	dbg ("command_port_write_callback");
+
+	if (urb->status) {
+		dbg ("nonzero urb status: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	/* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
+	/* in the future we're going to have to pay attention to the actual command that completed */
+	if (data[0] == WHITEHEAT_CMD_COMPLETE) {
+		info->command_finished = TRUE;
+	}
+	
+	return;
+}
+
+
+static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
+{
+	struct whiteheat_private *info;
+	struct usb_serial_port *port;
+	int timeout;
+	__u8 *transfer_buffer;
+
+	dbg("whiteheat_send_cmd: %d", command);
+
+	port = &serial->port[COMMAND_PORT];
+	info = (struct whiteheat_private *)port->private;
+	info->command_finished = FALSE;
+	
+	transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
+	transfer_buffer[0] = command;
+	memcpy (&transfer_buffer[1], data, datasize);
+	port->write_urb->transfer_buffer_length = datasize + 1;
+	if (usb_submit_urb (port->write_urb))
+		dbg ("submit urb failed");
+
+	/* wait for the command to complete */
+	timeout = COMMAND_TIMEOUT;
+	while (timeout && (info->command_finished == FALSE)) {
+		timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
+	}
+
+	if (info->command_finished == FALSE) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
 {
+	struct whiteheat_min_set	open_command;
+	struct usb_serial_port 		*command_port;
+	struct whiteheat_private	*info;
+
 	dbg("whiteheat_open port %d", port->number);
 
 	if (port->active) {
@@ -106,22 +222,50 @@
 		return -EINVAL;
 	}
 	port->active = 1;
- 
-	/*Start reading from the device*/
+
+	/* set up some stuff for our command port */
+	command_port = &port->serial->port[COMMAND_PORT];
+	if (command_port->private == NULL) {
+		info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+		if (info == NULL) {
+			err("out of memory");
+			return -ENOMEM;
+		}
+		
+		init_waitqueue_head(&info->wait_command);
+		command_port->private = info;
+		command_port->write_urb->complete = command_port_write_callback;
+		command_port->read_urb->complete = command_port_read_callback;
+		usb_submit_urb (command_port->read_urb);	
+	}
+	
+	/* Start reading from the device */
 	if (usb_submit_urb(port->read_urb))
 		dbg("usb_submit_urb(read bulk) failed");
 
+	/* send an open port command */
+	open_command.port = port->number - port->minor;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+
 	/* Need to do device specific setup here (control lines, baud rate, etc.) */
 	/* FIXME!!! */
 
+	dbg("whiteheat_open exit");
+	
 	return (0);
 }
 
 
 static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
 {
+	struct whiteheat_min_set	close_command;
+	
 	dbg("whiteheat_close port %d", port->number);
 	
+	/* send a close command to the port */
+	close_command.port = port->number - port->minor;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+
 	/* Need to change the control lines here */
 	/* FIXME */
 	
@@ -243,7 +387,24 @@
 	response = ezusb_set_reset (serial, 0);
 
 	/* we want this device to fail to have a driver assigned to it. */
-	return (1);
+	return 1;
+}
+
+
+static void whiteheat_shutdown (struct usb_serial *serial)
+{
+	struct usb_serial_port 		*command_port;
+
+	dbg("whiteheat_shutdown");
+
+	/* set up some stuff for our command port */
+	command_port = &serial->port[COMMAND_PORT];
+	if (command_port->private != NULL) {
+		kfree (command_port->private);
+		command_port->private = NULL;
+	}
+
+	return;
 }
 
 #endif	/* CONFIG_USB_SERIAL_WHITEHEAT */
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/serial/whiteheat.h linux/drivers/usb/serial/whiteheat.h
--- v2.3.99-pre6/linux/drivers/usb/serial/whiteheat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/whiteheat.h	Fri May  5 13:41:30 2000
@@ -0,0 +1,169 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ *      Copyright (C) 1999, 2000
+ *          Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_WHITEHEAT_H
+#define __LINUX_USB_SERIAL_WHITEHEAT_H
+
+
+#define FALSE				0
+#define TRUE				1
+
+/* WhiteHEAT commands */
+#define WHITEHEAT_OPEN			1	/* open the port */
+#define WHITEHEAT_CLOSE			2	/* close the port */
+#define WHITEHEAT_SETUP_PORT		3	/* change port settings */
+#define WHITEHEAT_SET_RTS		4	/* turn RTS on or off */
+#define WHITEHEAT_SET_DTR		5	/* turn DTR on or off */
+#define WHITEHEAT_SET_BREAK		6	/* turn BREAK on or off */
+#define WHITEHEAT_DUMP			7	/* dump memory */
+#define WHITEHEAT_STATUS		8	/* get status */
+#define WHITEHEAT_PURGE			9	/* clear the UART fifos */
+#define WHITEHEAT_GET_DTR_RTS		10	/* get the state of DTR and RTS for a port */
+#define WHITEHEAT_GET_HW_INFO		11	/* get EEPROM info and hardware ID */
+#define WHITEHEAT_REPORT_TX_DONE	12	/* get the next TX done */
+#define WHITEHEAT_EVENT			13	/* unsolicited status events */
+#define WHITEHEAT_ECHO			14	/* send data to the indicated IN endpoint */
+#define WHITEHEAT_DO_TEST		15	/* perform the specified test */
+#define WHITEHEAT_CMD_COMPLETE		16	/* reply for certain commands */
+
+/* Data for the WHITEHEAT_SETUP_PORT command */
+#define WHITEHEAT_CTS_FLOW		0x08
+#define WHITEHEAT_RTS_FLOW		0x80
+#define WHITEHEAT_DSR_FLOW		0x10
+#define WHITEHEAT_DTR_FLOW		0x02
+struct whiteheat_port_settings {
+	__u8	port;		/* port number (1 to N) */
+	__u32	baud;		/* any value allowed, default 9600, arrives little endian, range is 7 - 460800 */
+	__u8	bits;		/* 5, 6, 7, or 8, default 8 */
+	__u8	stop;		/* 1 or 2, default 1 (2 = 1.5 if bits = 5) */
+	__u8	parity;		/* 'n, e, o, 0, or 1' (ascii), default 'n'
+				 *	n = none	e = even	o = odd
+				 *	0 = force 0	1 = force 1	*/
+	__u8	sflow;		/* 'n, r, t, or b' (ascii), default 'n'
+				 *	n = none
+				 *	r = receive (XOFF/XON transmitted when receiver fills / empties)
+				 *	t = transmit (XOFF/XON received will stop/start TX)
+				 *	b = both 	*/
+	__u8	xoff;		/* XOFF byte value, default 0x13 */
+	__u8	xon;		/* XON byte value, default 0x11 */
+	__u8	hflow;		/* bits indicate mode as follows:
+				 *	CTS (0x08) (CTS off/on will control/cause TX off/on)
+				 *	DSR (0x10) (DSR off/on will control/cause TX off/on)
+				 *	RTS (0x80) (RTS off/on when receiver fills/empties)
+				 *	DTR (0x02) (DTR off/on when receiver fills/empties) */
+	__u8	lloop;		/* local loopback 0 or 1, default 0 */
+};
+
+/* data for WHITEHEAT_SET_RTS, WHITEHEAT_SET_DTR, and WHITEHEAT_SET_BREAK commands */
+struct whiteheat_rdb_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	state;		/* 0 = off, non-zero = on */
+};
+
+/* data for:
+	WHITEHEAT_OPEN
+	WHITEHEAT_CLOSE
+	WHITEHEAT_STATUS
+	WHITEHEAT_GET_DTR_RTS
+	WHITEHEAT_REPORT_TX_DONE */
+struct whiteheat_min_set {
+	__u8	port;		/* port number (1 to N) */
+};
+
+/* data for WHITEHEAT_PURGE command */
+#define WHITEHEAT_PURGE_INPUT		0x01
+#define WHITEHEAT_PURGE_OUTPUT		0x02
+struct whiteheat_purge_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	what;		/* bit pattern of what to purge */
+};
+
+/* data for WHITEHEAT_DUMP command */
+struct whiteheat_dump_info {
+	__u8	mem_type;	/* memory type: 'd' = data, 'i' = idata, 'b' = bdata, 'x' = xdata */
+	__u16	addr;		/* memory address to dump, address range depends on the above mem_type:
+				 *	'd' = 0 to ff (80 to FF is SFR's)
+				 *	'i' = 80 to ff
+				 *	'b' = 20 to 2f (bits returned as bytes)
+				 *	'x' = 0000 to ffff (also code space)	*/
+	__u16	length;		/* number of bytes to dump, max 64 */
+};
+
+/* data for WHITEHEAT_ECHO command */
+struct whiteheat_echo_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	length;		/* length of message to echo */
+	__u8	echo_data[61];	/* data to echo */
+};
+
+/* data returned from WHITEHEAT_STATUS command */
+#define WHITEHEAT_OVERRUN_ERROR		0x02
+#define WHITEHEAT_PARITY_ERROR		0x04
+#define WHITEHEAT_FRAMING_ERROR		0x08
+#define WHITEHEAT_BREAK_ERROR		0x10
+
+#define WHITEHEAT_OHFLOW		0x01	/* TX is stopped by CTS (waiting for CTS to go ON) */
+#define WHITEHEAT_IHFLOW		0x02	/* remote TX is stopped by RTS */
+#define WHITEHEAT_OSFLOW		0x04	/* TX is stopped by XOFF received (waiting for XON to occur) */
+#define WHITEHEAT_ISFLOW		0x08	/* remote TX is stopped by XOFF transmitted */
+#define WHITEHEAT_TX_DONE		0x80	/* TX has completed */
+
+#define WHITEHEAT_MODEM_EVENT		0x01
+#define WHITEHEAT_ERROR_EVENT		0x02
+#define WHITEHEAT_FLOW_EVENT		0x04
+#define WHITEHEAT_CONNECT_EVENT		0x08
+struct whiteheat_status_info {
+	__u8	port;		/* port number (1 to N) */
+	__u8	event;		/* indicates which of the following bytes are the current event */
+	__u8	modem;		/* modem signal status (copy of UART MSR register) */
+	__u8	error;		/* PFO and RX break (copy of UART LSR register) */
+	__u8	flow;		/* flow control state */
+	__u8	connect;	/* connect state, non-zero value indicates connected */
+};
+
+/* data returned from WHITEHEAT_EVENT command */
+struct whiteheat_event {
+	__u8	port;		/* port number (1 to N) */
+	__u8	event;		/* indicates which of the following bytes are the current event */
+	__u8	info;		/* either modem, error, flow, or connect information */
+};
+
+/* data retured by the WHITEHEAT_GET_HW_INFO command */
+struct whiteheat_hw_info {
+	__u8	hw_id;		/* hardware id number, WhiteHEAT = 0 */
+	__u8	sw_major_rev;	/* major version number */
+	__u8	sw_minor_rev;	/* minor version number */
+	struct whiteheat_hw_eeprom_info {
+		__u8	b0;			/* B0 */
+		__u8	vendor_id_low;		/* vendor id (low byte) */
+		__u8	vendor_id_high;		/* vendor id (high byte) */
+		__u8	product_id_low;		/* product id (low byte) */
+		__u8	product_id_high;	/* product id (high byte) */
+		__u8	device_id_low;		/* device id (low byte) */
+		__u8	device_id_high;		/* device id (high byte) */
+		__u8	not_used_1;
+		__u8	serial_number_0;	/* serial number (low byte) */
+		__u8	serial_number_1;	/* serial number */
+		__u8	serial_number_2;	/* serial number */
+		__u8	serial_number_3;	/* serial number (high byte) */
+		__u8	not_used_2;
+		__u8	not_used_3;
+		__u8	checksum_low;		/* checksum (low byte) */
+		__u8	checksum_high;		/* checksum (high byte */
+	} hw_eeprom_info;	/* EEPROM contents */
+};
+
+#endif
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.99-pre6/linux/drivers/usb/uhci.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/uhci.c	Mon May  8 15:48:18 2000
@@ -1889,7 +1889,7 @@
 			OK(len);
 		case 0x03:	/* string descriptors */
 			len = usb_root_hub_string (wValue & 0xff,
-				uhci->io_addr, "UHCI",
+				uhci->io_addr, "UHCI-alt",
 				data, wLength);
 			if (len > 0) {
 				OK (min (leni, len));
@@ -1929,9 +1929,10 @@
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	uhci->rh.send = 0;
-	del_timer(&uhci->rh.rh_int_timer);
-
+	if (uhci->rh.urb == urb) {
+		uhci->rh.send = 0;
+		del_timer(&uhci->rh.rh_int_timer);
+	}
 	return 0;
 }
 /*-------------------------------------------------------------------*/
@@ -2182,7 +2183,7 @@
 	 * us a reasonable dynamic range for irq latencies.
 	 */
 	for (i = 0; i < 1024; i++) {
-		struct uhci_td *irq = &uhci->skel_int2_td;
+		struct uhci_td *irq = &uhci->skel_int1_td;
 
 		if (i & 1) {
 			irq++;
@@ -2357,10 +2358,14 @@
 
 static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
+	struct uhci *uhci = dev->data;
 	switch (rqst) {
 	case PM_SUSPEND:
+		reset_hc(uhci);
 		break;
 	case PM_RESUME:
+		reset_hc(uhci);
+		start_hc(uhci);
 		break;
 	}
 	return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.3.99-pre6/linux/drivers/usb/usb-ohci.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/usb-ohci.c	Tue May  2 13:16:26 2000
@@ -81,12 +81,9 @@
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	int i;
-	void * wait;
 	
 	if (!urb_priv) return;
 	
-	wait = urb_priv->wait;
-	
 	for (i = 0; i < urb_priv->length; i++) {
 		if (urb_priv->td [i]) {
 			OHCI_FREE (urb_priv->td [i]);
@@ -94,11 +91,8 @@
 	}
 	kfree (urb->hcpriv);
 	urb->hcpriv = NULL;
-	
-	if (wait) {
-		add_wait_queue (&op_wakeup, wait); 
-		wake_up (&op_wakeup);
-	}
+
+	wake_up (&op_wakeup);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -476,7 +470,6 @@
 	urb_priv->td_cnt = 0;
 	urb_priv->state = 0;
 	urb_priv->ed = ed;	
-	urb_priv->wait = NULL;
 	
 	/* allocate the TDs */
 	for (i = 0; i < size; i++) { 
@@ -527,6 +520,9 @@
 	if (!urb) /* just to be sure */ 
 		return -EINVAL;
 		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
 	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
 
 #ifdef DEBUG
@@ -537,25 +533,31 @@
 		return rh_unlink_urb (urb); /* a request to the virtual root hub */
 	
 	if (urb->hcpriv) { 
-		if (urb->status == USB_ST_URB_PENDING) { /* URB active? */
+		/* URB active? */
+		if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) {
 			urb_priv_t  * urb_priv = urb->hcpriv;
 			urb_priv->state = URB_DEL; 
+
 			/* we want to delete the TDs of an URB from an ed 
-			 * request the deletion, it will be handled at the next USB-frame */
-			urb_priv->wait = &wait;
+			 * request the deletion, it will be handled at the
+			 * next USB-frame */
 			
 			spin_lock_irqsave (&usb_ed_lock, flags);
 			ep_rm_ed (urb->dev, urb_priv->ed);
 			urb_priv->ed->state |= ED_URB_DEL;
 			spin_unlock_irqrestore (&usb_ed_lock, flags);
 
+			add_wait_queue (&op_wakeup, &wait);
 			current->state = TASK_UNINTERRUPTIBLE;
-			if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
-				remove_wait_queue (&op_wakeup, &wait); 
-			else
+			if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
 				err("unlink URB timeout!");
+			remove_wait_queue (&op_wakeup, &wait); 
 		} else 
 			urb_rm_priv (urb);
+
+		urb->status = -ENOENT;	// mark urb as killed		
+		if (urb->complete)
+			urb->complete ((struct urb *) urb);
 		usb_dec_dev_use (urb->dev);		
 	}	
 	return 0;
@@ -611,7 +613,7 @@
   		spin_unlock_irqrestore (&usb_ed_lock, flags);
   		
 		if (cnt > 0) {
-			dev->wait = &wait;
+			add_wait_queue (&op_wakeup, &wait);
 			current->state = TASK_UNINTERRUPTIBLE;
 			schedule_timeout (HZ / 10);
 			remove_wait_queue (&op_wakeup, &wait);
@@ -1160,10 +1162,8 @@
    	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
    	 		ed->state = ED_NEW; 
    	 		/* if all eds are removed wake up sohci_free_dev */
-   	 		if ((! --dev->ed_cnt) && dev->wait) {
-   	 			add_wait_queue (&op_wakeup, dev->wait); 
+   	 		if (!--dev->ed_cnt)
 				wake_up (&op_wakeup);
-			}
    	 	}
    	 	else {
    	 		ed->state &= ~ED_URB_DEL;
@@ -1283,7 +1283,7 @@
 {
 	0x12,       /*  __u8  bLength; */
 	0x01,       /*  __u8  bDescriptorType; Device */
-	0x00,	    /*  __u16 bcdUSB; v1.0 */
+	0x10,	    /*  __u16 bcdUSB; v1.1 */
 	0x01,
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
@@ -1332,7 +1332,7 @@
 	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
 	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
  	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
- 	0x08,       /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
  	0x00,
 	0xff        /*  __u8  ep_bInterval; 255 ms */
 };
@@ -1631,8 +1631,10 @@
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
  
-	ohci->rh.send = 0;
-	del_timer (&ohci->rh.rh_int_timer);
+	if (ohci->rh.urb == urb) {
+		ohci->rh.send = 0;
+		del_timer (&ohci->rh.rh_int_timer);
+	}
 	return 0;
 }
  
@@ -1791,11 +1793,29 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* reinitialize after controller reset */
+
+static void hc_reinit_ohci (ohci_t *ohci)
+{
+	int i;
+
+	/* for load balancing of the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+	
+	ohci->ed_rm_list [0] = NULL;
+	ohci->ed_rm_list [1] = NULL;
+
+	/* end of control and bulk lists */	 
+	ohci->ed_isotail     = NULL;
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+} 
+
 /* allocate OHCI */
 
 static ohci_t * hc_alloc_ohci (void * mem_base)
 {
-	int i;
 	ohci_t * ohci;
 	struct usb_bus * bus;
 
@@ -1808,15 +1828,6 @@
 	ohci->irq = -1;
 	ohci->regs = mem_base;   
 
-	/* for load ballancing of the interrupt branches */
-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
-	
-	/* end of control and bulk lists */	 
-	ohci->ed_isotail     = NULL;
-	ohci->ed_controltail = NULL;
-	ohci->ed_bulktail    = NULL;
-
 	bus = usb_alloc_bus (&sohci_device_operations);
 	if (!bus) {
 		free_pages ((unsigned long) ohci, 1);
@@ -1829,6 +1840,7 @@
 	return ohci;
 } 
 
+
 /*-------------------------------------------------------------------------*/
 
 /* De-allocate all resources.. */
@@ -1924,21 +1936,9 @@
 {
 	unsigned long mem_base;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 	mem_base = dev->resource[0].start;
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
-#else
-	u16 cmd;
-
-	mem_base = dev->base_address[0];
-	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	/* Some Mac firmware will switch memory response off */
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
-#endif
 	
 	pci_set_master (dev);
 	mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
@@ -1998,15 +1998,47 @@
 	if (ohci) {
 		switch (rqst) {
 		case PM_SUSPEND:
-			dbg("USB-Bus suspend: %p", ohci->regs);
-			if (ohci->bus->root_hub)
-				usb_disconnect (&ohci->bus->root_hub);
-			hc_reset (ohci);
+			/* act as if usb suspend can always be used */
+			dbg("USB suspend: %p", ohci->regs);
+			ohci->hc_control = OHCI_USB_SUSPEND;
+			writel (ohci->hc_control, &ohci->regs->control);
+			wait_ms (10);
 			break;
+
 		case PM_RESUME:
-			dbg("USB-Bus resume: %p", ohci->regs);
-			if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
-				err ("can't restart controller, %d", temp);
+			/* did we suspend, or were we powered off? */
+			ohci->hc_control = readl (&ohci->regs->control);
+			temp = ohci->hc_control & OHCI_CTRL_HCFS;
+			switch (temp) {
+
+			case OHCI_USB_RESET:	// lost power
+				dbg("USB reset: %p", ohci->regs);
+				ohci->disabled = 1;
+				if (ohci->bus->root_hub)
+					usb_disconnect (&ohci->bus->root_hub);
+				hc_reinit_ohci (ohci);
+				if ((temp = hc_reset (ohci)) < 0
+					|| (temp = hc_start (ohci)) < 0) {
+					ohci->disabled = 1;
+					err ("can't restart, %d", temp);
+				}
+				dbg ("reset done");
+				break;
+
+			case OHCI_USB_SUSPEND:	// host wakeup
+			case OHCI_USB_RESUME:	// remote wakeup
+				dbg("USB resume: %p", ohci->regs);
+				ohci->hc_control = OHCI_USB_RESUME;
+				writel (ohci->hc_control, &ohci->regs->control);
+				wait_ms (20);
+
+				ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+				writel (ohci->hc_control, &ohci->regs->control);
+				break;
+
+			default:
+				warn ("odd PM_RESUME");
+			}
 			break;
 		}
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
--- v2.3.99-pre6/linux/drivers/usb/usb-storage.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/usb-storage.c	Tue May  2 13:15:41 2000
@@ -66,59 +66,59 @@
 
 /* we allocate one of these for every device that we remember */
 struct us_data {
-	struct us_data	        *next;	         /* next device */
+	struct us_data		*next;		 /* next device */
 
 	/* the device we're working with */
-	struct semaphore	dev_semaphore;   /* protect pusb_dev */
-	struct usb_device	*pusb_dev;       /* this usb_device */
+	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	struct usb_device	*pusb_dev;	 /* this usb_device */
 
 	unsigned int		flags;		 /* from filter initially */
 
 	/* information about the device -- always good */
-	char                    vendor[32];
-	char                    product[32];
-	char                    serial[32];
-	char                    *transport_name;
-	char                    *protocol_name;
-	__u8			subclass;
-	__u8			protocol;
+	char			vendor[USB_STOR_STRING_LEN];
+	char			product[USB_STOR_STRING_LEN];
+	char			serial[USB_STOR_STRING_LEN];
+	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 */
+	u8			ifnum;		 /* interface number   */
+	u8			ep_in;		 /* bulk in endpoint   */
+	u8			ep_out;		 /* bulk out endpoint  */
+	struct usb_endpoint_descriptor *ep_int;	 /* interrupt endpoint */ 
 
 	/* function pointers for this device */
-	trans_cmnd              transport;	 /* transport function     */
-	trans_reset             transport_reset; /* transport device reset */
-	proto_cmnd              proto_handler;   /* protocol handler       */
+	trans_cmnd		transport;	 /* transport function	   */
+	trans_reset		transport_reset; /* transport device reset */
+	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 -- 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 */
+	struct semaphore	ip_waitq;	 /* for CBI interrupts	 */
+	int			ip_wanted;	 /* is an IRQ expected?	 */
+
+	struct semaphore	irq_urb_sem;	 /* to protect irq_urb	 */
+	struct urb		*irq_urb;	 /* for USB int requests */
+	unsigned char		irqbuf[2];	 /* buffer for USB IRQ	 */
 
 	/* mutual exclusion structures */
-	struct semaphore	notify;          /* thread begin/end        */
-	struct semaphore        sleeper;         /* to sleep the thread on  */
-	struct semaphore        queue_exclusion; /* to protect data structs */
+	struct semaphore	notify;		 /* thread begin/end	    */
+	struct semaphore	sleeper;	 /* to sleep the thread on  */
+	struct semaphore	queue_exclusion; /* to protect data structs */
 };
 
 /*
@@ -151,7 +151,7 @@
  * Transfer one SCSI scatter-gather buffer via bulk transfer
  *
  * Note that this function is necessary because we want the ability to
- * use scatter-gather memory.  Good performance is achived by a combination
+ * use scatter-gather memory.  Good performance is achieved by a combination
  * of scatter-gather and clustering (which makes each chunk bigger).
  *
  * Note that the lower layer will always retry when a NAK occurs, up to the
@@ -166,7 +166,7 @@
 
 	/* 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);
+	result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, 5*HZ);
 	US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
 		  result, partial, length);
 	
@@ -226,7 +226,7 @@
 		 */
 		sg = (struct scatterlist *) srb->request_buffer;
 		for (i = 0; i < srb->use_sg; i++) {
-			result = us_transfer_partial(us, pipe, sg[i].address,
+			result = us_transfer_partial(us, pipe, sg[i].address, 
 						     sg[i].length);
 			if (result)
 				break;
@@ -234,7 +234,7 @@
 	}
 	else
 		/* no scatter-gather, just make the request */
-		result = us_transfer_partial(us, pipe, srb->request_buffer,
+		result = us_transfer_partial(us, pipe, srb->request_buffer, 
 					     srb->request_bufflen);
 
 	/* return the result in the data structure itself */
@@ -251,7 +251,7 @@
 	struct scatterlist *sg;
 
 	/* support those devices which need the length calculated
-	 * differently
+	 * differently 
 	 */
 	if (us->flags & US_FL_ALT_LENGTH) {
 		if (srb->cmnd[0] == INQUIRY) {
@@ -374,18 +374,18 @@
 		srb->cmnd[3] = 0;
 		srb->cmnd[4] = 18;
 		srb->cmnd[5] = 0;
-    
+
 		/* set the buffer length for transfer */
 		old_request_buffer = srb->request_buffer;
 		old_request_bufflen = srb->request_bufflen;
-	        old_sg = srb->use_sg;
+		old_sg = srb->use_sg;
 		srb->use_sg = 0;
 		srb->request_bufflen = 18;
 		srb->request_buffer = srb->sense_buffer;
 
 		/* issue the auto-sense command */
 		temp_result = us->transport(us->srb, us);
-		if (temp_result == USB_STOR_TRANSPORT_ERROR) {
+		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
 			/* FIXME: we need to invoke a transport reset here */
 			US_DEBUGP("-- auto-sense failure\n");
 			srb->result = DID_ERROR << 16;
@@ -433,20 +433,22 @@
 /*
  * Control/Bulk/Interrupt transport
  */
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
+static void CBI_irq(struct urb *urb)
 {
-	struct us_data *us = (struct us_data *)dev_id;
+	struct us_data *us = (struct us_data *)urb->context;
 
 	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-	US_DEBUGP("-- IRQ data length is %d\n", len);
-	US_DEBUGP("-- IRQ state is %d\n", state);
+	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
+	US_DEBUGP("-- IRQ state is %d\n", urb->status);
 
 	/* is the device removed? */
-	if (state != -ENOENT) {
+	if (urb->status != -ENOENT) {
 		/* save the data for interpretation later */
-		us->ip_data = le16_to_cpup((__u16 *)buffer);
-		US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
-  
+		US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
+			  ((unsigned char*)urb->transfer_buffer)[0], 
+			  ((unsigned char*)urb->transfer_buffer)[1]);
+
+
 		/* was this a wanted interrupt? */
 		if (us->ip_wanted) {
 			us->ip_wanted = 0;
@@ -455,12 +457,6 @@
 			US_DEBUGP("ERROR: Unwanted interrupt received!\n");
 	} else
 		US_DEBUGP("-- device has been removed\n");
-
-	/* This return code is truly meaningless -- and I mean truly.  It gets
-	 * ignored by other layers.  It used to indicate if we wanted to get
-	 * another interrupt or disable the interrupt callback
-	 */
-	return 0;
 }
 
 static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
@@ -480,7 +476,7 @@
 		/* STALL must be cleared when they are detected */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_clear_halt(us->pusb_dev, 	
+			result = usb_clear_halt(us->pusb_dev,	
 						usb_sndctrlpipe(us->pusb_dev,
 								0));
 			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
@@ -513,7 +509,9 @@
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 	
-	US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+	US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", 
+		  ((unsigned char*)us->irq_urb->transfer_buffer)[0],
+		  ((unsigned char*)us->irq_urb->transfer_buffer)[1]);
 	
 	/* UFI gives us ASC and ASCQ, like a request sense
 	 *
@@ -527,7 +525,7 @@
 		    srb->cmnd[0] == INQUIRY)
 			return USB_STOR_TRANSPORT_GOOD;
 		else
-			if (us->ip_data)
+			if (((unsigned char*)us->irq_urb->transfer_buffer)[0])
 				return USB_STOR_TRANSPORT_FAILED;
 			else
 				return USB_STOR_TRANSPORT_GOOD;
@@ -537,10 +535,14 @@
 	 * The first byte should always be a 0x0
 	 * The second byte & 0x0F should be 0x0 for good, otherwise error 
 	 */
-	switch ((us->ip_data & 0xFF0F)) {
-	case 0x0000: 
+	if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) {
+		US_DEBUGP("CBI IRQ data showed reserved bType\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) {
+	case 0x00: 
 		return USB_STOR_TRANSPORT_GOOD;
-	case 0x0001: 
+	case 0x01: 
 		return USB_STOR_TRANSPORT_FAILED;
 	default: 
 		return USB_STOR_TRANSPORT_ERROR;
@@ -609,8 +611,8 @@
 	int partial;
 	
 	/* set up the command wrapper */
-	bcb.Signature = US_BULK_CB_SIGN;
-	bcb.DataTransferLength = us_transfer_length(srb, us);
+	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
 	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
 	bcb.Tag = srb->serial_number;
 	bcb.Lun = srb->cmnd[1] >> 5;
@@ -625,8 +627,8 @@
 	
 	/* send it to out endpoint */
 	US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
-		  bcb.Signature, bcb.Tag, bcb.Lun, bcb.DataTransferLength,
-		  bcb.Flags, bcb.Length);
+		  le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun, 
+		  bcb.DataTransferLength, bcb.Flags, bcb.Length);
 	result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
 			      US_BULK_CB_WRAP_LEN, &partial, HZ*5);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
@@ -657,17 +659,17 @@
 	/* 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);
+			      US_BULK_CS_WRAP_LEN, &partial, HZ*2);
 	
 	/* 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);
+				      US_BULK_CS_WRAP_LEN, &partial, HZ*2);
 		
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
@@ -685,8 +687,10 @@
 	
 	/* check bulk status */
 	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
-		  bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
-	if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+		  le32_to_cpu(bcs.Signature), bcs.Tag, 
+		  bcs.Residue, bcs.Status);
+	if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
+	    bcs.Tag != bcb.Tag || 
 	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
@@ -718,7 +722,7 @@
 static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
 {
 	int old_cmnd = 0;
-  
+
 	/* Fix some commands -- this is a form of mode translation
 	 * ATAPI devices only accept 12 byte long commands 
 	 *
@@ -770,10 +774,10 @@
 		srb->cmnd[0] = srb->cmnd[0] | 0x20;
 		break;
 	} /* end switch on cmnd[0] */
-  
+
 	/* send the command to the transport layer */
 	invoke_transport(srb, us);
-  
+
 	/* Fix the MODE_SENSE data if we translated the command
 	 */
 	if (old_cmnd == MODE_SENSE) {
@@ -802,7 +806,7 @@
 static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
 {
 	int old_cmnd = 0;
-  
+
 	/* fix some commands -- this is a form of mode translation
 	 * UFI devices only accept 12 byte long commands 
 	 *
@@ -831,7 +835,7 @@
 		srb->cmnd[10] = 0;
 		srb->cmnd[9] = 0;
 
-		/* if we're sending data, we send all.  If getting data, 
+		/* if we're sending data, we send all.	If getting data, 
 		 * get the minimum */
 		if (srb->cmnd[0] == MODE_SELECT)
 			srb->cmnd[8] = srb->cmnd[4];
@@ -853,7 +857,7 @@
 		srb->cmnd[7] = 0;
 		srb->cmnd[8] = 8;
 		break;
- 
+
 		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
 	case REQUEST_SENSE:
 		srb->cmnd[4] = 18;
@@ -912,48 +916,48 @@
 	 * so some devices do not support them
 	 */
 	if (us->flags & US_FL_MODE_XLATE) {
-    
+
 		/* translate READ_6 to READ_10 */
 		if (srb->cmnd[0] == 0x08) {
-      
+
 			/* get the control */
 			srb->cmnd[9] = us->srb->cmnd[5];
-      
+
 			/* get the length */
 			srb->cmnd[8] = us->srb->cmnd[6];
 			srb->cmnd[7] = 0;
-      
+
 			/* set the reserved area to 0 */
 			srb->cmnd[6] = 0;	    
-      
+
 			/* get LBA */
 			srb->cmnd[5] = us->srb->cmnd[3];
 			srb->cmnd[4] = us->srb->cmnd[2];
 			srb->cmnd[3] = 0;
 			srb->cmnd[2] = 0;
-      
+
 			/* LUN and other info in cmnd[1] can stay */
-      
+
 			/* fix command code */
 			srb->cmnd[0] = 0x28;
-      
+
 			US_DEBUGP("Changing READ_6 to READ_10\n");
 			US_DEBUG(us_show_command(srb));
 		}
-    
+
 		/* translate WRITE_6 to WRITE_10 */
 		if (srb->cmnd[0] == 0x0A) {
-      
+
 			/* get the control */
 			srb->cmnd[9] = us->srb->cmnd[5];
-      
+
 			/* get the length */
 			srb->cmnd[8] = us->srb->cmnd[4];
 			srb->cmnd[7] = 0;
-      
+
 			/* set the reserved area to 0 */
 			srb->cmnd[6] = 0;	    
-      
+
 			/* get LBA */
 			srb->cmnd[5] = us->srb->cmnd[3];
 			srb->cmnd[4] = us->srb->cmnd[2];
@@ -961,7 +965,7 @@
 			srb->cmnd[2] = 0;
 	    
 			/* LUN and other info in cmnd[1] can stay */
-      
+
 			/* fix command code */
 			srb->cmnd[0] = 0x2A;
 
@@ -1226,7 +1230,7 @@
 	SPRINTF("   Host scsi%d: usb-storage\n", hostno);
 
 	/* print product, vendor, and serial number strings */
-	SPRINTF("       Vendor: %s\n", us->vendor);
+	SPRINTF("	Vendor: %s\n", us->vendor);
 	SPRINTF("      Product: %s\n", us->product);
 	SPRINTF("Serial Number: %s\n", us->serial);
 
@@ -1235,7 +1239,7 @@
 	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);
@@ -1334,7 +1338,7 @@
 		action = us->action;
 		us->action = 0;
 		us->srb = us->queue_srb;
-     	
+	
 		/* release the queue lock as fast as possible */
 		up(&(us->queue_exclusion));
 
@@ -1380,8 +1384,8 @@
 					       sizeof(sense_notready));
 					us->srb->result = GOOD;
 				} else {
-					memcpy(us->srb->sense_buffer,
-					       sense_notready,
+					memcpy(us->srb->sense_buffer, 
+					       sense_notready, 
 					       sizeof(sense_notready));
 					us->srb->result = CHECK_CONDITION;
 				}
@@ -1395,7 +1399,7 @@
 			up(&(us->dev_semaphore));
 
 			/* indicate that the command is done */
-			US_DEBUGP("scsi cmd done, result=0x%x\n",
+			US_DEBUGP("scsi cmd done, result=0x%x\n", 
 				  us->srb->result);
 			us->srb->scsi_done(us->srb);
 			us->srb = NULL;
@@ -1428,15 +1432,22 @@
 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 },
+	{ 0x059b, 0x0030, 0x0100,
+	  "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
 	{ 0x0781, 0x0001, 0x0200,
-	  "Sandisk ImageMate", US_SC_SCSI, US_PR_CB, 
+	  "Sandisk ImageMate (w/eject button)", 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},
+	  "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK, 
+	  US_FL_SINGLE_LUN | US_FL_IGNORE_SER },
 	{ 0x07af, 0x0005, 0x0100,
-	  "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+	  "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, 
+	{ 0x04e6, 0x0002, 0x0100,
+	  "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, 
+	{ 0x04e6, 0x0006, 0x0100,
+	  "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, 
+	{ 0x03f0, 0x0107, 0x0200,
+	  "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0}, 
 	{ 0x0000, 0x0000, 0x0,
 	  "", 0, 0, 0}
 };
@@ -1446,8 +1457,8 @@
  * 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)
+static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, 
+					  u16 bcdDevice)
 {
 	struct us_unusual_dev* ptr;
 
@@ -1472,14 +1483,64 @@
 	return ptr;
 }
 
+/* Set up the IRQ pipe and handler
+ * Note that this function assumes that all the data in the us_data
+ * strucuture is current.  This includes the ep_int field, which gives us
+ * the endpoint for the interrupt.
+ * Returns non-zero on failure, zero on success
+ */ 
+static int usb_stor_allocate_irq(struct us_data *ss)
+{
+	unsigned int pipe;
+	int maxp;
+	int result;
+
+	US_DEBUGP("Allocating IRQ for CBI transport\n");
+	
+	/* lock access to the data structure */
+	down(&(ss->irq_urb_sem));
+
+	/* allocate the URB */
+	ss->irq_urb = usb_alloc_urb(0);
+	if (!ss->irq_urb) {
+		up(&(ss->irq_urb_sem));
+		US_DEBUGP("couldn't allocate interrupt URB");
+		return 1;
+	}
+	
+	/* calculate the pipe and max packet size */
+	pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress & 
+			      USB_ENDPOINT_NUMBER_MASK);
+	maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+	if (maxp > sizeof(ss->irqbuf))
+		maxp = sizeof(ss->irqbuf);
+	
+	/* fill in the URB with our data */
+	FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp, 
+		     CBI_irq, ss, ss->ep_int->bInterval); 
+	
+	/* submit the URB for processing */
+	result = usb_submit_urb(ss->irq_urb);
+	US_DEBUGP("usb_submit_urb() returns %d\n", result);
+	if (result) {
+		usb_free_urb(ss->irq_urb);
+		up(&(ss->irq_urb_sem));
+		return 2;
+	}
+
+	/* unlock the data structure and return success */
+	up(&(ss->irq_urb_sem));
+	return 0;
+}
+
 /* 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[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 */
+	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;
@@ -1488,12 +1549,11 @@
 	/* these are temporary copies -- we test on these, then put them
 	 * in the us-data structure 
 	 */
-	__u8 ep_in = 0;
-	__u8 ep_out = 0;
-	__u8 ep_int = 0;
-	__u8 ep_interval = 0;
-	__u8 subclass = 0;
-	__u8 protocol = 0;
+	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_out = NULL;
+	struct usb_endpoint_descriptor *ep_int = NULL;
+	u8 subclass = 0;
+	u8 protocol = 0;
 
 	/* the altsettting 0 on the interface we're probing */
 	struct usb_interface_descriptor *altsetting = 
@@ -1550,23 +1610,19 @@
 			/* BULK in or out? */
 			if (altsetting->endpoint[i].bEndpointAddress & 
 			    USB_DIR_IN)
-				ep_in = altsetting->endpoint[i].bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
+				ep_in = &altsetting->endpoint[i];
 			else
-				ep_out = altsetting->endpoint[i].bEndpointAddress &
-					USB_ENDPOINT_NUMBER_MASK;
+				ep_out = &altsetting->endpoint[i];
 		}
 
 		/* is it an interrupt endpoint? */
 		if ((altsetting->endpoint[i].bmAttributes & 
 		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
-			ep_int = altsetting->endpoint[i].bEndpointAddress &
-				USB_ENDPOINT_NUMBER_MASK;
-			ep_interval = altsetting->endpoint[i].bInterval;
+			ep_int = &altsetting->endpoint[i];
 		}
 	}
-	US_DEBUGP("Endpoints: In %d Out %d Int %d (Period %d)\n",
-		  ep_in, ep_out, ep_int, ep_interval);
+	US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
+		  ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
 
 	/* set the interface -- STALL is an acceptable response here */
 	result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
@@ -1582,7 +1638,7 @@
 
 	/* 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("Sanity check failed.  Rejecting device.\n");
+		US_DEBUGP("Sanity check failed.	 Rejecting device.\n");
 		return NULL;
 	}
 
@@ -1591,14 +1647,14 @@
 	/* clear the GUID and fetch the strings */
 	GUID_CLEAR(guid);
 	if (dev->descriptor.iManufacturer)
-		usb_string(dev, dev->descriptor.iManufacturer, mf, 
-			   sizeof(mf));
+		usb_string(dev, dev->descriptor.iManufacturer, 
+			   mf, sizeof(mf));
 	if (dev->descriptor.iProduct)
-		usb_string(dev, dev->descriptor.iProduct, prod, 
-			   sizeof(prod));
-	if (dev->descriptor.iSerialNumber)
-		usb_string(dev, dev->descriptor.iSerialNumber, serial, 
-			   sizeof(serial));
+		usb_string(dev, dev->descriptor.iProduct, 
+			   prod, sizeof(prod));
+	if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER))
+		usb_string(dev, dev->descriptor.iSerialNumber, 
+			   serial, sizeof(serial));
 	
 	/* Create a GUID for this device */
 	if (dev->descriptor.iSerialNumber && serial[0]) {
@@ -1633,22 +1689,20 @@
 		ss->ifnum = ifnum;
 		ss->pusb_dev = dev;
 	
-		/* hook up the IRQ handler again */
-		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 */
-			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, ss->ep_interval,
-						 (void *)ss,
-						 &(ss->irq_handle));
-			US_DEBUGP("-- usb_request_irq returned %d\n", result);
-		}
+		/* copy over the endpoint data */
+		if (ep_in)
+			ss->ep_in = ep_in->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		if (ep_out)
+			ss->ep_out = ep_out->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_int = ep_int;
+
+		/* allocate an IRQ callback if one is needed */
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			return NULL;
 	} else { 
-		/* New device -- Allocate memory and initialize */
+		/* New device -- allocate memory and initialize */
 		US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
 	
 		if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), 
@@ -1662,7 +1716,9 @@
 		/* Initialize the mutexes only when the struct is new */
 		init_MUTEX_LOCKED(&(ss->sleeper));
 		init_MUTEX_LOCKED(&(ss->notify));
+		init_MUTEX_LOCKED(&(ss->ip_waitq));
 		init_MUTEX(&(ss->queue_exclusion));
+		init_MUTEX(&(ss->irq_urb_sem));
 		init_MUTEX(&(ss->dev_semaphore));
 
 		/* copy over the subclass and protocol data */
@@ -1671,10 +1727,13 @@
 		ss->flags = flags;
 
 		/* copy over the endpoint data */
-		ss->ep_in = ep_in;
-		ss->ep_out = ep_out;
+		if (ep_in)
+			ss->ep_in = ep_in->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		if (ep_out)
+			ss->ep_out = ep_out->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
 		ss->ep_int = ep_int;
-		ss->ep_interval = ep_interval;
 
 		/* establish the connection to the new device */
 		ss->ifnum = ifnum;
@@ -1739,7 +1798,7 @@
 
 		case US_SC_QIC:
 			ss->protocol_name = "QIC-157";
-			US_DEBUGP("Sorry, device not supported.  Please\n");
+			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);
@@ -1771,19 +1830,9 @@
 		}
 		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 */
-			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, ss->ep_interval,
-						 (void *)ss,
-						 &(ss->irq_handle));
-			US_DEBUGP("-- usb_request_irq returned %d\n", result);
-		}
+		/* allocate an IRQ callback if one is needed */
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			return NULL;
 		
 		/*
 		 * Since this is a new device, we need to generate a scsi 
@@ -1803,7 +1852,7 @@
 		 */
 		(struct us_data *)ss->htmplt.proc_dir = ss; 
 		
-		/* start up our thread */
+		/* start up our control thread */
 		ss->pid = kernel_thread(usb_stor_control_thread, ss,
 					CLONE_FS | CLONE_FILES |
 					CLONE_SIGHAND);
@@ -1814,10 +1863,10 @@
 			return NULL;
 		}
 		
-		/* wait for it to start */
+		/* wait for the thread to start */
 		down(&(ss->notify));
 			
-		/* now register - our detect function will be called */
+		/* now register	 - our detect function will be called */
 		ss->htmplt.module = THIS_MODULE;
 		scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
 		
@@ -1845,7 +1894,7 @@
 	int result;
 
 	US_DEBUGP("storage_disconnect() called\n");
- 
+
 	/* this is the odd case -- we disconnected but weren't using it */
 	if (!ss) {
 		US_DEBUGP("-- device was not in use\n");
@@ -1856,13 +1905,15 @@
 	down(&(ss->dev_semaphore));
 
 	/* release the IRQ, if we have one */
-	if (ss->irq_handle) {
+	down(&(ss->irq_urb_sem));
+	if (ss->irq_urb) {
 		US_DEBUGP("-- releasing irq handle\n");
-		result = usb_release_irq(ss->pusb_dev, ss->irq_handle, 
-					 ss->irqpipe);
-		US_DEBUGP("-- usb_release_irq() returned %d\n", result);
-		ss->irq_handle = NULL;
+		result = usb_unlink_urb(ss->irq_urb);
+		ss->irq_urb = NULL;
+		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+		usb_free_urb(ss->irq_urb);
 	}
+	up(&(ss->irq_urb_sem));
 
 	/* mark the device as gone */
 	ss->pusb_dev = NULL;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h
--- v2.3.99-pre6/linux/drivers/usb/usb-storage.h	Wed Apr 26 16:34:08 2000
+++ linux/drivers/usb/usb-storage.h	Tue May  2 13:15:41 2000
@@ -27,23 +27,23 @@
 
 /* Sub Classes */
 
-#define US_SC_RBC	1		/* Typically, flash devices */
-#define US_SC_8020	2		/* CD-ROM */
-#define US_SC_QIC	3		/* QIC-157 Tapes */
-#define US_SC_UFI	4		/* Floppy */
-#define US_SC_8070	5		/* Removable media */
-#define US_SC_SCSI	6		/* Transparent */
+#define US_SC_RBC	0x01		/* Typically, flash devices */
+#define US_SC_8020	0x02		/* CD-ROM */
+#define US_SC_QIC	0x03		/* QIC-157 Tapes */
+#define US_SC_UFI	0x04		/* Floppy */
+#define US_SC_8070	0x05		/* Removable media */
+#define US_SC_SCSI	0x06		/* Transparent */
 #define US_SC_MIN	US_SC_RBC
 #define US_SC_MAX	US_SC_SCSI
 
 /* Protocols */
 
-#define US_PR_CB	1		/* Control/Bulk w/o interrupt */
-#define US_PR_CBI	0		/* Control/Bulk/Interrupt */
+#define US_PR_CBI	0x00		/* Control/Bulk/Interrupt */
+#define US_PR_CB	0x01		/* Control/Bulk w/o interrupt */
 #define US_PR_BULK	0x50		/* bulk only */
 
 /*
- * Bulk only data structures (Zip 100, for example)
+ * Bulk only data structures
  */
 
 /* command block wrapper */
@@ -57,8 +57,8 @@
 	__u8	CDB[16];		/* max command */
 };
 
-#define US_BULK_CB_WRAP_LEN 	31
-#define US_BULK_CB_SIGN		0x43425355
+#define US_BULK_CB_WRAP_LEN	31
+#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
 #define US_BULK_FLAG_IN		1
 #define US_BULK_FLAG_OUT	0
 
@@ -72,7 +72,7 @@
 };
 
 #define US_BULK_CS_WRAP_LEN	13
-#define US_BULK_CS_SIGN		0x53425355
+#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
 #define US_BULK_STAT_OK		0
 #define US_BULK_STAT_FAIL	1
 #define US_BULK_STAT_PHASE	2
@@ -84,15 +84,15 @@
 /*
  * us_bulk_transfer() return codes
  */
-#define US_BULK_TRANSFER_GOOD   0
-#define US_BULK_TRANSFER_SHORT  1
+#define US_BULK_TRANSFER_GOOD	0
+#define US_BULK_TRANSFER_SHORT	1
 #define US_BULK_TRANSFER_FAILED 2
 
 /*
  * Transport return codes
  */
 
-#define USB_STOR_TRANSPORT_GOOD    0   /* Transport good, command good     */
+#define USB_STOR_TRANSPORT_GOOD	   0   /* Transport good, command good	   */
 #define USB_STOR_TRANSPORT_FAILED  1   /* Transport good, command failed   */
 #define USB_STOR_TRANSPORT_ERROR   2   /* Transport bad (i.e. device dead) */
 
@@ -147,9 +147,11 @@
 };
 
 /* Flag definitions */
-#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0 */
+#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_START_STOP      0x00000004 /* ignore START_STOP commands */
+						    Win/MacOS compatibility */
+#define US_FL_START_STOP      0x00000004 /* ignore START_STOP commands	    */
 #define US_FL_ALT_LENGTH      0x00000008 /* use the alternate algorithm for
-                                                    us_transfer_length() */
+						    us_transfer_length()    */
+#define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.3.99-pre6/linux/drivers/usb/usb-uhci.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/usb-uhci.c	Fri Apr 28 22:53:10 2000
@@ -29,9 +29,7 @@
 #include <linux/interrupt.h>	/* for in_interrupt() */
 #include <linux/init.h>
 #include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
 #include <linux/pm.h>
-#endif
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -2634,7 +2632,6 @@
 	return 0;
 }
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
 _static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
 {
 	uhci_t *s = (uhci_t*) dev->data;
@@ -2651,7 +2648,6 @@
 	}
 	return 0;
 }
-#endif
 
 _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
 {
@@ -2754,11 +2750,11 @@
 
 	//chain new uhci device into global list
 	devs = s;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
+
 	pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(dev), handle_pm_event);
 	if (pmdev)
 		pmdev->data = s;
-#endif
+
 	return 0;
 }
 
@@ -2768,19 +2764,12 @@
 
 	/* Search for the IO base address.. */
 	for (i = 0; i < 6; i++) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+
 		unsigned int io_addr = dev->resource[i].start;
 		unsigned int io_size =
 		dev->resource[i].end - dev->resource[i].start + 1;
 		if (!(dev->resource[i].flags & 1))
 			continue;
-#else
-		unsigned int io_addr = dev->base_address[i];
-		unsigned int io_size = 0x14;
-		if (!(io_addr & 1))
-			continue;
-		io_addr &= ~1;
-#endif
 
 		/* Is it already in use? */
 		if (check_region (io_addr, io_size))
@@ -2835,10 +2824,10 @@
 		if (type != 0)
 			continue;
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+
 		if (pci_enable_device (dev) < 0)
 			continue;
-#endif
+
 		if(!dev->irq)
 		{
 			err("Found UHCI device with no IRQ assigned. Check BIOS settings!");
@@ -2879,9 +2868,7 @@
 
 void cleanup_module (void)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
 	pm_unregister_all (handle_pm_event);
-#endif
 	uhci_cleanup ();
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.99-pre6/linux/drivers/usb/usb.c	Wed Apr 12 10:02:34 2000
+++ linux/drivers/usb/usb.c	Mon May  8 17:37:28 2000
@@ -539,17 +539,6 @@
 }
 
 /*-------------------------------------------------------------------*
- * completion handler for compatibility wrappers (async bulk)        *
- *-------------------------------------------------------------------*/
-static void usb_api_async_completion(urb_t *urb)
-{
-	api_wrapper_data *awd = (api_wrapper_data *)urb->context;
-
-	if (awd->handler)
-		awd->handler(urb->status, urb->transfer_buffer, urb->actual_length, awd->stuff);
- }
-
-/*-------------------------------------------------------------------*
  *                         COMPATIBILITY STUFF                       *
  *-------------------------------------------------------------------*/
 
@@ -668,50 +657,6 @@
 
 	return usb_start_wait_urb(urb,timeout,actual_length);
 }
-/*-------------------------------------------------------------------*/
-
-void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
-{
-	urb_t *urb;
-	api_wrapper_data *awd;
-
-	if (!(urb=usb_alloc_urb(0)))
-		return NULL;
-	if (!(awd = kmalloc(sizeof(api_wrapper_data), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) {
-		kfree(urb);
-		return NULL;
-	}
-
-	/* build urb */
-	FILL_BULK_URB(urb, dev, pipe, data, len, (usb_complete_t)usb_api_async_completion, awd);
-
-	awd->handler=handler;
-	awd->stuff=dev_id;
-	if (usb_submit_urb(urb) < 0) {
-		kfree(awd);
-		kfree(urb);
-		return NULL;
-	}
-	return urb;
-}
-
-// compatibility wrapper. Remove urb only if it is called before the
-// transaction's completion interrupt. If called from within the
-// completion handler (urb->completed==1), it does nothing, since the
-// qh is already removed 
-
-int usb_terminate_bulk(struct usb_device *dev, void *first)
-{
-	urb_t *urb=(urb_t*)first;
-	dbg("usb_terminate_bulk: urb:%p",urb);
-	if (!urb) // none found? there is nothing to remove!
-		return -ENODEV;
-  
-	usb_unlink_urb(urb);
-	kfree(urb->context);
-	kfree(urb);
-	return USB_ST_NOERROR;
-}
 
 /*
  * usb_release_bandwidth():
@@ -728,106 +673,6 @@
 		dev->bus->bandwidth_isoc_reqs);
 }
 
-static void irq_callback(urb_t *urb)
-{
-	struct irq_wrapper_data *wd = (struct irq_wrapper_data *)urb->context;
-
-	if (!wd->handler)
-		return;
-#if 0 // verbose...
-	if (!wd->handler(urb->status, urb->transfer_buffer, urb->actual_length, wd->context))
-		err("legacy irq callback returned 0!!!");
-#else
-	wd->handler(urb->status, urb->transfer_buffer, urb->actual_length, wd->context);
-#endif
-}
-
-int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
-{
-	long    bustime;
-	int     ret;
-	struct irq_wrapper_data *wd;
-	urb_t *urb;
-	unsigned int maxsze = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-	*handle = NULL;
-	
-	//dbg("irq: dev:%p pipe:%08X handler:%p period:%d dev_id:%p max:%d", dev, pipe, handler, period, dev_id, maxsze);
-	
-	/* Check host controller's bandwidth for this int. request. */
-	bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
-			usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
-	bustime = NS_TO_US(bustime);	/* work in microseconds */
-	if (check_bandwidth_alloc (dev->bus->bandwidth_allocated, bustime))
-		return -EUSERS;  // no bandwidth left
-
-	if (!maxsze || !usb_pipeint(pipe))
-		return -EINVAL;
-
-	if (!(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
-
-	if (!(wd = kmalloc(sizeof(struct irq_wrapper_data), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) {
-		kfree(urb);
-		return -ENOMEM;
-	}
-	if (!(urb->transfer_buffer = kmalloc(maxsze, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) {
-		kfree(urb);
-		kfree(wd);
-		return -ENOMEM;
-	}
-	wd->handler=handler;
-	wd->context=dev_id;
-	urb->dev = dev;
-	urb->pipe = pipe;
-	urb->transfer_buffer_length = urb->actual_length = maxsze;
-	urb->interval = period;
-	urb->context = wd;
-	urb->complete = irq_callback;
-	if ((ret = usb_submit_urb(urb)) < 0) {
-		kfree(wd);
-		kfree(urb->transfer_buffer);
-		kfree(urb);
-		return ret;
-	}
-	*handle = urb;
-
-	/* Claim the USB bandwidth if no error. */
-	if (!ret) {
-		dev->bus->bandwidth_allocated += bustime;
-		dev->bus->bandwidth_int_reqs++;
-		dbg("bw_alloc bumped to %d for %d requesters",
-			dev->bus->bandwidth_allocated,
-			dev->bus->bandwidth_int_reqs +
-			dev->bus->bandwidth_isoc_reqs);
-	}
-
-	return ret;
-}
-
-int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe)
-{
-	long    bustime;
-	int	err;
-	urb_t *urb = (urb_t*)handle;
-
-	if (!urb)
-		return -EBADF;
-	err=usb_unlink_urb(urb);
-	kfree(urb->context);
-	kfree(urb->transfer_buffer);
-	kfree(urb);
-
-	/* Return the USB bandwidth if no error. */
-	if (!err) {
-		bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
-				usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
-		bustime = NS_TO_US(bustime);	/* work in microseconds */
-		usb_release_bandwidth(dev, bustime);
-	}
-	return err;
-}
-
 /*
  * usb_get_current_frame_number()
  *
@@ -1206,10 +1051,10 @@
  */
 int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
 {
-	char buf [20];
+	char buf [30];
 
 	// assert (len > (2 * (sizeof (buf) + 1)));
-	// assert (strlen (type) ~== 4);
+	// assert (strlen (type) <= 8);
 
 	// language ids
 	if (id == 0) {
@@ -1906,8 +1751,4 @@
 EXPORT_SYMBOL(usb_unlink_urb);
 
 EXPORT_SYMBOL(usb_control_msg);
-EXPORT_SYMBOL(usb_request_irq);
-EXPORT_SYMBOL(usb_release_irq);
 EXPORT_SYMBOL(usb_bulk_msg);
-EXPORT_SYMBOL(usb_request_bulk);
-EXPORT_SYMBOL(usb_terminate_bulk);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.3.99-pre6/linux/drivers/usb/uss720.c	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/uss720.c	Mon May  8 15:48:18 2000
@@ -620,7 +620,9 @@
 	struct parport *pp = (struct parport *)ptr;
 	struct parport_uss720_private *priv = pp->private_data;
 
+#if 0
 	usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
+#endif
 	priv->usbdev = NULL;
 	parport_proc_unregister(pp);
 	parport_unregister_port(pp);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.99-pre6/linux/drivers/video/Makefile	Tue Apr 11 15:09:21 2000
+++ linux/drivers/video/Makefile	Tue May  2 12:59:39 2000
@@ -48,7 +48,7 @@
 
 # Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
 obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o
-obj-$(CONFIG_FB_COMPAT_XPMAC)     += macmodes.o
+obj-$(CONFIG_PPC)                 += macmodes.o
 
 obj-$(CONFIG_FB_ACORN)            += acornfb.o
 obj-$(CONFIG_FB_AMIGA)            += amifb.o
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.99-pre6/linux/drivers/video/aty128fb.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/video/aty128fb.c	Tue May  2 12:59:07 2000
@@ -14,11 +14,10 @@
  *		- monitor sensing (DDC)
  *              - virtual display
  *		- other platform support (only ppc/x86 supported)
- *		- PPLL_REF_DIV & XTALIN calculation    -done for x86
- *		- determine MCLK from previous setting -done for x86            
- *              - calculate XCLK, rather than probe BIOS
  *		- hardware cursor support
  *		- ioctl()'s
+ *
+ *    Please cc: your patches to brad@neruo.com.
  */
 
 /*
@@ -82,7 +81,7 @@
 #endif
 
 /* default mode */
-static struct fb_var_screeninfo default_var = {
+static struct fb_var_screeninfo default_var __initdata = {
     /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
     640, 480, 640, 480, 0, 0, 8, 0,
     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -118,6 +117,7 @@
 };
 
 /* packed BIOS settings */
+#ifndef CONFIG_PPC
 #pragma pack(1)
 typedef struct {
     u8 clock_chip_type;
@@ -144,6 +144,7 @@
     u32 XCLK_max_freq;
 } PLL_BLOCK;
 #pragma pack()
+#endif /* !CONFIG_PPC */
 
 /* onboard memory information */
 struct aty128_meminfo {
@@ -1772,8 +1773,9 @@
         info->palette[j].blue = default_blu[k];
     }
 
+    /* setup the DAC the way we like it */
     dac = aty_ld_le32(DAC_CNTL);
-    dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL | DAC_BLANKING);
+    dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL);
     dac |= DAC_MASK;
     aty_st_le32(DAC_CNTL, dac);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.3.99-pre6/linux/drivers/video/clgenfb.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/clgenfb.c	Thu May 11 13:45:34 2000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
  *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
  *
  * Contributors (thanks, all!)
  *
@@ -31,9 +31,10 @@
  *
  */
 
-#define CLGEN_VERSION "1.9.4.5"
+#define CLGEN_VERSION "1.9.6"
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -73,27 +74,6 @@
 
 /*****************************************************************
  *
- * compatibility with older kernel versions
- *
- */
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-#endif
-
-#ifndef PCI_DEVICE_ID_CIRRUS_5462
-#define PCI_DEVICE_ID_CIRRUS_5462      0x00d0
-#endif
-
-
-
-
-/*****************************************************************
- *
  * debugging and utility macros
  *
  */
@@ -139,8 +119,6 @@
 #define MAX_NUM_BOARDS 7
 
 
-
-
 /*****************************************************************
  *
  * chipset information
@@ -161,7 +139,6 @@
 } clgen_board_t;
 
 
-
 /*
  * per-board-type information, used for enumerating and abstracting
  * chip-specific information
@@ -311,7 +288,6 @@
 #endif /* CONFIG_PCI */
 
 
-
 #ifdef CONFIG_ZORRO
 static const struct {
 	clgen_board_t btype;
@@ -495,10 +471,6 @@
 int clgenfb_init (void);
 int clgenfb_setup (char *options);
 
-#ifdef MODULE
-static void clgenfb_cleanup (struct clgenfb_info *info);
-#endif
-
 static int clgenfb_open (struct fb_info *info, int user);
 static int clgenfb_release (struct fb_info *info, int user);
 static int clgenfb_ioctl (struct inode *inode, struct file *file,
@@ -2592,7 +2564,10 @@
 	iounmap (info->fbmem);
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
 	release_mem_region(info->fbmem_phys, info->size);
+
+#if 0 /* if system didn't claim this region, we would... */
 	release_mem_region(0xA0000, 65535);
+#endif
 	if (release_io_ports)
 		release_region(0x3C0, 32);
 #endif
@@ -2678,17 +2653,19 @@
 
 	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
 		pci_write_config_word (pdev, PCI_COMMAND, tmp16);
-		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
+		printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
 		       board_addr);
 		return -1;
 	}
+#if 0 /* if the system didn't claim this region, we would... */
 	if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
 		pci_write_config_word (pdev, PCI_COMMAND, tmp16);
-		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
+		printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
 		       0xA0000L);
 		release_mem_region(board_addr, board_size);
 		return -1;
 	}
+#endif
 	if (request_region(0x3C0, 32, "clgenfb"))
 		release_io_ports = 1;
 
@@ -2784,7 +2761,7 @@
 	info->board_size = board_size = z->resource.end-z->resource.start+1;
 
 	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
-		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
+		printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
 		       board_addr);
 		return -1;
 	}
@@ -2932,25 +2909,15 @@
 #if defined(CONFIG_FB_OF)
 int __init clgen_of_init (struct device_node *dp)
 {
-	int rc;
-	
-	DPRINTK ("ENTER\n");
-
-	rc = clgenfb_init ();
-
-	DPRINTK ("EXIT, returning %d\n", rc);
-
-	return rc;
+	return clgenfb_init ();
 }
 #endif				/* CONFIG_FB_OF */
 
 
-
     /*
      *  Cleanup (only needed for module)
      */
-#ifdef MODULE
-static void clgenfb_cleanup (struct clgenfb_info *info)
+static void __exit clgenfb_cleanup (struct clgenfb_info *info)
 {
 	DPRINTK ("ENTER\n");
 
@@ -2967,9 +2934,6 @@
 
 	DPRINTK ("EXIT\n");
 }
-#endif
-
-
 
 
 #ifndef MODULE
@@ -2999,33 +2963,14 @@
 #endif
 
 
-
-
-
     /*
      *  Modularization
      */
 
-#ifdef MODULE
-MODULE_AUTHOR("Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 
-int init_module (void)
-{
-#if defined(CONFIG_FB_OF)
-/* Nothing to do, must be called from offb */
-	return 0;
-#else
-	int i;
-	
-	DPRINTK ("ENTER\n");
-	i = clgenfb_init ();
-	DPRINTK ("EXIT\n");
-	return i;
-#endif
-}
-
-void cleanup_module (void)
+static void __exit clgenfb_exit (void)
 {
 	DPRINTK ("ENTER\n");
 
@@ -3034,7 +2979,10 @@
 	DPRINTK ("EXIT\n");
 }
 
-#endif				/* MODULE */
+#ifdef MODULE
+module_init(clgenfb_init);
+#endif
+module_exit(clgenfb_exit);
 
 
 /**********************************************************************/
@@ -3144,7 +3092,6 @@
 }
 
 
-
 /*** WSFR() - write to the "special function register" (SFR) ***/
 static void WSFR (struct clgenfb_info *fb_info, unsigned char val)
 {
@@ -3193,7 +3140,6 @@
 }
 
 
-
 #if 0
 /*** RClut - read CLUT entry (range 0..63) ***/
 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
@@ -3322,6 +3268,7 @@
 	DPRINTK ("EXIT\n");
 }
 
+
 /*******************************************************************
 	clgen_RectFill()
 
@@ -3402,6 +3349,7 @@
 	DPRINTK ("EXIT\n");
 }
 
+
 /**************************************************************************
  * bestclock() - determine closest possible clock lower(?) than the
  * desired pixel clock
@@ -3478,10 +3426,6 @@
 }
 
 
-
-
-
-
 /* -------------------------------------------------------------------------
  *
  * debugging functions
@@ -3518,7 +3462,6 @@
 }
 
 
-
 /**
  * clgen_dbg_print_regs
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3566,9 +3509,6 @@
 }
 
 
-
-
-
 /**
  * clgen_dump
  * @clgeninfo:
@@ -3583,7 +3523,6 @@
 }
 
 
-
 /**
  * clgen_dbg_reg_dump
  * @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3685,5 +3624,5 @@
 	DPRINTK ("\n");
 }
 
-
 #endif				/* CLGEN_DEBUG */
+
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.3.99-pre6/linux/drivers/video/fbcon.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/video/fbcon.c	Wed May  3 01:47:56 2000
@@ -229,15 +229,13 @@
 static void cursor_timer_handler(unsigned long dev_addr);
 
 static struct timer_list cursor_timer = {
-    NULL, NULL, 0, 0L, cursor_timer_handler
+    function: cursor_timer_handler
 };
 
 static void cursor_timer_handler(unsigned long dev_addr)
 {
       fbcon_vbl_handler(0, NULL, NULL);
       cursor_timer.expires = jiffies+HZ/50;
-      cursor_timer.data = 0;
-      cursor_timer.next = cursor_timer.prev = NULL;
       add_timer(&cursor_timer);
 }
 
@@ -411,8 +409,6 @@
     if (irqres) {
 	cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
 	cursor_timer.expires = jiffies+HZ/50;
-	cursor_timer.data = 0;
-	cursor_timer.next = cursor_timer.prev = NULL;
 	add_timer(&cursor_timer);
     }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.3.99-pre6/linux/drivers/video/imsttfb.c	Thu Jan  6 12:57:48 2000
+++ linux/drivers/video/imsttfb.c	Wed May  3 01:45:18 2000
@@ -1927,9 +1927,10 @@
 	while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
 		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
 			continue;
-		pci_enable_device(pdev);
+		if (pci_enable_device(pdev))
+			continue;
 
-		addr = pdev->resource[0].start;
+		addr = pci_resource_start (pdev, 0);
 		if (!addr)
 			continue;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c
--- v2.3.99-pre6/linux/drivers/video/macmodes.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/video/macmodes.c	Wed May  3 01:47:57 2000
@@ -12,6 +12,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/string.h>
@@ -188,8 +189,10 @@
     { -1,    VMODE_640_480_60 },	/* catch-all, must be last */
 };
 
+#ifdef CONFIG_FB_COMPAT_XPMAC
 struct fb_info *console_fb_info = NULL;
 struct vc_mode display_info;
+
 static u16 palette_red[16];
 static u16 palette_green[16];
 static u16 palette_blue[16];
@@ -198,20 +201,12 @@
 };
 
 
-int console_getmode(struct vc_mode *);
-int console_setmode(struct vc_mode *, int);
-int console_setcmap(int, unsigned char *, unsigned char *, unsigned char *);
-int console_powermode(int);
-int mac_var_to_vmode(const struct fb_var_screeninfo *, int *, int *);
-
-
 int console_getmode(struct vc_mode *mode)
 {
     *mode = display_info;
     return 0;
 }
 
-
 int console_setmode(struct vc_mode *mode, int doit)
 {
     struct fb_var_screeninfo var;
@@ -258,7 +253,6 @@
     return 0;
 }
 
-
 int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
                     unsigned char *blue)
 {
@@ -289,6 +283,17 @@
     return 0;
 }
 
+int console_powermode(int mode)
+{
+    if (mode == VC_POWERMODE_INQUIRY)
+        return 0;
+    if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+        return -EINVAL;
+    /* Not Supported */
+    return -ENXIO;
+}
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
 
     /*
      *  Convert a MacOS vmode/cmode pair to a frame buffer video mode structure
@@ -360,17 +365,6 @@
     var->sync = mode->sync;
     var->vmode = mode->vmode;
     return 0;
-}
-
-
-int console_powermode(int mode)
-{
-    if (mode == VC_POWERMODE_INQUIRY)
-        return 0;
-    if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
-        return -EINVAL;
-    /* Not Supported */
-    return -ENXIO;
 }
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c
--- v2.3.99-pre6/linux/drivers/video/matrox/matroxfb_base.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/matrox/matroxfb_base.c	Wed May  3 01:45:17 2000
@@ -2034,7 +2034,7 @@
 	ACCESS_FBINFO(fastfont.size) = fastfont;
 
 	ACCESS_FBINFO(cursor.state) = CM_ERASE;
-	ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL;
+	init_timer (&ACCESS_FBINFO(cursor.timer));
 	ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO;
 	spin_lock_init(&ACCESS_FBINFO(lock.DAC));
 	spin_lock_init(&ACCESS_FBINFO(lock.accel));
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.3.99-pre6/linux/drivers/video/sbusfb.c	Wed Dec 29 13:13:20 1999
+++ linux/drivers/video/sbusfb.c	Fri May  5 12:24:17 2000
@@ -131,10 +131,12 @@
 	struct fb_info_sbusfb *fb = sbusfbinfo(info);
 	
 	if (user) {
-		if (fb->open) return -EBUSY;
-		fb->mmaped = 0;
-		fb->open = 1;
-		fb->vtconsole = -1;
+		if (fb->open == 0) {
+			fb->mmaped = 0;
+			fb->open = 1;
+			fb->vtconsole = -1;
+		}
+		fb->open++;
 	} else
 		fb->consolecnt++;
 	MOD_INC_USE_COUNT;
@@ -146,15 +148,18 @@
 	struct fb_info_sbusfb *fb = sbusfbinfo(info);
 
 	if (user) {	
-		if (fb->vtconsole != -1) {
-			vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
-			if (fb->mmaped) {
-				fb->graphmode--;
-				sbusfb_clear_margin(&fb_display[fb->vtconsole], 0);
+		fb->open--;
+		if (fb->open == 0) {
+			if (fb->vtconsole != -1) {
+				vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+				if (fb->mmaped) {
+					fb->graphmode--;
+					sbusfb_clear_margin(&fb_display[fb->vtconsole], 0);
+				}
 			}
+			if (fb->reset)
+				fb->reset(fb);
 		}
-		if (fb->reset)
-			fb->reset(fb);
 		fb->open = 0;
 	} else
 		fb->consolecnt--;
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.3.99-pre6/linux/drivers/video/tdfxfb.c	Wed Apr 26 16:34:08 2000
+++ linux/drivers/video/tdfxfb.c	Fri May  5 12:37:52 2000
@@ -2052,10 +2052,10 @@
       currcon = -1;
       if (!nohwcursor) tdfxfb_hwcursor_init();
        
+      init_timer(&fb_info.cursor.timer);
       fb_info.cursor.timer.function = do_flashcursor; 
-      fb_info.cursor.state = CM_ERASE;
-      fb_info.cursor.timer.prev = fb_info.cursor.timer.next=NULL;
       fb_info.cursor.timer.data = (unsigned long)(&fb_info);
+      fb_info.cursor.state = CM_ERASE;
       spin_lock_init(&fb_info.DAClock);
        
       strcpy(fb_info.fb_info.modename, "3Dfx "); 
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.3.99-pre6/linux/drivers/video/vesafb.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/video/vesafb.c	Thu May 11 13:45:35 2000
@@ -543,12 +543,19 @@
 
 	if (!request_mem_region(video_base, video_size, "vesafb")) {
 		printk(KERN_ERR
-		       "vesafb: abort, cannot reserve video memory at 0x%lu\n",
+		       "vesafb: abort, cannot reserve video memory at 0x%lx\n",
 			video_base);
-		return -1;
+		return -EBUSY;
 	}
 
         video_vbase = ioremap(video_base, video_size);
+	if (!video_vbase) {
+		release_mem_region(video_base, video_size);
+		printk(KERN_ERR
+		       "vesafb: abort, cannot ioremap video memory 0x%lx @ 0x%lx\n",
+			video_size, video_base);
+		return -EIO;
+	}
 
 	printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
 	       video_base, video_vbase, video_size/1024);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/vga.h linux/drivers/video/vga.h
--- v2.3.99-pre6/linux/drivers/video/vga.h	Thu Jan  6 12:57:48 2000
+++ linux/drivers/video/vga.h	Thu Apr 27 15:55:09 2000
@@ -179,39 +179,39 @@
  * generic VGA port read/write
  */
  
-extern inline unsigned char vga_io_r (unsigned short port)
+static inline unsigned char vga_io_r (unsigned short port)
 {
 	return inb (port);
 }
 
-extern inline void vga_io_w (unsigned short port, unsigned char val)
+static inline void vga_io_w (unsigned short port, unsigned char val)
 {
 	outb (val, port);
 }
 
-extern inline void vga_io_w_fast (unsigned short port, unsigned char reg,
+static inline void vga_io_w_fast (unsigned short port, unsigned char reg,
 				  unsigned char val)
 {
 	outw (VGA_OUT16VAL (val, reg), port);
 }
 
-extern inline unsigned char vga_mm_r (caddr_t regbase, unsigned short port)
+static inline unsigned char vga_mm_r (caddr_t regbase, unsigned short port)
 {
 	return readb (regbase + port);
 }
 
-extern inline void vga_mm_w (caddr_t regbase, unsigned short port, unsigned char val)
+static inline void vga_mm_w (caddr_t regbase, unsigned short port, unsigned char val)
 {
 	writeb (val, regbase + port);
 }
 
-extern inline void vga_mm_w_fast (caddr_t regbase, unsigned short port,
+static inline void vga_mm_w_fast (caddr_t regbase, unsigned short port,
 				  unsigned char reg, unsigned char val)
 {
 	writew (VGA_OUT16VAL (val, reg), regbase + port);
 }
 
-extern inline unsigned char vga_r (caddr_t regbase, unsigned short port)
+static inline unsigned char vga_r (caddr_t regbase, unsigned short port)
 {
 	if (regbase)
 		return vga_mm_r (regbase, port);
@@ -219,7 +219,7 @@
 		return vga_io_r (port);
 }
 
-extern inline void vga_w (caddr_t regbase, unsigned short port, unsigned char val)
+static inline void vga_w (caddr_t regbase, unsigned short port, unsigned char val)
 {
 	if (regbase)
 		vga_mm_w (regbase, port, val);
@@ -228,7 +228,7 @@
 }
 
 
-extern inline void vga_w_fast (caddr_t regbase, unsigned short port,
+static inline void vga_w_fast (caddr_t regbase, unsigned short port,
 			       unsigned char reg, unsigned char val)
 {
 	if (regbase)
@@ -242,13 +242,13 @@
  * VGA CRTC register read/write
  */
  
-extern inline unsigned char vga_rcrt (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rcrt (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_CRT_IC, reg);
         return vga_r (regbase, VGA_CRT_DC);
 }
 
-extern inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_w_fast (regbase, VGA_CRT_IC, reg, val);
@@ -258,13 +258,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rcrt (unsigned char reg)
+static inline unsigned char vga_io_rcrt (unsigned char reg)
 {
         vga_io_w (VGA_CRT_IC, reg);
         return vga_io_r (VGA_CRT_DC);
 }
 
-extern inline void vga_io_wcrt (unsigned char reg, unsigned char val)
+static inline void vga_io_wcrt (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_io_w_fast (VGA_CRT_IC, reg, val);
@@ -274,13 +274,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rcrt (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rcrt (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_CRT_IC, reg);
         return vga_mm_r (regbase, VGA_CRT_DC);
 }
 
-extern inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_mm_w_fast (regbase, VGA_CRT_IC, reg, val);
@@ -295,13 +295,13 @@
  * VGA sequencer register read/write
  */
  
-extern inline unsigned char vga_rseq (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rseq (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_SEQ_I, reg);
         return vga_r (regbase, VGA_SEQ_D);
 }
 
-extern inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_w_fast (regbase, VGA_SEQ_I, reg, val);
@@ -311,13 +311,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rseq (unsigned char reg)
+static inline unsigned char vga_io_rseq (unsigned char reg)
 {
         vga_io_w (VGA_SEQ_I, reg);
         return vga_io_r (VGA_SEQ_D);
 }
 
-extern inline void vga_io_wseq (unsigned char reg, unsigned char val)
+static inline void vga_io_wseq (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_io_w_fast (VGA_SEQ_I, reg, val);
@@ -327,13 +327,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rseq (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rseq (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_SEQ_I, reg);
         return vga_mm_r (regbase, VGA_SEQ_D);
 }
 
-extern inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_mm_w_fast (regbase, VGA_SEQ_I, reg, val);
@@ -349,13 +349,13 @@
  * VGA graphics controller register read/write
  */
  
-extern inline unsigned char vga_rgfx (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rgfx (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_GFX_I, reg);
         return vga_r (regbase, VGA_GFX_D);
 }
 
-extern inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_w_fast (regbase, VGA_GFX_I, reg, val);
@@ -365,13 +365,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_io_rgfx (unsigned char reg)
+static inline unsigned char vga_io_rgfx (unsigned char reg)
 {
         vga_io_w (VGA_GFX_I, reg);
         return vga_io_r (VGA_GFX_D);
 }
 
-extern inline void vga_io_wgfx (unsigned char reg, unsigned char val)
+static inline void vga_io_wgfx (unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_io_w_fast (VGA_GFX_I, reg, val);
@@ -381,13 +381,13 @@
 #endif /* VGA_OUTW_WRITE */
 }
 
-extern inline unsigned char vga_mm_rgfx (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rgfx (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_GFX_I, reg);
         return vga_mm_r (regbase, VGA_GFX_D);
 }
 
-extern inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
 {
 #ifdef VGA_OUTW_WRITE
 	vga_mm_w_fast (regbase, VGA_GFX_I, reg, val);
@@ -402,37 +402,37 @@
  * VGA attribute controller register read/write
  */
  
-extern inline unsigned char vga_rattr (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_rattr (caddr_t regbase, unsigned char reg)
 {
         vga_w (regbase, VGA_ATT_IW, reg);
         return vga_r (regbase, VGA_ATT_R);
 }
 
-extern inline void vga_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
 {
         vga_w (regbase, VGA_ATT_IW, reg);
         vga_w (regbase, VGA_ATT_W, val);
 }
 
-extern inline unsigned char vga_io_rattr (unsigned char reg)
+static inline unsigned char vga_io_rattr (unsigned char reg)
 {
         vga_io_w (VGA_ATT_IW, reg);
         return vga_io_r (VGA_ATT_R);
 }
 
-extern inline void vga_io_wattr (unsigned char reg, unsigned char val)
+static inline void vga_io_wattr (unsigned char reg, unsigned char val)
 {
         vga_io_w (VGA_ATT_IW, reg);
         vga_io_w (VGA_ATT_W, val);
 }
 
-extern inline unsigned char vga_mm_rattr (caddr_t regbase, unsigned char reg)
+static inline unsigned char vga_mm_rattr (caddr_t regbase, unsigned char reg)
 {
         vga_mm_w (regbase, VGA_ATT_IW, reg);
         return vga_mm_r (regbase, VGA_ATT_R);
 }
 
-extern inline void vga_mm_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+static inline void vga_mm_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
 {
         vga_mm_w (regbase, VGA_ATT_IW, reg);
         vga_mm_w (regbase, VGA_ATT_W, val);
diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.3.99-pre6/linux/drivers/video/vga16fb.c	Thu Jan  6 12:57:48 2000
+++ linux/drivers/video/vga16fb.c	Fri May  5 12:37:52 2000
@@ -104,8 +104,6 @@
 
 static int             currcon   = 0;
 
-static int release_io_ports = 0;
-
 /* --------------------------------------------------------------------- */
 
 	/*
@@ -918,16 +916,13 @@
 	}
 }
 
-int __init vga16_init(void)
+int __init vga16fb_init(void)
 {
 	int i,j;
 
 	printk(KERN_DEBUG "vga16fb: initializing\n");
 
-	if (!request_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN, "vga16fb")) {
-		printk (KERN_ERR "vga16fb: unable to reserve VGA memory, exiting\n");
-		return -1;
-	}
+	/* XXX share VGA_FB_PHYS region with vgacon */
 
         vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
 	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
@@ -948,10 +943,7 @@
 		palette[i].blue  = default_blu[j];
 	}
 
-	/* note - does not cause failure, b/c vgacon probably still owns this 
-	 * region (FIXME) */
-	if (request_region(0x3C0, 32, "vga16fb"))
-		release_io_ports = 1;
+	/* XXX share VGA I/O region with vgacon and others */
 
 	disp.var = vga16fb_defined;
 
@@ -976,29 +968,18 @@
 	return 0;
 }
 
-#ifndef MODULE
-int __init vga16fb_init(void)
-{
-    return vga16_init();
-}
-
-#else /* MODULE */
-
-int init_module(void)
-{
-    return vga16_init();
-}
-
-void cleanup_module(void)
+static void __exit vga16fb_exit(void)
 {
     unregister_framebuffer(&vga16fb.fb_info);
     iounmap(vga16fb.video_vbase);
-    release_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
-    if (release_io_ports)
-    	release_region(0x3c0, 32);
+    /* XXX unshare VGA regions */
 }
 
+#ifdef MODULE
+module_init(vga16fb_init);
 #endif
+module_exit(vga16fb_exit);
+
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/Config.in linux/fs/Config.in
--- v2.3.99-pre6/linux/fs/Config.in	Wed Apr 26 16:34:08 2000
+++ linux/fs/Config.in	Mon May  8 22:00:41 2000
@@ -41,6 +41,7 @@
 bool '/proc file system support' CONFIG_PROC_FS
 
 dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL
+dep_bool '  Automatically mount at boot' CONFIG_DEVFS_MOUNT $CONFIG_DEVFS_FS
 dep_bool '  Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS
 
 # It compiles as a module for testing only.  It should not be used
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.3.99-pre6/linux/fs/adfs/inode.c	Wed Apr 26 16:34:08 2000
+++ linux/fs/adfs/inode.c	Mon May  8 13:51:01 2000
@@ -49,12 +49,12 @@
 	return 0;
 }
 
-static int adfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int adfs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page, adfs_get_block);
 }
 
-static int adfs_readpage(struct dentry *dentry, struct page *page)
+static int adfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page, adfs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.3.99-pre6/linux/fs/affs/file.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/affs/file.c	Mon May  8 13:51:01 2000
@@ -338,11 +338,11 @@
 
 }
 		
-static int affs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int affs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,affs_get_block);
 }
-static int affs_readpage(struct dentry *dentry, struct page *page)
+static int affs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,affs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v2.3.99-pre6/linux/fs/affs/symlink.c	Sat Feb 26 22:31:51 2000
+++ linux/fs/affs/symlink.c	Mon May  8 14:21:38 2000
@@ -15,10 +15,10 @@
 #include <linux/amigaffs.h>
 #include <linux/pagemap.h>
 
-static int affs_symlink_readpage(struct dentry *dentry, struct page *page)
+static int affs_symlink_readpage(struct file *file, struct page *page)
 {
 	struct buffer_head *bh;
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	char *link = (char*)kmap(page);
 	struct slink_front *lf;
 	int err;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/attr.c linux/fs/attr.c
--- v2.3.99-pre6/linux/fs/attr.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/attr.c	Mon May  8 14:31:13 2000
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 
 /* Taken over from the old code... */
 
@@ -91,6 +92,7 @@
 	if (!(ia_valid & ATTR_MTIME_SET))
 		attr->ia_mtime = now;
 
+	lock_kernel();
 	if (inode && inode->i_op && inode->i_op->setattr) 
 		error = inode->i_op->setattr(dentry, attr);
 	else {
@@ -98,5 +100,6 @@
 		if (!error)
 			inode_setattr(inode, attr);
 	}
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.3.99-pre6/linux/fs/autofs/autofs_i.h	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs/autofs_i.h	Tue May  2 12:36:09 2000
@@ -132,7 +132,7 @@
 /* Expiration-handling functions */
 
 void autofs_update_usage(struct autofs_dirhash *,struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_expire(struct super_block *,struct autofs_sb_info *);
+struct autofs_dir_ent *autofs_expire(struct super_block *,struct autofs_sb_info *, struct vfsmount *mnt);
 
 /* Operations structures */
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c
--- v2.3.99-pre6/linux/fs/autofs/dirhash.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs/dirhash.c	Tue May  2 12:36:09 2000
@@ -34,7 +34,8 @@
 }
 
 struct autofs_dir_ent *autofs_expire(struct super_block *sb,
-				     struct autofs_sb_info *sbi)
+				     struct autofs_sb_info *sbi,
+				     struct vfsmount *mnt)
 {
 	struct autofs_dirhash *dh = &sbi->dirhash;
 	struct autofs_dir_ent *ent;
@@ -79,12 +80,25 @@
 			DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
 			continue;
 		}
+		mntget(mnt);
+		dget(dentry);
+		if (!follow_down(&mnt, &dentry)) {
+			dput(dentry);
+			mntput(mnt);
+			DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
+			continue;
+		}
+		while (d_mountpoint(dentry) && follow_down(&mnt, &dentry))
+			;
+		dput(dentry);
 
-		if ( !is_root_busy(dentry->d_mounts) ) {
+		if ( may_umount(mnt) == 0 ) {
+			mntput(mnt);
 			DPRINTK(("autofs: signaling expire on %s\n", ent->name));
 			return ent; /* Expirable! */
 		}
-		DPRINTK(("autofs: didn't expire due to is_root_busy: %s\n", ent->name));
+		DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name));
+		mntput(mnt);
 	}
 	return NULL;		/* No expirable entries */
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.3.99-pre6/linux/fs/autofs/root.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs/root.c	Tue May  2 12:36:09 2000
@@ -432,6 +432,7 @@
 /* Perform an expiry operation */
 static inline int autofs_expire_run(struct super_block *sb,
 				    struct autofs_sb_info *sbi,
+				    struct vfsmount *mnt,
 				    struct autofs_packet_expire *pkt_p)
 {
 	struct autofs_dir_ent *ent;
@@ -443,7 +444,7 @@
 	pkt.hdr.type = autofs_ptype_expire;
 
 	if ( !sbi->exp_timeout ||
-	     !(ent = autofs_expire(sb,sbi)) )
+	     !(ent = autofs_expire(sb,sbi,mnt)) )
 		return -EAGAIN;
 
 	pkt.len = ent->len;
@@ -487,7 +488,7 @@
 	case AUTOFS_IOC_SETTIMEOUT:
 		return autofs_get_set_timeout(sbi,(unsigned long *)arg);
 	case AUTOFS_IOC_EXPIRE:
-		return autofs_expire_run(inode->i_sb,sbi,
+		return autofs_expire_run(inode->i_sb, sbi, filp->f_vfsmnt,
 					 (struct autofs_packet_expire *)arg);
 	default:
 		return -ENOSYS;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs4/autofs_i.h linux/fs/autofs4/autofs_i.h
--- v2.3.99-pre6/linux/fs/autofs4/autofs_i.h	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs4/autofs_i.h	Thu May 11 11:30:39 2000
@@ -129,9 +129,10 @@
 
 /* Expiration */
 int is_autofs4_dentry(struct dentry *);
-int autofs4_expire_run(struct super_block *, struct autofs_sb_info *,
-		      struct autofs_packet_expire *);
-int autofs4_expire_multi(struct super_block *, struct autofs_sb_info *, int *);
+int autofs4_expire_run(struct super_block *, struct vfsmount *,
+			struct autofs_sb_info *, struct autofs_packet_expire *);
+int autofs4_expire_multi(struct super_block *, struct vfsmount *,
+			struct autofs_sb_info *, int *);
 
 /* Operations structures */
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c
--- v2.3.99-pre6/linux/fs/autofs4/expire.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs4/expire.c	Mon May  8 11:17:47 2000
@@ -14,102 +14,39 @@
 #include "autofs_i.h"
 
 /*
- * Determine if a dentry tree is in use.  This is much the
- * same as the standard is_root_busy() function, except
- * that :-
- *  - the extra dentry reference in autofs dentries is not
- *    considered to be busy
- *  - mountpoints within the tree are not busy
- *  - it traverses across mountpoints
- * XXX doesn't consider children of covered dentries at mountpoints
+ * Determine if a subtree of the namespace is busy.
  */
-static int is_tree_busy(struct dentry *root)
+static int is_tree_busy(struct vfsmount *mnt)
 {
-	struct dentry *this_parent;
+	struct vfsmount *this_parent = mnt;
 	struct list_head *next;
 	int count;
 
-	root = root->d_mounts;
-
-	count = root->d_count;
-	this_parent = root;
-
-	DPRINTK(("is_tree_busy: starting at %.*s/%.*s, d_count=%d\n",
-		 root->d_covers->d_parent->d_name.len,
-		 root->d_covers->d_parent->d_name.name,
-		 root->d_name.len, root->d_name.name,
-		 root->d_count));
-
-	/* Ignore autofs's extra reference */
-	if (is_autofs4_dentry(root)) {
-		DPRINTK(("is_tree_busy: autofs\n"));
-		count--;
-	}
-
-	/* Mountpoints don't count (either mountee or mounter) */
-	if (d_mountpoint(root) ||
-	    root != root->d_covers) {
-		DPRINTK(("is_tree_busy: mountpoint\n"));
-		count--;
-	}
-
+	count = atomic_read(&mnt->mnt_count);
 repeat:
-	next = this_parent->d_mounts->d_subdirs.next;
+	next = this_parent->mnt_mounts.next;
 resume:
-	while (next != &this_parent->d_mounts->d_subdirs) {
-		int adj = 0;
+	while (next != &this_parent->mnt_mounts) {
 		struct list_head *tmp = next;
-		struct dentry *dentry = list_entry(tmp, struct dentry,
-						   d_child);
-
+		struct vfsmount *p = list_entry(tmp, struct vfsmount,
+						mnt_child);
 		next = tmp->next;
-
-		dentry = dentry->d_mounts;
-
-		DPRINTK(("is_tree_busy: considering %.*s/%.*s, d_count=%d, count=%d\n",
-			 this_parent->d_name.len,
-			 this_parent->d_name.name,
-			 dentry->d_covers->d_name.len, 
-			 dentry->d_covers->d_name.name,
-			 dentry->d_count, count));
-
 		/* Decrement count for unused children */
-		count += (dentry->d_count - 1);
-
-		/* 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++;
-		}
-
-		/* Ignore autofs's extra reference */
-		if (is_autofs4_dentry(dentry)) {
-			DPRINTK(("is_tree_busy: autofs\n"));
-			adj++;
-		}
-
-		count -= adj;
-
-		if (!list_empty(&dentry->d_mounts->d_subdirs)) {
-			this_parent = dentry->d_mounts;
+		count += atomic_read(&p->mnt_count) - 1;
+		if (!list_empty(&p->mnt_mounts)) {
+			this_parent = p;
 			goto repeat;
 		}
-
 		/* root is busy if any leaf is busy */
-		if (dentry->d_count != adj) {
-			DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n",
-				 dentry->d_count, adj));
+		if (atomic_read(&p->mnt_count) > 1)
 			return 1;
-		}
 	}
 	/*
 	 * All done at this level ... ascend and resume the search.
 	 */
-	if (this_parent != root) {
-		next = this_parent->d_covers->d_child.next; 
-		this_parent = this_parent->d_covers->d_parent;
+	if (this_parent != mnt) {
+		next = this_parent->mnt_child.next; 
+		this_parent = this_parent->mnt_parent;
 		goto resume;
 	}
 
@@ -124,6 +61,7 @@
  *  - it has been unused for exp_timeout time
  */
 static struct dentry *autofs4_expire(struct super_block *sb,
+				    struct vfsmount *mnt,
 				    struct autofs_sb_info *sbi,
 				    int do_now)
 {
@@ -131,6 +69,8 @@
 	unsigned long timeout;
 	struct dentry *root = sb->s_root;
 	struct list_head *tmp;
+	struct dentry *d;
+	struct vfsmount *p;
 
 	if (!sbi->exp_timeout || !root)
 		return NULL;
@@ -168,8 +108,14 @@
 			   attempts if expire fails the first time */
 			ino->last_used = now;
 		}
-
-		if (!is_tree_busy(dentry)) {
+		p = mntget(mnt);
+		d = dget(dentry);
+		while(d_mountpoint(d) && follow_down(&p, &d))
+			;
+
+		if (!is_tree_busy(p)) {
+			dput(d);
+			mntput(p);
 			DPRINTK(("autofs_expire: returning %p %.*s\n",
 				 dentry, dentry->d_name.len, dentry->d_name.name));
 			/* Start from here next time */
@@ -177,6 +123,8 @@
 			list_add(&root->d_subdirs, &dentry->d_child);
 			return dentry;
 		}
+		dput(d);
+		mntput(p);
 	}
 
 	return NULL;
@@ -184,6 +132,7 @@
 
 /* Perform an expiry operation */
 int autofs4_expire_run(struct super_block *sb,
+		      struct vfsmount *mnt,
 		      struct autofs_sb_info *sbi,
 		      struct autofs_packet_expire *pkt_p)
 {
@@ -195,7 +144,7 @@
 	pkt.hdr.proto_version = sbi->version;
 	pkt.hdr.type = autofs_ptype_expire;
 
-	if ((dentry = autofs4_expire(sb, sbi, 0)) == NULL)
+	if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
 		return -EAGAIN;
 
 	pkt.len = dentry->d_name.len;
@@ -210,7 +159,7 @@
 
 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
    more to be done */
-int autofs4_expire_multi(struct super_block *sb,
+int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
 			struct autofs_sb_info *sbi, int *arg)
 {
 	struct dentry *dentry;
@@ -220,7 +169,7 @@
 	if (arg && get_user(do_now, arg))
 		return -EFAULT;
 
-	if ((dentry = autofs4_expire(sb, sbi, do_now)) != NULL) {
+	if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
 		struct autofs_info *de_info = autofs4_dentry_ino(dentry);
 
 		/* This is synchronous because it makes the daemon a
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/autofs4/root.c linux/fs/autofs4/root.c
--- v2.3.99-pre6/linux/fs/autofs4/root.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/autofs4/root.c	Mon May  8 11:17:47 2000
@@ -120,7 +120,7 @@
 	struct dentry *top = dentry->d_sb->s_root;
 
 	for(; dentry != top; dentry = dentry->d_parent) {
-		struct autofs_info *ino = autofs4_dentry_ino(dentry->d_covers);
+		struct autofs_info *ino = autofs4_dentry_ino(dentry);
 
 		if (ino) {
 			update_atime(dentry->d_inode);
@@ -575,11 +575,12 @@
 
 	/* return a single thing to expire */
 	case AUTOFS_IOC_EXPIRE:
-		return autofs4_expire_run(inode->i_sb,sbi,
+		return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi,
 					 (struct autofs_packet_expire *)arg);
 	/* same as above, but can send multiple expires through pipe */
 	case AUTOFS_IOC_EXPIRE_MULTI:
-		return autofs4_expire_multi(inode->i_sb, sbi, (int *)arg);
+		return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi,
+					(int *)arg);
 
 	default:
 		return -ENOSYS;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/bfs/file.c linux/fs/bfs/file.c
--- v2.3.99-pre6/linux/fs/bfs/file.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/bfs/file.c	Mon May  8 13:51:01 2000
@@ -127,12 +127,12 @@
 	return err;
 }
 
-static int bfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int bfs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page, bfs_get_block);
 }
 
-static int bfs_readpage(struct dentry *dentry, struct page *page)
+static int bfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page, bfs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.99-pre6/linux/fs/binfmt_aout.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/binfmt_aout.c	Tue May  9 16:18:27 2000
@@ -363,20 +363,24 @@
 			goto beyond_if;
 		}
 
+		down(&current->mm->mmap_sem);
 		error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 			PROT_READ | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 			fd_offset);
+		up(&current->mm->mmap_sem);
 
 		if (error != N_TXTADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
 
+		down(&current->mm->mmap_sem);
  		error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
+		up(&current->mm->mmap_sem);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.99-pre6/linux/fs/binfmt_elf.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/binfmt_elf.c	Tue May  9 16:18:27 2000
@@ -261,12 +261,14 @@
 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
 	    	elf_type |= MAP_FIXED;
 
+	    down(&current->mm->mmap_sem);
 	    map_addr = do_mmap(interpreter,
 			    load_addr + ELF_PAGESTART(vaddr),
 			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
 			    elf_prot,
 			    elf_type,
 			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+	    up(&current->mm->mmap_sem);
 	    if (map_addr > -1024UL) /* Real error */
 		goto out_close;
 
@@ -612,11 +614,13 @@
 			elf_flags |= MAP_FIXED;
 		}
 
+		down(&current->mm->mmap_sem);
 		error = do_mmap(bprm->file, ELF_PAGESTART(load_bias + vaddr),
 		                (elf_ppnt->p_filesz +
 		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
 		                elf_prot, elf_flags, (elf_ppnt->p_offset -
 		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+		up(&current->mm->mmap_sem);
 
 		if (!load_addr_set) {
 			load_addr_set = 1;
@@ -726,8 +730,10 @@
 		   Since we do not have the power to recompile these, we
 		   emulate the SVr4 behavior.  Sigh.  */
 		/* N.B. Shouldn't the size here be PAGE_SIZE?? */
+		down(&current->mm->mmap_sem);
 		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, 0);
+		up(&current->mm->mmap_sem);
 	}
 
 #ifdef ELF_PLAT_INIT
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.99-pre6/linux/fs/buffer.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/buffer.c	Thu May 11 00:17:56 2000
@@ -789,7 +789,7 @@
 	/*
 	 * Run the hooks that have to be done when a page I/O has completed.
 	 */
-	if (test_and_clear_bit(PG_decr_after, &page->flags))
+	if (PageTestandClearDecrAfter(page))
 		atomic_dec(&nr_async_pages);
 
 	UnlockPage(page);
@@ -1578,7 +1578,6 @@
 		nr++;
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
-	++current->maj_flt;
 	if (nr) {
 		if (Page_Uptodate(page))
 			BUG();
@@ -1958,7 +1957,7 @@
 
 	if (!PageLocked(page))
 		panic("brw_page: page not locked for I/O");
-//	clear_bit(PG_error, &page->flags);
+//	ClearPageError(page);
 	/*
 	 * We pretty much rely on the page lock for this, because
 	 * create_page_buffers() might sleep.
@@ -2002,8 +2001,6 @@
 		}
 		bh = bh->b_this_page;
 	} while (bh != head);
-	if (rw == READ)
-		++current->maj_flt;
 	if ((rw == READ) && nr) {
 		if (Page_Uptodate(page))
 			BUG();
@@ -2115,6 +2112,29 @@
 }
 
 /*
+ * Sync all the buffers on one page..
+ *
+ * If we have old buffers that are locked, we'll
+ * wait on them, but we won't wait on the new ones
+ * we're writing out now.
+ *
+ * This all is required so that we can free up memory
+ * later.
+ */
+static void sync_page_buffers(struct buffer_head *bh)
+{
+	struct buffer_head * tmp;
+
+	tmp = bh;
+	do {
+		struct buffer_head *p = tmp;
+		tmp = tmp->b_this_page;
+		if (buffer_dirty(p) && !buffer_locked(p))
+			ll_rw_block(WRITE, 1, &p);
+	} while (tmp != bh);
+}
+
+/*
  * Can the buffer be thrown out?
  */
 #define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
@@ -2133,16 +2153,15 @@
  */
 int try_to_free_buffers(struct page * page)
 {
-	struct buffer_head * tmp, * p, * bh = page->buffers;
+	struct buffer_head * tmp, * bh = page->buffers;
 	int index = BUFSIZE_INDEX(bh->b_size);
-	int ret;
 
 	spin_lock(&lru_list_lock);
 	write_lock(&hash_table_lock);
 	spin_lock(&free_list[index].lock);
 	tmp = bh;
 	do {
-		p = tmp;
+		struct buffer_head *p = tmp;
 
 		tmp = tmp->b_this_page;
 		if (buffer_busy(p))
@@ -2172,19 +2191,18 @@
 	/* And free the page */
 	page->buffers = NULL;
 	__free_page(page);
-	ret = 1;
-out:
 	spin_unlock(&free_list[index].lock);
 	write_unlock(&hash_table_lock);
 	spin_unlock(&lru_list_lock);
-	return ret;
+	return 1;
 
 busy_buffer_page:
 	/* Uhhuh, start writeback so that we don't end up with all dirty pages */
-	if (buffer_dirty(p))
-		wakeup_bdflush(0);
-	ret = 0;
-	goto out;
+	spin_unlock(&free_list[index].lock);
+	write_unlock(&hash_table_lock);
+	spin_unlock(&lru_list_lock);	
+	sync_page_buffers(bh);
+	return 0;
 }
 
 /* ================== Debugging =================== */
@@ -2277,7 +2295,7 @@
 		    __get_free_pages(GFP_ATOMIC, order);
 	} while (hash_table == NULL && --order > 0);
 	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
-	       nr_hash, order, (1UL<<order) * PAGE_SIZE);
+	       nr_hash, order, (PAGE_SIZE << order));
 
 	if (!hash_table)
 		panic("Failed to allocate buffer hash table\n");
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/coda/pioctl.c linux/fs/coda/pioctl.c
--- v2.3.99-pre6/linux/fs/coda/pioctl.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/coda/pioctl.c	Mon May  8 11:17:47 2000
@@ -73,7 +73,7 @@
 static int coda_pioctl(struct inode * inode, struct file * filp, 
 		       unsigned int cmd, unsigned long user_data)
 {
-        struct dentry *target_de;
+	struct nameidata nd;
         int error;
 	struct PioctlData data;
         struct inode *target_inode = NULL;
@@ -92,16 +92,16 @@
 	CDEBUG(D_PIOCTL, "namei, data.follow = %d\n", 
 	       data.follow);
         if ( data.follow ) {
-                target_de = namei(data.path);
+                error = user_path_walk(data.path, &nd);
 	} else {
-	        target_de = lnamei(data.path);
+	        error = user_path_walk_link(data.path, &nd);
 	}
 		
-	if ( IS_ERR(target_de) ) {
+	if ( error ) {
                 CDEBUG(D_PIOCTL, "error: lookup fails.\n");
-		return PTR_ERR(target_de);
+		return error;
         } else {
-	        target_inode = target_de->d_inode;
+	        target_inode = nd.dentry->d_inode;
 	}
 	
 	CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%d\n",
@@ -109,8 +109,7 @@
 
 	/* return if it is not a Coda inode */
 	if ( target_inode->i_sb != inode->i_sb ) {
-  	        if ( target_de )
-		        dput(target_de);
+		path_release(&nd);
 	        return  -EINVAL;
 	}
 
@@ -121,9 +120,8 @@
 
         CDEBUG(D_PIOCTL, "ioctl on inode %ld\n", target_inode->i_ino);
 	CDEBUG(D_DOWNCALL, "dput on ino: %ld, icount %d, dcount %d\n", target_inode->i_ino, 
-	       target_inode->i_count, target_de->d_count);
-        if ( target_de ) 
-	        dput(target_de);
+	       target_inode->i_count, nd.dentry->d_count);
+	path_release(&nd);
         return error;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/coda/psdev.c linux/fs/coda/psdev.c
--- v2.3.99-pre6/linux/fs/coda/psdev.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/coda/psdev.c	Wed May 10 16:56:43 2000
@@ -35,6 +35,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/smp_lock.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -144,7 +145,9 @@
 		        return -EFAULT;
 
 		/* what downcall errors does Venus handle ? */
+		lock_kernel();
 		error = coda_downcall(hdr.opcode, dcbuf, sb);
+		unlock_kernel();
 
 		if ( error) {
 		        printk("psdev_write: coda_downcall error: %d\n", 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/coda/symlink.c linux/fs/coda/symlink.c
--- v2.3.99-pre6/linux/fs/coda/symlink.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/coda/symlink.c	Mon May  8 14:22:36 2000
@@ -22,9 +22,9 @@
 #include <linux/coda_cache.h>
 #include <linux/coda_proc.h>
 
-static int coda_symlink_filler(struct dentry *dentry, struct page *page)
+static int coda_symlink_filler(struct file *file, struct page *page)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	int error;
 	struct coda_inode_info *cnp;
 	unsigned int len = PAGE_SIZE;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- v2.3.99-pre6/linux/fs/cramfs/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/cramfs/inode.c	Mon May  8 14:23:03 2000
@@ -303,9 +303,9 @@
 	return NULL;
 }
 
-static int cramfs_readpage(struct dentry *dentry, struct page * page)
+static int cramfs_readpage(struct file *file, struct page * page)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	u32 maxblock, bytes_filled;
 
 	maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.99-pre6/linux/fs/dcache.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/dcache.c	Mon May  8 16:28:01 2000
@@ -337,25 +337,27 @@
 	}
 }
 
+/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
+ 
 /**
- * is_root_busy - check if a root dentry could be freed
- * @root: Dentry to work down from
- *
- * Check whether a root dentry would be in use if all of its
- * child dentries were freed. This allows a non-destructive
- * test for unmounting a device.
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
  *
- * Return non zero if the root is still busy.
+ * Return true if the parent or its subdirectories contain
+ * a mount point
  */
  
-int is_root_busy(struct dentry *root)
+int have_submounts(struct dentry *parent)
 {
-	struct dentry *this_parent = root;
+	struct dentry *this_parent = parent;
 	struct list_head *next;
-	int count = root->d_count;
-
-	check_lock();
 
+	if (d_mountpoint(parent))
+		return 1;
 repeat:
 	next = this_parent->d_subdirs.next;
 resume:
@@ -363,48 +365,31 @@
 		struct list_head *tmp = next;
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
 		next = tmp->next;
-		/* Decrement count for unused children */
-		count += (dentry->d_count - 1);
+		/* Have we found a mount point ? */
+		if (d_mountpoint(dentry))
+			return 1;
 		if (!list_empty(&dentry->d_subdirs)) {
 			this_parent = dentry;
 			goto repeat;
 		}
-		/* root is busy if any leaf is busy */
-		if (dentry->d_count)
-			return 1;
 	}
 	/*
 	 * All done at this level ... ascend and resume the search.
 	 */
-	if (this_parent != root) {
+	if (this_parent != parent) {
 		next = this_parent->d_child.next; 
 		this_parent = this_parent->d_parent;
 		goto resume;
 	}
-	return (count > 1); /* remaining users? */
+	return 0; /* No mount points found in tree */
 }
 
-/*
- * Search for at least 1 mount point in the dentry's subdirs.
- * We descend to the next level whenever the d_subdirs
- * list is non-empty and continue searching.
- */
- 
-/**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
- *
- * Return true if the parent or its subdirectories contain
- * a mount point
- */
- 
-int have_submounts(struct dentry *parent)
+int d_active_refs(struct dentry *root)
 {
-	struct dentry *this_parent = parent;
+	struct dentry *this_parent = root;
 	struct list_head *next;
+	int count = root->d_count;
 
-	if (d_mountpoint(parent))
-		return 1;
 repeat:
 	next = this_parent->d_subdirs.next;
 resume:
@@ -412,9 +397,8 @@
 		struct list_head *tmp = next;
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
 		next = tmp->next;
-		/* Have we found a mount point ? */
-		if (d_mountpoint(dentry))
-			return 1;
+		/* Decrement count for unused children */
+		count += (dentry->d_count - 1);
 		if (!list_empty(&dentry->d_subdirs)) {
 			this_parent = dentry;
 			goto repeat;
@@ -423,12 +407,12 @@
 	/*
 	 * All done at this level ... ascend and resume the search.
 	 */
-	if (this_parent != parent) {
+	if (this_parent != root) {
 		next = this_parent->d_child.next; 
 		this_parent = this_parent->d_parent;
 		goto resume;
 	}
-	return 0; /* No mount points found in tree */
+	return count;
 }
 
 /*
@@ -511,7 +495,7 @@
  *  ...
  *   6 - base-level: try to shrink a bit.
  */
-int shrink_dcache_memory(int priority, unsigned int gfp_mask, zone_t * zone)
+int shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
 	int count = 0;
 	lock_kernel();
@@ -574,8 +558,7 @@
 	} else
 		INIT_LIST_HEAD(&dentry->d_child);
 		
-	dentry->d_mounts = dentry;
-	dentry->d_covers = dentry;
+	INIT_LIST_HEAD(&dentry->d_vfsmnt);
 	INIT_LIST_HEAD(&dentry->d_hash);
 	INIT_LIST_HEAD(&dentry->d_lru);
 	INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -895,6 +878,7 @@
 {
 	char * end = buffer+buflen;
 	char * retval;
+	int namelen;
 
 	*--end = '\0';
 	buflen--;
@@ -910,14 +894,18 @@
 
 	for (;;) {
 		struct dentry * parent;
-		int namelen;
 
-		if (dentry == root)
+		if (dentry == root && vfsmnt == rootmnt)
 			break;
-		dentry = dentry->d_covers;
+		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+			/* Global root? */
+			if (vfsmnt->mnt_parent == vfsmnt)
+				goto global_root;
+			dentry = vfsmnt->mnt_mountpoint;
+			vfsmnt = vfsmnt->mnt_parent;
+			continue;
+		}
 		parent = dentry->d_parent;
-		if (dentry == parent)
-			break;
 		namelen = dentry->d_name.len;
 		buflen -= namelen + 1;
 		if (buflen < 0)
@@ -929,6 +917,14 @@
 		dentry = parent;
 	}
 	return retval;
+global_root:
+	namelen = dentry->d_name.len;
+	buflen -= namelen;
+	if (buflen >= 0) {
+		end -= namelen;
+		memcpy(end, dentry->d_name.name, namelen);
+	}
+	return end;
 }
 
 /*
@@ -1100,10 +1096,11 @@
 			__get_free_pages(GFP_ATOMIC, order);
 	} while (dentry_hashtable == NULL && --order >= 0);
 
+	printk("Dentry-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+			nr_hash, order, (PAGE_SIZE << order));
+
 	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;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.3.99-pre6/linux/fs/devfs/base.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/devfs/base.c	Mon May  8 22:00:41 2000
@@ -443,6 +443,14 @@
 	       Don't kill existing block ops in <devfs_read_inode>.
 	       Work sponsored by SGI.
   v0.94
+    20000424   Richard Gooch <rgooch@atnf.csiro.au>
+	       Don't create missing directories in <devfs_find_handle>.
+	       Work sponsored by SGI.
+  v0.95
+    20000430   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added CONFIG_DEVFS_MOUNT.
+	       Work sponsored by SGI.
+  v0.96
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -477,7 +485,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.94 (20000415)"
+#define DEVFS_VERSION            "0.96 (20000430)"
 
 #ifndef DEVFS_NAME
 #  define DEVFS_NAME "devfs"
@@ -691,8 +699,11 @@
 #  endif
 #endif
 
-/* by default, we do not mount devfs on bootup */
+#ifdef CONFIG_DEVFS_MOUNT
+static unsigned int boot_options = OPTION_NONE;
+#else
 static unsigned int boot_options = OPTION_NOMOUNT;
+#endif
 
 /*  Forward function declarations  */
 static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
@@ -959,7 +970,7 @@
 	    ++name;
 	    --namelen;
 	}
-	entry = search_for_entry (dir, name, namelen, TRUE, FALSE, NULL,
+	entry = search_for_entry (dir, name, namelen, FALSE, FALSE, NULL,
 				  traverse_symlink);
 	if (entry != NULL) return entry;
     }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.3.99-pre6/linux/fs/devpts/root.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/devpts/root.c	Mon May  8 15:56:08 2000
@@ -62,7 +62,7 @@
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
-		while ( nr < sbi->max_ptys ) {
+		while ( nr - 2 < sbi->max_ptys ) {
 			int ptynr = nr - 2;
 			if ( sbi->inodes[ptynr] ) {
 				genptsname(numbuf, ptynr);
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/dquot.c linux/fs/dquot.c
--- v2.3.99-pre6/linux/fs/dquot.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/dquot.c	Mon May  8 11:17:47 2000
@@ -1544,15 +1544,15 @@
 	dev = NODEV;
 	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
 		mode_t mode;
-		struct dentry * dentry;
+		struct nameidata nd;
 
-		dentry = namei(special);
-		if (IS_ERR(dentry))
+		ret = user_path_walk(special, &nd);
+		if (ret)
 			goto out;
 
-		dev = dentry->d_inode->i_rdev;
-		mode = dentry->d_inode->i_mode;
-		dput(dentry);
+		dev = nd.dentry->d_inode->i_rdev;
+		mode = nd.dentry->d_inode->i_mode;
+		path_release(&nd);
 
 		ret = -ENOTBLK;
 		if (!S_ISBLK(mode))
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/efs/inode.c linux/fs/efs/inode.c
--- v2.3.99-pre6/linux/fs/efs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/efs/inode.c	Mon May  8 11:11:29 2000
@@ -11,7 +11,7 @@
 #include <linux/efs_fs_sb.h>
 
 extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
-static int efs_readpage(struct dentry *dentry, struct page *page)
+static int efs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,efs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/efs/symlink.c linux/fs/efs/symlink.c
--- v2.3.99-pre6/linux/fs/efs/symlink.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/efs/symlink.c	Mon May  8 14:23:23 2000
@@ -10,11 +10,11 @@
 #include <linux/efs_fs.h>
 #include <linux/pagemap.h>
 
-static int efs_symlink_readpage(struct dentry *dentry, struct page *page)
+static int efs_symlink_readpage(struct file *file, struct page *page)
 {
 	char *link = (char*)kmap(page);
 	struct buffer_head * bh;
-	struct inode * inode = dentry->d_inode;
+	struct inode * inode = (struct inode*)page->mapping->host;
 	efs_block_t size = inode->i_size;
 	int err;
   
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/exec.c linux/fs/exec.c
--- v2.3.99-pre6/linux/fs/exec.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/exec.c	Tue May  9 16:18:27 2000
@@ -322,8 +322,9 @@
 	int err = 0;
 
 	lock_kernel();
-	if (walk_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		err = walk_name(name, &nd);
+	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		err = path_walk(name, &nd);
+	unlock_kernel();
 	file = ERR_PTR(err);
 	if (!err) {
 		file = ERR_PTR(-EACCES);
@@ -331,14 +332,14 @@
 			int err = permission(nd.dentry->d_inode, MAY_EXEC);
 			file = ERR_PTR(err);
 			if (!err) {
+				lock_kernel();
 				file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
-out:
 				unlock_kernel();
+out:
 				return file;
 			}
 		}
-		dput(nd.dentry);
-		mntput(nd.mnt);
+		path_release(&nd);
 	}
 	goto out;
 }
@@ -378,8 +379,10 @@
 		struct mm_struct *active_mm = current->active_mm;
 
 		init_new_context(current, mm);
+		task_lock(current);
 		current->mm = mm;
 		current->active_mm = mm;
+		task_unlock(current);
 		activate_mm(active_mm, mm);
 		mm_release();
 		if (old_mm) {
@@ -412,7 +415,9 @@
 	spin_lock_init(&newsig->siglock);
 	atomic_set(&newsig->count, 1);
 	memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
+	spin_lock_irq(&current->sigmask_lock);
 	current->sig = newsig;
+	spin_unlock_irq(&current->sigmask_lock);
 	return 0;
 }
 	
@@ -465,7 +470,6 @@
 	/*
 	 * Make sure we have a private signal table
 	 */
-	task_lock(current);
 	oldsig = current->sig;
 	retval = make_private_signals();
 	if (retval) goto flush_failed;
@@ -504,16 +508,16 @@
 			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
-	task_unlock(current);
 
 	return 0;
 
 mmap_failed:
+flush_failed:
+	spin_lock_irq(&current->sigmask_lock);
 	if (current->sig != oldsig)
 		kfree(current->sig);
-flush_failed:
 	current->sig = oldsig;
-	task_unlock(current);
+	spin_unlock_irq(&current->sigmask_lock);
 	return retval;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.99-pre6/linux/fs/ext2/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/ext2/inode.c	Mon May  8 13:51:01 2000
@@ -620,11 +620,11 @@
 	return NULL;
 }
 
-static int ext2_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int ext2_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,ext2_get_block);
 }
-static int ext2_readpage(struct dentry *dentry, struct page *page)
+static int ext2_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,ext2_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.3.99-pre6/linux/fs/fat/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/fat/inode.c	Mon May  8 13:51:01 2000
@@ -729,11 +729,11 @@
 	return 0;
 }
 
-static int fat_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int fat_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,fat_get_block);
 }
-static int fat_readpage(struct dentry *dentry, struct page *page)
+static int fat_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,fat_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/file_table.c linux/fs/file_table.c
--- v2.3.99-pre6/linux/fs/file_table.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/file_table.c	Mon May  8 11:17:47 2000
@@ -131,9 +131,9 @@
 	filp->f_vfsmnt = NULL;
 	if (filp->f_mode & FMODE_WRITE)
 		put_write_access(inode);
+	dput(dentry);
 	if (mnt)
 		mntput(mnt);
-	dput(dentry);
 }
 
 void _fput(struct file *file)
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.3.99-pre6/linux/fs/hfs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/hfs/inode.c	Mon May  8 13:51:01 2000
@@ -217,11 +217,11 @@
 	return __hfs_notify_change(dentry, attr, HFS_HDR);
 }
 
-static int hfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int hfs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,hfs_get_block);
 }
-static int hfs_readpage(struct dentry *dentry, struct page *page)
+static int hfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,hfs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.99-pre6/linux/fs/hpfs/file.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/hpfs/file.c	Mon May  8 13:51:01 2000
@@ -86,11 +86,11 @@
 	return 0;
 }
 
-static int hpfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int hpfs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,hpfs_get_block);
 }
-static int hpfs_readpage(struct dentry *dentry, struct page *page)
+static int hpfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,hpfs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.99-pre6/linux/fs/hpfs/hpfs_fn.h	Tue Mar 14 19:10:40 2000
+++ linux/fs/hpfs/hpfs_fn.h	Mon May  8 11:11:29 2000
@@ -301,7 +301,7 @@
 int hpfs_symlink(struct inode *, struct dentry *, const char *);
 int hpfs_unlink(struct inode *, struct dentry *);
 int hpfs_rmdir(struct inode *, struct dentry *);
-int hpfs_symlink_readpage(struct dentry *, struct page *);
+int hpfs_symlink_readpage(struct file *, struct page *);
 int hpfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 
 /* super.c */
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.3.99-pre6/linux/fs/hpfs/namei.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/hpfs/namei.c	Mon May  8 14:24:10 2000
@@ -393,10 +393,10 @@
 	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
 }
 
-int hpfs_symlink_readpage(struct dentry *dentry, struct page *page)
+int hpfs_symlink_readpage(struct file *file, struct page *page)
 {
 	char *link = (char*)kmap(page);
-	struct inode *i = dentry->d_inode;
+	struct inode *i = (struct inode*)page->mapping->host;
 	struct fnode *fnode;
 	struct buffer_head *bh;
 	int err;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/inode.c linux/fs/inode.c
--- v2.3.99-pre6/linux/fs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/inode.c	Mon May  8 16:28:14 2000
@@ -450,7 +450,7 @@
 	dispose_list(freeable);
 }
 
-int shrink_icache_memory(int priority, int gfp_mask, zone_t *zone)
+int shrink_icache_memory(int priority, int gfp_mask)
 {
 	int count = 0;
 		
@@ -876,10 +876,11 @@
 			__get_free_pages(GFP_ATOMIC, order);
 	} while (inode_hashtable == NULL && --order >= 0);
 
+	printk("Inode-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+			nr_hash, order, (PAGE_SIZE << order));
+
 	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;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.3.99-pre6/linux/fs/isofs/dir.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/isofs/dir.c	Tue May  2 14:26:03 2000
@@ -133,12 +133,28 @@
 		       block, offset, filp->f_pos);
 	        printk("inode->i_size = %x\n",inode->i_size);
 #endif
+		/* Next directory_record on next CDROM sector */
+		if (offset >= bufsize) {
+#ifdef DEBUG
+			printk("offset >= bufsize\n");
+#endif
+			brelse(bh);
+			offset = 0;
+			block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
+			if (!block)
+				return 0;
+			bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
+			if (!bh)
+				return 0;
+			continue;
+		}
+
 		de = (struct iso_directory_record *) (bh->b_data + offset);
 		if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
 		de_len = *(unsigned char *) de;
 #ifdef DEBUG
-		printk("de_len = %ld\n", de_len);
+		printk("de_len = %d\n", de_len);
 #endif
 	    
 
@@ -146,16 +162,11 @@
 		   CDROM sector.  If we are at the end of the directory, we
 		   kick out of the while loop. */
 
-		if ((de_len == 0) || (offset >= bufsize) ) {
+		if (de_len == 0) {
 			brelse(bh);
-			if (de_len == 0) {
-				filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
-					       + ISOFS_BLOCK_SIZE);
-				offset = 0;
-			} else {
-				offset -= bufsize;
-				filp->f_pos += offset;
-			}
+			filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+				       + ISOFS_BLOCK_SIZE);
+			offset = 0;
 
 			if (filp->f_pos >= inode->i_size)
 				return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.99-pre6/linux/fs/isofs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/isofs/inode.c	Mon May  8 11:11:29 2000
@@ -981,7 +981,7 @@
 	return 0;
 }
 
-static int isofs_readpage(struct dentry *dentry, struct page *page)
+static int isofs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,isofs_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.3.99-pre6/linux/fs/isofs/rock.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/isofs/rock.c	Mon May  8 14:24:44 2000
@@ -445,9 +445,9 @@
 /* readpage() for symlinks: reads symlink contents into the page and either
    makes it uptodate and returns 0 or returns error (-EIO) */
 
-static int rock_ridge_symlink_readpage(struct dentry *dentry, struct page *page)
+static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	char *link = (char*)kmap(page);
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.99-pre6/linux/fs/minix/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/minix/inode.c	Mon May  8 13:51:01 2000
@@ -1006,11 +1006,11 @@
 	return NULL;
 }
 
-static int minix_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int minix_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,minix_get_block);
 }
-static int minix_readpage(struct dentry *dentry, struct page *page)
+static int minix_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,minix_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/namei.c linux/fs/namei.c
--- v2.3.99-pre6/linux/fs/namei.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/namei.c	Mon May  8 15:27:12 2000
@@ -11,6 +11,8 @@
 /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
  * lookup logic.
  */
+/* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture.
+ */
 
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
@@ -27,11 +29,6 @@
 
 #include <asm/namei.h>
 
-/* This can be removed after the beta phase. */
-#define CACHE_SUPERVISE	/* debug the correctness of dcache entries */
-#undef DEBUG		/* some other debugging */
-
-
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /* [Feb-1997 T. Schoebel-Theuer]
@@ -85,6 +82,15 @@
  * [10-Sep-98 Alan Modra] Another symlink change.
  */
 
+/* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks:
+ *	inside the path - always follow.
+ *	in the last component in creation/removal/renaming - never follow.
+ *	if LOOKUP_FOLLOW passed - follow.
+ *	if the pathname has trailing slashes - follow.
+ *	otherwise - don't follow.
+ * (applied in that order).
+ */
+
 /* In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
  * kernel data space before using them..
@@ -142,24 +148,35 @@
 {
 	int mode = inode->i_mode;
 
-	if (inode->i_op && inode->i_op->permission)
-		return inode->i_op->permission(inode, mask);
-	else if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+	if (inode->i_op && inode->i_op->permission) {
+		int retval;
+		lock_kernel();
+		retval = inode->i_op->permission(inode, mask);
+		unlock_kernel();
+		return retval;
+	}
+
+	if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
 		 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
 		return -EROFS; /* Nobody gets write access to a read-only fs */
-	else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+
+	if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
 		return -EACCES; /* Nobody gets write access to an immutable file */
-	else if (current->fsuid == inode->i_uid)
+
+	if (current->fsuid == inode->i_uid)
 		mode >>= 6;
 	else if (in_group_p(inode->i_gid))
 		mode >>= 3;
+
 	if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
 		return 0;
+
 	/* read and search access */
 	if ((mask == S_IROTH) ||
 	    (S_ISDIR(mode)  && !(mask & ~(S_IROTH | S_IXOTH))))
 		if (capable(CAP_DAC_READ_SEARCH))
 			return 0;
+
 	return -EACCES;
 }
 
@@ -191,6 +208,14 @@
 	atomic_dec(&inode->i_writecount);
 }
 
+void path_release(struct nameidata *nd)
+{
+	lock_kernel();
+	dput(nd->dentry);
+	mntput(nd->mnt);
+	unlock_kernel();
+}
+
 /*
  * Internal lookup() using the new generic dcache.
  */
@@ -265,19 +290,54 @@
 	current->link_count--;
 	return err;
 loop:
-	dput(nd->dentry);
-	mntput(nd->mnt);
+	path_release(nd);
 	return -ELOOP;
 }
 
-static inline int follow_down(struct dentry ** dentry, struct vfsmount **mnt)
+static inline int __follow_up(struct vfsmount **mnt, struct dentry **base)
 {
-	struct dentry * parent = dget((*dentry)->d_mounts);
-	dput(*dentry);
-	*dentry = parent;
+	struct vfsmount *parent=(*mnt)->mnt_parent;
+	struct dentry *dentry;
+	if (parent == *mnt)
+		return 0;
+	mntget(parent);
+	dentry=dget((*mnt)->mnt_mountpoint);
+	dput(*base);
+	*base = dentry;
+	mntput(*mnt);
+	*mnt = parent;
 	return 1;
 }
 
+int follow_up(struct vfsmount **mnt, struct dentry **dentry)
+{
+	return __follow_up(mnt, dentry);
+}
+
+static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
+{
+	struct list_head *p = (*dentry)->d_vfsmnt.next;
+	while (p != &(*dentry)->d_vfsmnt) {
+		struct vfsmount *tmp;
+		tmp = list_entry(p, struct vfsmount, mnt_clash);
+		if (tmp->mnt_parent == *mnt) {
+			*mnt = mntget(tmp);
+			mntput(tmp->mnt_parent);
+			/* tmp holds the mountpoint, so... */
+			dput(*dentry);
+			*dentry = dget(tmp->mnt_root);
+			return 1;
+		}
+		p = p->next;
+	}
+	return 0;
+}
+
+int follow_down(struct vfsmount **mnt, struct dentry **dentry)
+{
+	return __follow_down(mnt,dentry);
+}
+
 /*
  * Name resolution.
  *
@@ -286,7 +346,7 @@
  *
  * We expect 'base' to be positive and a directory.
  */
-int walk_name(const char * name, struct nameidata *nd)
+int path_walk(const char * name, struct nameidata *nd)
 {
 	struct dentry *dentry;
 	struct inode *inode;
@@ -343,12 +403,20 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				if (nd->dentry != current->fs->root) {
-					dentry = dget(nd->dentry->d_covers->d_parent);
-					dput(nd->dentry);
-					nd->dentry = dentry;
-					inode = dentry->d_inode;
+				while (1) {
+					if (nd->dentry == current->fs->root &&
+					    nd->mnt == current->fs->rootmnt)
+						break;
+					if (nd->dentry != nd->mnt->mnt_root) {
+						dentry = dget(nd->dentry->d_parent);
+						dput(nd->dentry);
+						nd->dentry = dentry;
+						break;
+					}
+					if (!__follow_up(&nd->mnt, &nd->dentry))
+						break;
 				}
+				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
 				continue;
@@ -371,7 +439,7 @@
 				break;
 		}
 		/* Check mountpoints.. */
-		while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
 			;
 
 		err = -ENOENT;
@@ -415,12 +483,20 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				if (nd->dentry != current->fs->root) {
-					dentry = dget(nd->dentry->d_covers->d_parent);
-					dput(nd->dentry);
-					nd->dentry = dentry;
-					inode = dentry->d_inode;
+				while (1) {
+					if (nd->dentry == current->fs->root &&
+					    nd->mnt == current->fs->rootmnt)
+						break;
+					if (nd->dentry != nd->mnt->mnt_root) {
+						dentry = dget(nd->dentry->d_parent);
+						dput(nd->dentry);
+						nd->dentry = dentry;
+						break;
+					}
+					if (!__follow_up(&nd->mnt, &nd->dentry))
+						break;
 				}
+				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
 				goto return_base;
@@ -437,7 +513,7 @@
 			if (IS_ERR(dentry))
 				break;
 		}
-		while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
 			;
 		inode = dentry->d_inode;
 		if ((lookup_flags & LOOKUP_FOLLOW)
@@ -480,8 +556,7 @@
 		dput(dentry);
 		break;
 	}
-	dput(nd->dentry);
-	mntput(nd->mnt);
+	path_release(nd);
 return_err:
 	return err;
 }
@@ -491,7 +566,7 @@
 {
 	nd->mnt = mntget(current->fs->altrootmnt);
 	nd->dentry = dget(current->fs->altroot);
-	if (walk_name(name, nd))
+	if (path_walk(name, nd))
 		return 0;
 
 	if (!nd->dentry->d_inode) {
@@ -500,18 +575,16 @@
 		nd_root.flags = nd->flags;
 		nd_root.mnt = mntget(current->fs->rootmnt);
 		nd_root.dentry = dget(current->fs->root);
-		if (walk_name(name, &nd_root))
+		if (path_walk(name, &nd_root))
 			return 1;
 		if (nd_root.dentry->d_inode) {
-			dput(nd->dentry);
-			mntput(nd->mnt);
+			path_release(nd);
 			nd->dentry = nd_root.dentry;
 			nd->mnt = nd_root.mnt;
 			nd->last = nd_root.last;
 			return 1;
 		}
-		dput(nd_root.dentry);
-		mntput(nd_root.mnt);
+		path_release(&nd_root);
 	}
 	return 1;
 }
@@ -526,7 +599,7 @@
 		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) {
+		if (path_walk(emul,&nd) == 0) {
 			mnt = nd.mnt;
 			dentry = nd.dentry;
 		}
@@ -552,7 +625,7 @@
 	return 1;
 }
 
-int walk_init(const char *name,unsigned int flags,struct nameidata *nd)
+int path_init(const char *name,unsigned int flags,struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
@@ -563,25 +636,11 @@
 	return 1;
 }
 
-struct dentry * lookup_dentry(const char * name, unsigned int lookup_flags)
-{
-	struct nameidata nd;
-	int err = 0;
-
-	if (walk_init(name, lookup_flags, &nd))
-		err = walk_name(name, &nd);
-	if (!err) {
-		mntput(nd.mnt);
-		return nd.dentry;
-	}
-	return ERR_PTR(err);
-}
-
 /*
  * Restricted form of lookup. Doesn't follow links, single-component only,
  * needs parent already locked. Doesn't follow mounts.
  */
-static inline struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
+struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
 {
 	struct dentry * dentry;
 	struct inode *inode;
@@ -657,18 +716,22 @@
  * namei exists in two versions: namei/lnamei. The only difference is
  * that namei follows links, while lnamei does not.
  */
-struct dentry * __namei(const char *pathname, unsigned int lookup_flags)
+int __user_walk(const char *name, unsigned flags, struct nameidata *nd)
 {
-	char *name;
-	struct dentry *dentry;
+	char *tmp;
+	int err;
 
-	name = getname(pathname);
-	dentry = (struct dentry *) name;
-	if (!IS_ERR(name)) {
-		dentry = lookup_dentry(name,lookup_flags|LOOKUP_POSITIVE);
-		putname(name);
+	tmp = getname(name);
+	err = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		err = 0;
+		lock_kernel();
+		if (path_init(tmp, flags, nd))
+			err = path_walk(tmp, nd);
+		unlock_kernel();
+		putname(tmp);
 	}
-	return dentry;
+	return err;
 }
 
 /*
@@ -812,8 +875,8 @@
 
 	acc_mode = ACC_MODE(flag);
 	if (!(flag & O_CREAT)) {
-		if (walk_init(pathname, lookup_flags(flag), nd))
-			error = walk_name(pathname, nd);
+		if (path_init(pathname, lookup_flags(flag), nd))
+			error = path_walk(pathname, nd);
 		if (error)
 			return error;
 
@@ -821,8 +884,8 @@
 	} else {
 		struct dentry *dir;
 
-		if (walk_init(pathname, LOOKUP_PARENT, nd))
-			error = walk_name(pathname, nd);
+		if (path_init(pathname, LOOKUP_PARENT, nd))
+			error = path_walk(pathname, nd);
 		if (error)
 			return error;
 		/*
@@ -960,41 +1023,29 @@
 exit_dput:
 	dput(dentry);
 exit:
-	dput(nd->dentry);
-	mntput(nd->mnt);
+	path_release(nd);
 	return error;
 }
 
-static struct dentry *lookup_create(const char *name, int is_dir)
+static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
 {
-	struct nameidata nd;
 	struct dentry *dentry;
-	int err = 0;
-	if (walk_init(name, LOOKUP_PARENT, &nd))
-		err = walk_name(name, &nd);
-	dentry = ERR_PTR(err);
-	if (err)
-		goto out;
-	down(&nd.dentry->d_inode->i_sem);
+
+	down(&nd->dentry->d_inode->i_sem);
 	dentry = ERR_PTR(-EEXIST);
-	if (nd.last_type != LAST_NORM)
+	if (nd->last_type != LAST_NORM)
 		goto fail;
-	dentry = lookup_hash(&nd.last, 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)
+	if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
 		goto enoent;
-out_dput:
-	dput(nd.dentry);
-	mntput(nd.mnt);
-out:
 	return dentry;
 enoent:
 	dput(dentry);
 	dentry = ERR_PTR(-ENOENT);
 fail:
-	up(&nd.dentry->d_inode->i_sem);
-	goto out_dput;
+	return dentry;
 }
 
 int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -1022,33 +1073,12 @@
 	return error;
 }
 
-struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
-{
-	int error;
-	struct dentry *dir;
-	struct dentry *dentry, *retval;
-
-	dentry = lookup_create(filename, 0);
-	if (IS_ERR(dentry))
-		return dentry;
-
-	dir = dget(dentry->d_parent);
-
-	error = vfs_mknod(dir->d_inode, dentry, mode, dev);
-
-	retval = ERR_PTR(error);
-	if (!error)
-		retval = dget(dentry);
-	unlock_dir(dir);
-	dput(dentry);
-	return retval;
-}
-
 asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
 {
-	int error;
+	int error = 0;
 	char * tmp;
-	struct dentry * dentry, *dir;
+	struct dentry * dentry;
+	struct nameidata nd;
 
 	if (S_ISDIR(mode))
 		return -EPERM;
@@ -1057,26 +1087,30 @@
 		return PTR_ERR(tmp);
 
 	lock_kernel();
-	dentry = lookup_create(tmp, 0);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	if (path_init(tmp, LOOKUP_PARENT, &nd))
+		error = path_walk(tmp, &nd);
+	if (error)
 		goto out;
-	dir = dget(dentry->d_parent);
-	switch (mode & S_IFMT) {
-	case 0: case S_IFREG:
-		error = vfs_create(dir->d_inode, dentry, mode);
-		break;
-	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
-		error = vfs_mknod(dir->d_inode, dentry, mode, dev);
-		break;
-	case S_IFDIR:
-		error = -EPERM;
-		break;
-	default:
-		error = -EINVAL;
+	dentry = lookup_create(&nd, 0);
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		switch (mode & S_IFMT) {
+		case 0: case S_IFREG:
+			error = vfs_create(nd.dentry->d_inode,dentry,mode);
+			break;
+		case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
+			error = vfs_mknod(nd.dentry->d_inode,dentry,mode,dev);
+			break;
+		case S_IFDIR:
+			error = -EPERM;
+			break;
+		default:
+			error = -EINVAL;
+		}
+		dput(dentry);
 	}
-	unlock_dir(dir);
-	dput(dentry);
+	up(&nd.dentry->d_inode->i_sem);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	putname(tmp);
@@ -1108,27 +1142,32 @@
 
 asmlinkage long sys_mkdir(const char * pathname, int mode)
 {
-	int error;
+	int error = 0;
 	char * tmp;
 
 	tmp = getname(pathname);
 	error = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
-		struct dentry *dir;
 		struct dentry *dentry;
+		struct nameidata nd;
 
 		lock_kernel();
-		dentry = lookup_create(tmp, 1);
+		if (path_init(tmp, LOOKUP_PARENT, &nd))
+			error = path_walk(tmp, &nd);
+		if (error)
+			goto out;
+		dentry = lookup_create(&nd, 1);
 		error = PTR_ERR(dentry);
 		if (!IS_ERR(dentry)) {
-			dir = dget(dentry->d_parent);
-			error = vfs_mkdir(dir->d_inode, dentry, mode);
-			unlock_dir(dir);
+			error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
 			dput(dentry);
 		}
+		up(&nd.dentry->d_inode->i_sem);
+		path_release(&nd);
+out:
 		unlock_kernel();
+		putname(tmp);
 	}
-	putname(tmp);
 
 	return error;
 }
@@ -1197,8 +1236,8 @@
 		return PTR_ERR(name);
 	lock_kernel();
 
-	if (walk_init(name, LOOKUP_PARENT, &nd))
-		error = walk_name(name, &nd);
+	if (path_init(name, LOOKUP_PARENT, &nd))
+		error = path_walk(name, &nd);
 	if (error)
 		goto exit;
 
@@ -1219,8 +1258,7 @@
 	}
 	up(&nd.dentry->d_inode->i_sem);
 exit1:
-	dput(nd.dentry);
-	mntput(nd.mnt);
+	path_release(&nd);
 exit:
 	unlock_kernel();
 	putname(name);
@@ -1256,8 +1294,8 @@
 		return PTR_ERR(name);
 	lock_kernel();
 
-	if (walk_init(name, LOOKUP_PARENT, &nd))
-		error = walk_name(name, &nd);
+	if (path_init(name, LOOKUP_PARENT, &nd))
+		error = path_walk(name, &nd);
 	if (error)
 		goto exit;
 	error = -EISDIR;
@@ -1276,8 +1314,7 @@
 	}
 	up(&nd.dentry->d_inode->i_sem);
 exit1:
-	dput(nd.dentry);
-	mntput(nd.mnt);
+	path_release(&nd);
 exit:
 	unlock_kernel();
 	putname(name);
@@ -1313,7 +1350,7 @@
 
 asmlinkage long sys_symlink(const char * oldname, const char * newname)
 {
-	int error;
+	int error = 0;
 	char * from;
 	char * to;
 
@@ -1323,18 +1360,23 @@
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
-		struct dentry *dir;
 		struct dentry *dentry;
+		struct nameidata nd;
 
 		lock_kernel();
-		dentry = lookup_create(to, 0);
+		if (path_init(to, LOOKUP_PARENT, &nd))
+			error = path_walk(to, &nd);
+		if (error)
+			goto out;
+		dentry = lookup_create(&nd, 0);
 		error = PTR_ERR(dentry);
 		if (!IS_ERR(dentry)) {
-			dir = dget(dentry->d_parent);
-			error = vfs_symlink(dir->d_inode, dentry, from);
-			unlock_dir(dir);
+			error = vfs_symlink(nd.dentry->d_inode, dentry, from);
 			dput(dentry);
 		}
+		up(&nd.dentry->d_inode->i_sem);
+		path_release(&nd);
+out:
 		unlock_kernel();
 		putname(to);
 	}
@@ -1399,23 +1441,32 @@
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
-		struct dentry *old_dentry, *new_dentry, *dir;
+		struct dentry *new_dentry;
+		struct nameidata nd, old_nd;
 
 		lock_kernel();
-		old_dentry = lookup_dentry(from, LOOKUP_POSITIVE);
-		error = PTR_ERR(old_dentry);
-		if (IS_ERR(old_dentry))
+		error = 0;
+		if (path_init(from, LOOKUP_POSITIVE, &old_nd))
+			error = path_walk(from, &old_nd);
+		if (error)
 			goto exit;
-
-		new_dentry = lookup_create(to, 0);
+		if (path_init(to, LOOKUP_PARENT, &nd))
+			error = path_walk(to, &nd);
+		if (error)
+			goto out;
+		error = -EXDEV;
+		if (old_nd.mnt != nd.mnt)
+			goto out;
+		new_dentry = lookup_create(&nd, 0);
 		error = PTR_ERR(new_dentry);
 		if (!IS_ERR(new_dentry)) {
-			dir = dget(new_dentry->d_parent);
-			error = vfs_link(old_dentry, dir->d_inode, new_dentry);
-			unlock_dir(dir);
+			error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
 			dput(new_dentry);
 		}
-		dput(old_dentry);
+		up(&nd.dentry->d_inode->i_sem);
+		path_release(&nd);
+out:
+		path_release(&old_nd);
 exit:
 		unlock_kernel();
 		putname(to);
@@ -1577,14 +1628,14 @@
 	struct dentry * old_dentry, *new_dentry;
 	struct nameidata oldnd, newnd;
 
-	if (walk_init(oldname, LOOKUP_PARENT, &oldnd))
-		error = walk_name(oldname, &oldnd);
+	if (path_init(oldname, LOOKUP_PARENT, &oldnd))
+		error = path_walk(oldname, &oldnd);
 
 	if (error)
 		goto exit;
 
-	if (walk_init(newname, LOOKUP_PARENT, &newnd))
-		error = walk_name(newname, &newnd);
+	if (path_init(newname, LOOKUP_PARENT, &newnd))
+		error = path_walk(newname, &newnd);
 	if (error)
 		goto exit1;
 
@@ -1633,11 +1684,9 @@
 exit3:
 	double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem);
 exit2:
-	dput(newnd.dentry);
-	mntput(newnd.mnt);
+	path_release(&newnd);
 exit1:
-	dput(oldnd.dentry);
-	mntput(oldnd.mnt);
+	path_release(&oldnd);
 exit:
 	return error;
 }
@@ -1687,17 +1736,15 @@
 		goto fail;
 
 	if (*link == '/') {
-		dput(nd->dentry);
-		mntput(nd->mnt);
+		path_release(nd);
 		if (!walk_init_root(link, nd))
 			/* weird __emul_prefix() stuff did it */
 			return 0;
 	}
-	return walk_name(link, nd);
+	return path_walk(link, nd);
 
 fail:
-	dput(nd->dentry);
-	mntput(nd->mnt);
+	path_release(nd);
 	return PTR_ERR(link);
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ncpfs/symlink.c linux/fs/ncpfs/symlink.c
--- v2.3.99-pre6/linux/fs/ncpfs/symlink.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/ncpfs/symlink.c	Mon May  8 14:25:02 2000
@@ -43,9 +43,9 @@
 
 /* ----- read a symbolic link ------------------------------------------ */
 
-static int ncp_symlink_readpage(struct dentry *dentry, struct page *page)
+static int ncp_symlink_readpage(struct file *file, struct page *page)
 {
-	struct inode *inode=dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	int error, length, len, cnt;
 	char *link;
 	char *buf = (char*)kmap(page);
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.3.99-pre6/linux/fs/nfs/read.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/nfs/read.c	Mon May  8 11:11:29 2000
@@ -15,6 +15,7 @@
  * within the RPC code when root squashing is suspected.
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -471,8 +472,9 @@
  *  -	The server is congested.
  */
 int
-nfs_readpage(struct dentry *dentry, struct page *page)
+nfs_readpage(struct file *file, struct page *page)
 {
+	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	int		error;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.3.99-pre6/linux/fs/nfs/write.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/nfs/write.c	Mon May  8 13:51:01 2000
@@ -249,8 +249,9 @@
  * Write an mmapped page to the server.
  */
 int
-nfs_writepage(struct file *file, struct dentry * dentry, struct page *page)
+nfs_writepage(struct file *file, struct page *page)
 {
+	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset = PAGE_CACHE_SIZE;
@@ -1048,7 +1049,7 @@
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
                                                 status, (long long)inode->i_size);
 	if (status < 0)
-		clear_bit(PG_uptodate, &page->flags);
+		ClearPageUptodate(page);
 	return status;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.3.99-pre6/linux/fs/nfsd/export.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/nfsd/export.c	Mon May  8 11:17:47 2000
@@ -150,7 +150,7 @@
 	svc_client	*clp;
 	svc_export	*exp, *parent;
 	svc_export	**head;
-	struct dentry	*dentry = NULL;
+	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		i, err;
 	kdev_t		dev;
@@ -190,12 +190,13 @@
 	}
 
 	/* Look up the dentry */
-	err = -EINVAL;
-	dentry = lookup_dentry(nxp->ex_path, LOOKUP_POSITIVE);
-	if (IS_ERR(dentry))
+	err = 0;
+	if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd))
+		err = path_walk(nxp->ex_path, &nd);
+	if (err)
 		goto out_unlock;
 
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 	err = -EINVAL;
 	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
 		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
@@ -218,12 +219,12 @@
 		goto finish;
 	}
 
-	if ((parent = exp_child(clp, dev, dentry)) != NULL) {
+	if ((parent = exp_child(clp, dev, nd.dentry)) != NULL) {
 		dprintk("exp_export: export not valid (Rule 3).\n");
 		goto finish;
 	}
 	/* Is this is a sub-export, must be a proper subset of FS */
-	if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
+	if ((parent = exp_parent(clp, dev, nd.dentry)) != NULL) {
 		dprintk("exp_export: sub-export not valid (Rule 2).\n");
 		goto finish;
 	}
@@ -236,7 +237,8 @@
 	strcpy(exp->ex_path, nxp->ex_path);
 	exp->ex_client = clp;
 	exp->ex_parent = parent;
-	exp->ex_dentry = dentry;
+	exp->ex_dentry = nd.dentry;
+	exp->ex_mnt = nd.mnt;
 	exp->ex_flags = nxp->ex_flags;
 	exp->ex_dev = dev;
 	exp->ex_ino = ino;
@@ -270,7 +272,7 @@
 
 	/* Release the dentry */
 finish:
-	dput(dentry);
+	path_release(&nd);
 	goto out_unlock;
 }
 
@@ -284,6 +286,7 @@
 	svc_export	*exp;
 	svc_client	*clp;
 	struct dentry	*dentry;
+	struct vfsmount *mnt;
 	struct inode	*inode;
 	int		i;
 
@@ -296,10 +299,12 @@
 	}
 
 	dentry = unexp->ex_dentry;
+	mnt = unexp->ex_mnt;
 	inode = dentry->d_inode;
 	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
 		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
 	dput(dentry);
+	mntput(mnt);
 
 	kfree(unexp);
 }
@@ -376,38 +381,40 @@
 	   char *path, struct knfsd_fh *f, int maxsize)
 {
 	struct svc_export	*exp;
-	struct dentry		*dentry = NULL;
+	struct nameidata	nd;
 	struct inode		*inode;
 	struct svc_fh		fh;
 	int			err;
 
 	err = -EPERM;
 	if (path) {
-		if (!(dentry = lookup_dentry(path, 0))) {
+		err = 0;
+		if (path_init(path, LOOKUP_POSITIVE, &nd))
+			err = path_walk(path, &nd);
+		if (err) {
 			printk("nfsd: exp_rootfh path not found %s", path);
 			return -EPERM;
 		}
-		dev = dentry->d_inode->i_dev;
-		ino = dentry->d_inode->i_ino;
+		dev = nd.dentry->d_inode->i_dev;
+		ino = nd.dentry->d_inode->i_ino;
 	
 		dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
-		         path, dentry, clp->cl_ident, dev, (long) ino);
-		exp = exp_parent(clp, dev, dentry);
+		         path, nd.dentry, clp->cl_ident, dev, (long) ino);
+		exp = exp_parent(clp, dev, nd.dentry);
 	} else {
 		dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
 		         clp->cl_ident, dev, (long) ino);
-		if ((exp = exp_get(clp, dev, ino)))
-			if (!(dentry = dget(exp->ex_dentry))) {
-				printk("exp_rootfh: Aieee, NULL dentry\n");
-				return -EPERM;
-			}
+		if ((exp = exp_get(clp, dev, ino))) {
+			nd.mnt = mntget(exp->ex_mnt);
+			nd.dentry = dget(exp->ex_dentry);
+		}
 	}
 	if (!exp) {
 		dprintk("nfsd: exp_rootfh export not found.\n");
 		goto out;
 	}
 
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 	if (!inode) {
 		printk("exp_rootfh: Aieee, NULL d_inode\n");
 		goto out;
@@ -423,7 +430,7 @@
 	 * fh must be initialized before calling fh_compose
 	 */
 	fh_init(&fh, maxsize);
-	if (fh_compose(&fh, exp, dentry))
+	if (fh_compose(&fh, exp, nd.dentry))
 		err = -EINVAL;
 	else
 		err = 0;
@@ -432,7 +439,7 @@
 	return err;
 
 out:
-	dput(dentry);
+	path_release(&nd);
 	return err;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfsd/nfscache.c linux/fs/nfsd/nfscache.c
--- v2.3.99-pre6/linux/fs/nfsd/nfscache.c	Sun Jan 24 21:54:35 1999
+++ linux/fs/nfsd/nfscache.c	Wed May  3 01:45:19 2000
@@ -34,10 +34,10 @@
 	struct svc_cacherep *	prev;
 };
 
-static struct nfscache_head	hash_list[HASHSIZE];
+static struct nfscache_head *	hash_list;
 static struct svc_cacherep *	lru_head;
 static struct svc_cacherep *	lru_tail;
-static struct svc_cacherep	nfscache[CACHESIZE];
+static struct svc_cacherep *	nfscache;
 static int			cache_initialized = 0;
 static int			cache_disabled = 1;
 
@@ -48,11 +48,27 @@
 {
 	struct svc_cacherep	*rp;
 	struct nfscache_head	*rh;
-	int			i;
+	size_t			i;
 
 	if (cache_initialized)
 		return;
 
+	i = CACHESIZE * sizeof (struct svc_cacherep);
+	nfscache = kmalloc (i, GFP_KERNEL);
+	if (!nfscache) {
+		printk (KERN_ERR "nfsd: cannot allocate %d bytes for reply cache\n", i);
+		return;
+	}
+
+	i = HASHSIZE * sizeof (struct nfscache_head);
+	hash_list = kmalloc (i, GFP_KERNEL);
+	if (!hash_list) {
+		kfree (nfscache);
+		nfscache = NULL;
+		printk (KERN_ERR "nfsd: cannot allocate %d bytes for hash list\n", i);
+		return;
+	}
+
 	for (i = 0, rh = hash_list; i < HASHSIZE; i++, rh++)
 		rh->next = rh->prev = (struct svc_cacherep *) rh;
 
@@ -88,6 +104,11 @@
 
 	cache_initialized = 0;
 	cache_disabled = 1;
+
+	kfree (nfscache);
+	nfscache = NULL;
+	kfree (hash_list);
+	hash_list = NULL;
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.3.99-pre6/linux/fs/nfsd/nfsctl.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfsd/nfsctl.c	Mon May  8 15:54:17 2000
@@ -240,7 +240,7 @@
 	if (cmd<0 || cmd > CMD_MAX)
 		goto done;
 	err = -EFAULT;
-	argsize = sizes[cmd].argsize + sizeof(int); /* int for ca_version */
+	argsize = sizes[cmd].argsize + (int)&((struct nfsctl_arg *)0)->u;
 	respsize = sizes[cmd].respsize;	/* maximum */
 	if (!access_ok(VERIFY_READ, argp, argsize)
 	 || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) {
@@ -288,7 +288,7 @@
 		break;
 	case NFSCTL_GETFS:
 		err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
-		respsize = res->cr_getfs.fh_size+sizeof(int);
+		respsize = res->cr_getfs.fh_size+ (int)&((struct knfsd_fh*)0)->fh_base;
 		break;
 	default:
 		err = -EINVAL;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.99-pre6/linux/fs/nfsd/vfs.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/nfsd/vfs.c	Mon May  8 15:54:17 2000
@@ -92,7 +92,7 @@
 {
 	struct svc_export	*exp;
 	struct dentry		*dparent;
-	struct nameidata nd;
+	struct dentry		*dentry;
 	int			err;
 
 	dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
@@ -105,76 +105,72 @@
 	dparent = fhp->fh_dentry;
 	exp  = fhp->fh_export;
 
-#if 0
-	err = nfsd_permission(exp, dparent, MAY_EXEC);
-	if (err)
-		goto out;
-#endif
 	err = nfserr_acces;
 
 	/* Lookup the name, but don't follow links */
-	if (strcmp(name, "..")==0) {
+	if (strcmp(name, ".")==0) {
+		dentry = dget(dparent);
+	} else if (strcmp(name, "..")==0) {
 		/* checking mountpoint crossing is very different when stepping up */
 		if (dparent == exp->ex_dentry) {
 			if (!EX_CROSSMNT(exp))
-				nd.dentry = dget(dparent); /* .. == . just like at / */
+				dentry = dget(dparent); /* .. == . just like at / */
 			else
 			{
 				struct svc_export *exp2 = NULL;
 				struct dentry *dp;
-				nd.dentry = dparent->d_covers->d_parent;
-				for (dp=nd.dentry;
-				     exp2 == NULL && dp->d_covers->d_parent != dp;
-				     dp=dp->d_covers->d_parent)
+				struct vfsmount *mnt = mntget(exp->ex_mnt);
+				dentry = dget(dparent);
+				while(follow_up(&mnt, &dentry))
+					;
+				dp = dget(dentry->d_parent);
+				dput(dentry);
+				dentry = dp;
+				for ( ; exp2 == NULL && dp->d_parent != dp;
+				     dp=dp->d_parent)
 					exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-				if (exp2==NULL || nd.dentry->d_sb != exp2->ex_dentry->d_sb) {
-					nd.dentry = dget(dparent);
+				if (exp2==NULL) {
+					dput(dentry);
+					dentry = dget(dparent);
 				} else {
-					dget(nd.dentry);
 					exp = exp2;
 				}
+				mntput(mnt);
 			}
 		} else
-			nd.dentry = dget(dparent->d_parent);
+			dentry = dget(dparent->d_parent);
 	} else {
-		nd.mnt = NULL;
-		nd.dentry = dget(dparent);
-		nd.flags = 0;
-		err = walk_name(name, &nd);
-		if (err)
+		dentry = lookup_one(name, dparent);
+		err = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
 			goto out_nfserr;
 		/*
 		 * check if we have crossed a mount point ...
 		 */
-		if (nd.dentry->d_sb != dparent->d_sb) {
+		if (d_mountpoint(dentry)) {
 			struct svc_export *exp2 = NULL;
+			struct vfsmount *mnt = mntget(exp->ex_mnt);
+			struct dentry *mounts = dget(dentry);
+			while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts))
+				;
 			exp2 = exp_get(rqstp->rq_client,
-				       nd.dentry->d_inode->i_dev,
-				       nd.dentry->d_inode->i_ino);
-			if (exp2 && EX_CROSSMNT(exp2))
+				       mounts->d_inode->i_dev,
+				       mounts->d_inode->i_ino);
+			if (exp2 && EX_CROSSMNT(exp2)) {
 				/* successfully crossed mount point */
 				exp = exp2;
-			else if (nd.dentry->d_covers->d_sb == dparent->d_sb) {
-				/* stay in the original filesystem */
-				struct dentry *tdentry = dget(nd.dentry->d_covers);
-				dput(nd.dentry);
-				nd.dentry = tdentry;
-			} else {
-				/* This cannot possibly happen */
-				printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, nd.dentry->d_name.name);
-				dput(nd.dentry);
-				err = nfserr_acces;
-				goto out;
-
-			}
+				dput(dentry);
+				dentry = mounts;
+			} else
+				dput(mounts);
 		}
 	}
 	/*
 	 * Note: we compose the file handle now, but as the
 	 * dentry may be negative, it may need to be updated.
 	 */
-	err = fh_compose(resfh, exp, nd.dentry);
-	if (!err && !nd.dentry->d_inode)
+	err = fh_compose(resfh, exp, dentry);
+	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
 out:
 	return err;
@@ -201,11 +197,9 @@
 	int		size_change = 0;
 
 	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
-		accmode |= MAY_WRITE;
-	if (iap->ia_valid & ATTR_SIZE) {
-		accmode |= MAY_OWNER_OVERRIDE;
+		accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE;
+	if (iap->ia_valid & ATTR_SIZE)
 		ftype = S_IFREG;
-	}
 
 	/* Get inode */
 	err = fh_verify(rqstp, fhp, ftype, accmode);
@@ -964,7 +958,7 @@
 	 */
 	dchild = lookup_one(fname, dentry);
 	err = PTR_ERR(dchild);
-	if(IS_ERR(dchild))
+	if (IS_ERR(dchild))
 		goto out_nfserr;
 
 	err = fh_compose(resfhp, fhp->fh_export, dchild);
@@ -1051,7 +1045,7 @@
 	mm_segment_t	oldfs;
 	int		err;
 
-	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ);
+	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);
 	if (err)
 		goto out;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ntfs/Makefile linux/fs/ntfs/Makefile
--- v2.3.99-pre6/linux/fs/ntfs/Makefile	Tue Apr 11 15:09:22 2000
+++ linux/fs/ntfs/Makefile	Tue May  2 13:46:53 2000
@@ -3,7 +3,7 @@
 O_TARGET := ntfs.o
 O_OBJS   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
 M_OBJS   := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000410\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000502\"
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.3.99-pre6/linux/fs/ntfs/fs.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/ntfs/fs.c	Mon May  8 13:51:01 2000
@@ -2,10 +2,10 @@
  *  fs.c
  *  NTFS driver for Linux 2.3.x
  *
- *  Copyright (C) 2000, Anton Altaparmakov
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1996 Richard Russon
  *  Copyright (C) 1996-1997 Régis Duchesne
+ *  Copyright (C) 2000, Anton Altaparmakov
  */
 
 #ifdef HAVE_CONFIG_H
@@ -587,11 +587,11 @@
 #endif
 };
 
-static int ntfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int ntfs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,ntfs_get_block);
 }
-static int ntfs_readpage(struct dentry *dentry, struct page *page)
+static int ntfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,ntfs_get_block);
 }
@@ -937,7 +937,7 @@
 	return register_filesystem(&ntfs_fs_type);
 }
 
-static __exit void exit_ntfs_fs(void)
+static void __exit exit_ntfs_fs(void)
 {
 	SYSCTL(0);
 	ntfs_debug(DEBUG_OTHER, "unregistering %s\n",ntfs_fs_type.name);
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ntfs/struct.h linux/fs/ntfs/struct.h
--- v2.3.99-pre6/linux/fs/ntfs/struct.h	Fri Dec 19 15:24:21 1997
+++ linux/fs/ntfs/struct.h	Tue May  2 13:46:53 2000
@@ -3,6 +3,7 @@
  * Structure definitions
  *
  *  Copyright (C) 1997 Régis Duchesne
+ *  Copyright (C) 2000 Anton Altaparmakov
  */
 
 /* Necessary forward definition */
@@ -42,7 +43,10 @@
 	ntfs_u32 at_standard_information;
 	ntfs_u32 at_attribute_list;
 	ntfs_u32 at_file_name;
+	ntfs_u32 at_volume_version;
 	ntfs_u32 at_security_descriptor;
+	ntfs_u32 at_volume_name;
+	ntfs_u32 at_volume_information;
 	ntfs_u32 at_data;
 	ntfs_u32 at_index_root;
 	ntfs_u32 at_index_allocation;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ntfs/super.c linux/fs/ntfs/super.c
--- v2.3.99-pre6/linux/fs/ntfs/super.c	Tue Dec 14 01:27:24 1999
+++ linux/fs/ntfs/super.c	Tue May  2 13:46:53 2000
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1996-1997 Régis Duchesne
  *  Copyright (C) 1999 Steve Dodd
+ *  Copyright (C) 2000 Anton Altparmakov
  */
 
 #include "ntfstypes.h"
@@ -62,7 +63,10 @@
 	vol->at_standard_information=0x10;
 	vol->at_attribute_list=0x20;
 	vol->at_file_name=0x30;
+	vol->at_volume_version=0x40;
 	vol->at_security_descriptor=0x50;
+	vol->at_volume_name=0x60;
+	vol->at_volume_information=0x70;
 	vol->at_data=0x80;
 	vol->at_index_root=0x90;
 	vol->at_index_allocation=0xA0;
@@ -141,8 +145,18 @@
 	}else if(ntfs_ua_strncmp(name,"$FILE_NAME",64)==0){
 		vol->at_file_name=type;
 		check_type=0x30;
+	}else if(ntfs_ua_strncmp(name,"$VOLUME_VERSION",64)==0){
+		vol->at_volume_version=type;
+		check_type=0x40;
 	}else if(ntfs_ua_strncmp(name,"$SECURITY_DESCRIPTOR",64)==0){
-		vol->at_file_name=type;
+		vol->at_security_descriptor=type;
+		check_type=0x50;
+	}else if(ntfs_ua_strncmp(name,"$VOLUME_NAME",64)==0){
+		vol->at_volume_name=type;
+		check_type=0x60;
+	}else if(ntfs_ua_strncmp(name,"$VOLUME_INFORMATION",64)==0){
+		vol->at_volume_information=type;
+		check_type=0x70;
 	}else if(ntfs_ua_strncmp(name,"$DATA",64)==0){
 		vol->at_data=type;
 		check_type=0x80;
@@ -158,6 +172,7 @@
 	}else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64)==0 ||
 		 ntfs_ua_strncmp(name,"$REPARSE_POINT",64)==0){
 		vol->at_symlink=type;
+		check_type=0xC0;
 	}
 	if(check_type && check_type!=type){
 		ntfs_error("Unexpected type %x for %x\n",type,check_type);
@@ -196,10 +211,32 @@
 	return error;
 }
 
+/* ntfs_get_version will determine the NTFS version of the 
+   volume and will return the version in a BCD format, with
+   the MSB being the major version number and the LSB the
+   minor one. Otherwise return <0 on error. 
+   Example: version 3.1 will be returned as 0x0301.
+   This has the obvious limitation of not coping with version
+   numbers above 0x80 but that shouldn't be a problem... */
+int ntfs_get_version(ntfs_inode* volume)
+{
+	ntfs_attribute *volinfo;
+	int i;
+
+	volinfo = ntfs_find_attr(volume, volume->vol->at_volume_information, 0);
+	if (!volinfo) 
+		return -EINVAL;
+	if (!volinfo->resident) {
+		ntfs_error("Volume information attribute is not resident!\n");
+		return -EINVAL;
+	}
+	return ((ntfs_u8*)volinfo->d.data)[8] << 8 | ((ntfs_u8*)volinfo->d.data)[9];
+}
+
 int ntfs_load_special_files(ntfs_volume *vol)
 {
 	int error;
-	ntfs_inode upcase,attrdef;
+	ntfs_inode upcase, attrdef, volume;
 
 	vol->mft_ino=(ntfs_inode*)ntfs_calloc(3*sizeof(ntfs_inode));
 	error=ENOMEM;
@@ -232,6 +269,21 @@
 	error=ntfs_init_attrdef(&attrdef);
 	ntfs_clear_inode(&attrdef);
 	if(error)return error;
+
+	/* Check for NTFS version and if Win2k version (ie. 3.0+)
+	   do not allow write access since the driver write support
+	   is broken, especially for Win2k. */
+	ntfs_debug(DEBUG_BSD,"Going to load VOLUME\n");
+	error = ntfs_init_inode(&volume,vol,FILE_VOLUME);
+	if (error) return error;
+	if ((error = ntfs_get_version(&volume)) >= 0x0300) {
+		NTFS_SB(vol)->s_flags |= MS_RDONLY;
+		ntfs_error("Warning! NTFS volume version is Win2k+: Mounting read-only\n");
+	}
+	ntfs_clear_inode(&volume);
+	if (error < 0) return error;
+	ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8, error & 0xff);
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ntfs/util.c linux/fs/ntfs/util.c
--- v2.3.99-pre6/linux/fs/ntfs/util.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/ntfs/util.c	Tue May  2 13:46:53 2000
@@ -267,6 +267,8 @@
 			return -1;
 		if(b[i]<a[i])
 			return 1;
+		if (a[i] == 0)
+			return 0;
 	}
 	return 0;
 }
@@ -282,6 +284,8 @@
 			return -1;
 		if(b[i]<NTFS_GETU16(a+i))
 			return 1;
+		if (b[i] == 0)
+			return 0;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/open.c linux/fs/open.c
--- v2.3.99-pre6/linux/fs/open.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/open.c	Mon May  8 13:31:40 2000
@@ -13,22 +13,36 @@
 
 #include <asm/uaccess.h>
 
+int vfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	int retval = -ENODEV;
+
+	if (sb) {
+		retval = -ENOSYS;
+		if (sb->s_op && sb->s_op->statfs) {
+			memset(buf, 0, sizeof(struct statfs));
+			lock_kernel();
+			retval = sb->s_op->statfs(sb, buf);
+			unlock_kernel();
+		}
+	}
+	return retval;
+}
+
+
 asmlinkage long sys_statfs(const char * path, struct statfs * buf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
-	lock_kernel();
-	dentry = namei(path);
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
+	error = user_path_walk(path, &nd);
+	if (!error) {
 		struct statfs tmp;
-		error = vfs_statfs(dentry->d_inode->i_sb, &tmp);
+		error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 		if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
 			error = -EFAULT;
-		dput(dentry);
+		path_release(&nd);
 	}
-	unlock_kernel();
 	return error;
 }
 
@@ -42,11 +56,9 @@
 	file = fget(fd);
 	if (!file)
 		goto out;
-	lock_kernel();
 	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 	if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
 		error = -EFAULT;
-	unlock_kernel();
 	fput(file);
 out:
 	return error;
@@ -72,22 +84,18 @@
 
 static inline long do_sys_truncate(const char * path, loff_t length)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	struct inode * inode;
 	int error;
 
-	lock_kernel();
-
 	error = -EINVAL;
 	if (length < 0)	/* sorry, but loff_t says... */
 		goto out;
 
-	dentry = namei(path);
-
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	error = user_path_walk(path, &nd);
+	if (error)
 		goto out;
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 
 	error = -EACCES;
 	if (S_ISDIR(inode->i_mode))
@@ -105,6 +113,7 @@
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto dput_and_out;
 
+	lock_kernel();
 	error = get_write_access(inode);
 	if (error)
 		goto dput_and_out;
@@ -112,13 +121,14 @@
 	error = locks_verify_truncate(inode, NULL, length);
 	if (!error) {
 		DQUOT_INIT(inode);
-		error = do_truncate(dentry, length);
+		error = do_truncate(nd.dentry, length);
 	}
 	put_write_access(inode);
+	unlock_kernel();
+
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -149,8 +159,9 @@
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto out_putf;
-	error = locks_verify_truncate(inode, file, length);
+
 	lock_kernel();
+	error = locks_verify_truncate(inode, file, length);
 	if (!error)
 		error = do_truncate(dentry, length);
 	unlock_kernel();
@@ -194,17 +205,14 @@
 asmlinkage long sys_utime(char * filename, struct utimbuf * times)
 {
 	int error;
-	struct dentry * dentry;
+	struct nameidata nd;
 	struct inode * inode;
 	struct iattr newattrs;
 
-	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	error = user_path_walk(filename, &nd);
+	if (error)
 		goto out;
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
@@ -225,11 +233,10 @@
 		    (error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
-	error = notify_change(dentry, &newattrs);
+	error = notify_change(nd.dentry, &newattrs);
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -242,17 +249,15 @@
 asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
 {
 	int error;
-	struct dentry * dentry;
+	struct nameidata nd;
 	struct inode * inode;
 	struct iattr newattrs;
 
-	lock_kernel();
-	dentry = namei(filename);
+	error = user_path_walk(filename, &nd);
 
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	if (error)
 		goto out;
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
@@ -272,11 +277,10 @@
 		if ((error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
-	error = notify_change(dentry, &newattrs);
+	error = notify_change(nd.dentry, &newattrs);
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -287,7 +291,7 @@
  */
 asmlinkage long sys_access(const char * filename, int mode)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int old_fsuid, old_fsgid;
 	kernel_cap_t old_cap;
 	int res;
@@ -308,17 +312,14 @@
 	else
 		current->cap_effective = current->cap_permitted;
 
-	lock_kernel();		
-	dentry = namei(filename);
-	res = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		res = permission(dentry->d_inode, mode);
+	res = user_path_walk(filename, &nd);
+	if (!res) {
+		res = permission(nd.dentry->d_inode, mode);
 		/* SuS v2 requires we report a read only fs too */
-		if(!res && (mode & S_IWOTH) && IS_RDONLY(dentry->d_inode))
+		if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode))
 			res = -EROFS;
-		dput(dentry);
+		path_release(&nd);
 	}
-	unlock_kernel();
 
 	current->fsuid = old_fsuid;
 	current->fsgid = old_fsgid;
@@ -341,8 +342,8 @@
 		goto out;
 
 	error = 0;
-	if (walk_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
-		error = walk_name(name, &nd);
+	if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
+		error = path_walk(name, &nd);
 	putname(name);
 	if (error)
 		goto out;
@@ -354,8 +355,7 @@
 	set_fs_pwd(current->fs, nd.mnt, nd.dentry);
 
 dput_and_out:
-	dput(nd.dentry);
-	mntput(nd.mnt);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return error;
@@ -406,9 +406,9 @@
 	if (IS_ERR(name))
 		goto out;
 
-	walk_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+	path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
 		      LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
-	error = walk_name(name, &nd);	
+	error = path_walk(name, &nd);	
 	putname(name);
 	if (error)
 		goto out;
@@ -425,8 +425,7 @@
 	set_fs_altroot();
 	error = 0;
 dput_and_out:
-	dput(nd.dentry);
-	mntput(nd.mnt);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return error;
@@ -469,18 +468,15 @@
 
 asmlinkage long sys_chmod(const char * filename, mode_t mode)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	struct inode * inode;
 	int error;
 	struct iattr newattrs;
 
-	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	error = user_path_walk(filename, &nd);
+	if (error)
 		goto out;
-	inode = dentry->d_inode;
+	inode = nd.dentry->d_inode;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
@@ -494,12 +490,11 @@
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	error = notify_change(dentry, &newattrs);
+	error = notify_change(nd.dentry, &newattrs);
 
 dput_and_out:
-	dput(dentry);
+	path_release(&nd);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -565,35 +560,27 @@
 
 asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
-	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = chown_common(dentry, user, group);
-		dput(dentry);
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = chown_common(nd.dentry, user, group);
+		path_release(&nd);
 	}
-	unlock_kernel();
 	return error;
 }
 
 asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
-	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = chown_common(dentry, user, group);
-		dput(dentry);
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = chown_common(nd.dentry, user, group);
+		path_release(&nd);
 	}
-	unlock_kernel();
 	return error;
 }
 
@@ -604,13 +591,10 @@
 	int error = -EBADF;
 
 	file = fget(fd);
-	if (!file)
-		goto out;
-	lock_kernel();
-	error = chown_common(file->f_dentry, user, group);
-	unlock_kernel();
-	fput(file);
-out:
+	if (file) {
+		error = chown_common(file->f_dentry, user, group);
+		fput(file);
+	}
 	return error;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.99-pre6/linux/fs/pipe.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/pipe.c	Mon May  8 11:17:47 2000
@@ -9,6 +9,8 @@
 #include <linux/poll.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -463,6 +465,8 @@
 	return NULL;
 }
 
+static struct vfsmount *pipe_mnt = NULL;
+
 static struct inode * get_pipe_inode(void)
 {
 	struct inode *inode = get_empty_inode();
@@ -474,6 +478,7 @@
 		goto fail_iput;
 	PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
 	inode->i_fop = &rdwr_pipe_fops;
+	inode->i_sb = pipe_mnt->mnt_sb;
 
 	/*
 	 * Mark the inode dirty from the very beginning,
@@ -497,6 +502,9 @@
 
 int do_pipe(int *fd)
 {
+	struct qstr this;
+	char name[32];
+	struct dentry *dentry;
 	struct inode * inode;
 	struct file *f1, *f2;
 	int error;
@@ -526,9 +534,16 @@
 	j = error;
 
 	error = -ENOMEM;
-	f1->f_dentry = f2->f_dentry = dget(d_alloc_root(inode));
-	if (!f1->f_dentry)
+	sprintf(name, "%lu", inode->i_ino);
+	this.name = name;
+	this.len = strlen(name);
+	/* We don't care for hash - it will never be looked up */
+	dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
+	if (!dentry)
 		goto close_f12_inode_i_j;
+	d_instantiate(dentry, inode);
+	f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
+	f1->f_dentry = f2->f_dentry = dget(dentry);
 
 	/* read file */
 	f1->f_pos = f2->f_pos = 0;
@@ -565,3 +580,67 @@
 no_files:
 	return error;	
 }
+
+/*
+ * pipefs should _never_ be mounted by userland - too much of security hassle,
+ * no real gain from having the whole whorehouse mounted. So we don't need
+ * any operations on the root directory. However, we need a non-trivial
+ * d_name - pipe: will go nicely and kill the special-casing in procfs.
+ */
+static int pipefs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = PIPEFS_MAGIC;
+	buf->f_bsize = 1024;
+	buf->f_namelen = 255;
+	return 0;
+}
+
+static struct super_operations pipefs_ops = {
+	statfs:		pipefs_statfs,
+};
+
+static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
+{
+	struct inode *root = get_empty_inode();
+	if (!root)
+		return NULL;
+	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+	root->i_uid = root->i_gid = 0;
+	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_op	= &pipefs_ops;
+	sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
+	if (!sb->s_root) {
+		iput(root);
+		return NULL;
+	}
+	sb->s_root->d_sb = sb;
+	sb->s_root->d_parent = sb->s_root;
+	d_instantiate(sb->s_root, root);
+	return sb;
+}
+
+static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super,
+	FS_NOMOUNT|FS_SINGLE);
+
+static int __init init_pipe_fs(void)
+{
+	int err = register_filesystem(&pipe_fs_type);
+	if (!err) {
+		pipe_mnt = kern_mount(&pipe_fs_type);
+		err = PTR_ERR(pipe_mnt);
+		if (!IS_ERR(pipe_mnt))
+			err = 0;
+	}
+	return err;
+}
+
+static void __exit exit_pipe_fs(void)
+{
+	unregister_filesystem(&pipe_fs_type);
+	kern_umount(pipe_mnt);
+}
+
+module_init(init_pipe_fs)
+module_exit(exit_pipe_fs)
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.99-pre6/linux/fs/proc/array.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/proc/array.c	Tue May  9 16:18:27 2000
@@ -148,20 +148,25 @@
 {
 	int g;
 
+	read_lock(&tasklist_lock);
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
 		"Pid:\t%d\n"
 		"PPid:\t%d\n"
 		"TracerPid:\t%d\n"
 		"Uid:\t%d\t%d\t%d\t%d\n"
-		"Gid:\t%d\t%d\t%d\t%d\n"
-		"FDSize:\t%d\n"
-		"Groups:\t",
+		"Gid:\t%d\t%d\t%d\t%d\n",
 		get_task_state(p),
 		p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_opptr->pid : 0,
 		p->uid, p->euid, p->suid, p->fsuid,
-		p->gid, p->egid, p->sgid, p->fsgid,
+		p->gid, p->egid, p->sgid, p->fsgid);
+	read_unlock(&tasklist_lock);	
+	task_lock(p);
+	buffer += sprintf(buffer,
+		"FDSize:\t%d\n"
+		"Groups:\t",
 		p->files ? p->files->max_fds : 0);
+	task_unlock(p);
 
 	for (g = 0; g < p->ngroups; g++)
 		buffer += sprintf(buffer, "%d ", p->groups[g]);
@@ -264,20 +269,25 @@
 }
 
 
-/* task is locked, so we are safe here */
-
 int proc_pid_status(struct task_struct *task, char * buffer)
 {
 	char * orig = buffer;
-	struct mm_struct *mm = task->mm;
+	struct mm_struct *mm;
 #if defined(CONFIG_ARCH_S390)
 	int line,len;
 #endif
 
 	buffer = task_name(task, buffer);
 	buffer = task_state(task, buffer);
-	if (mm)
+	task_lock(task);
+	mm = task->mm;
+	if(mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
+	if (mm) {
 		buffer = task_mem(mm, buffer);
+		mmput(mm);
+	}
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
 #if defined(CONFIG_ARCH_S390)
@@ -287,20 +297,25 @@
 	return buffer - orig;
 }
 
-/* task is locked, so we are safe here */
-
 int proc_pid_stat(struct task_struct *task, char * buffer)
 {
-	struct mm_struct *mm = task->mm;
 	unsigned long vsize, eip, esp, wchan;
 	long priority, nice;
 	int tty_pgrp;
 	sigset_t sigign, sigcatch;
 	char state;
 	int res;
+	pid_t ppid;
+	int tty_nr;
+	struct mm_struct *mm;
 
 	state = *get_task_state(task);
 	vsize = eip = esp = 0;
+	task_lock(task);
+	mm = task->mm;
+	if(mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
 	if (mm) {
 		struct vm_area_struct *vma;
 		down(&mm->mmap_sem);
@@ -318,10 +333,13 @@
 
 	collect_sigign_sigcatch(task, &sigign, &sigcatch);
 
+	task_lock(task);
 	if (task->tty)
 		tty_pgrp = task->tty->pgrp;
 	else
 		tty_pgrp = -1;
+	tty_nr = task->tty ? kdev_t_to_nr(task->tty->device) : 0;
+	task_unlock(task);
 
 	/* scale priority and nice values from timeslices to -20..20 */
 	/* to make it look like a "normal" Unix priority/nice value  */
@@ -330,16 +348,19 @@
 	nice = task->priority;
 	nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
 
+	read_lock(&tasklist_lock);
+	ppid = task->p_opptr->pid;
+	read_unlock(&tasklist_lock);
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
 		task->pid,
 		task->comm,
 		state,
-		task->p_opptr->pid,
+		ppid,
 		task->pgrp,
 		task->session,
-	        task->tty ? kdev_t_to_nr(task->tty->device) : 0,
+	        tty_nr,
 		tty_pgrp,
 		task->flags,
 		task->min_flt,
@@ -376,6 +397,8 @@
 		task->cnswap,
 		task->exit_signal,
 		task->processor);
+	if(mm)
+		mmput(mm);
 	return res;
 }
 		
@@ -455,9 +478,14 @@
 
 int proc_pid_statm(struct task_struct *task, char * buffer)
 {
-	struct mm_struct *mm = task->mm;
+	struct mm_struct *mm;
 	int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
 
+	task_lock(task);
+	mm = task->mm;
+	if(mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
 	if (mm) {
 		struct vm_area_struct * vma;
 		down(&mm->mmap_sem);
@@ -482,6 +510,7 @@
 			vma = vma->vm_next;
 		}
 		up(&mm->mmap_sem);
+		mmput(mm);
 	}
 	return sprintf(buffer,"%d %d %d %d %d %d %d\n",
 		       size, resident, share, trs, lrs, drs, dt);
@@ -523,7 +552,7 @@
 ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf,
 			  size_t count, loff_t *ppos)
 {
-	struct mm_struct *mm = task->mm;
+	struct mm_struct *mm;
 	struct vm_area_struct * map, * next;
 	char * destptr = buf, * buffer;
 	loff_t lineno;
@@ -539,7 +568,14 @@
 	if (!buffer)
 		goto out;
 
-	if (!mm || count == 0)
+	if (count == 0)
+		goto getlen_out;
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
+	if (!mm)
 		goto getlen_out;
 
 	/* Check whether the mmaps could change if we sleep */
@@ -637,6 +673,7 @@
 
 	/* encode f_pos */
 	*ppos = (lineno << MAPS_LINE_SHIFT) + column;
+	mmput(mm);
 
 getlen_out:
 	retval = destptr - buf;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.99-pre6/linux/fs/proc/base.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/proc/base.c	Tue May  9 16:19:04 2000
@@ -40,12 +40,18 @@
 int proc_pid_cpu(struct task_struct*,char*);
 
 /* MOUNT_REWRITE: make all files have non-NULL ->f_vfsmnt (pipefs, sockfs) */
+/* Until then... */
+#define NULL_VFSMNT	/* remove as soon as pipefs and sockfs will be there */
+
 static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
 	if (inode->u.proc_i.file) {
-		if (inode->u.proc_i.file->f_vfsmnt) {
-			*mnt = mntget(inode->u.proc_i.file->f_vfsmnt);
-		}
+#ifdef NULL_VFSMNT
+		if (!inode->u.proc_i.file->f_vfsmnt)
+			mntget(*mnt);
+		else
+#endif
+		*mnt = mntget(inode->u.proc_i.file->f_vfsmnt);
 		*dentry = dget(inode->u.proc_i.file->f_dentry);
 		return 0;
 	}
@@ -59,9 +65,11 @@
 	int result = -ENOENT;
 	struct task_struct *task = inode->u.proc_i.task;
 
-	if (!task_lock(task))
-		return result;
+	task_lock(task);
 	mm = task->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
 	if (!mm)
 		goto out;
 	down(&mm->mmap_sem);
@@ -77,67 +85,81 @@
 		vma = vma->vm_next;
 	}
 	up(&mm->mmap_sem);
+	mmput(mm);
 out:
-	task_unlock(task);
 	return result;
 }
 
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
+	struct fs_struct *fs;
 	int result = -ENOENT;
-	if (task_lock(inode->u.proc_i.task)) {
-		struct fs_struct *fs = inode->u.proc_i.task->fs;
-		if (fs) {
-			*mnt = mntget(fs->pwdmnt);
-			*dentry = dget(fs->pwd);
-			result = 0;
-		}
-		task_unlock(inode->u.proc_i.task);
+	task_lock(inode->u.proc_i.task);
+	fs = inode->u.proc_i.task->fs;
+	if(fs)
+		atomic_inc(&fs->count);
+	task_unlock(inode->u.proc_i.task);
+	if (fs) {
+		*mnt = mntget(fs->pwdmnt);
+		*dentry = dget(fs->pwd);
+		result = 0;
+		put_fs_struct(fs);
 	}
 	return result;
 }
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
+	struct fs_struct *fs;
 	int result = -ENOENT;
-	if (task_lock(inode->u.proc_i.task)) {
-		struct fs_struct *fs = inode->u.proc_i.task->fs;
-		if (fs) {
-			*mnt = mntget(fs->rootmnt);
-			*dentry = dget(fs->root);
-			result = 0;
-		}
-		task_unlock(inode->u.proc_i.task);
+	task_lock(inode->u.proc_i.task);
+	fs = inode->u.proc_i.task->fs;
+	if(fs)
+		atomic_inc(&fs->count);
+	task_unlock(inode->u.proc_i.task);
+	if (fs) {
+		*mnt = mntget(fs->rootmnt);
+		*dentry = dget(fs->root);
+		result = 0;
+		put_fs_struct(fs);
 	}
 	return result;
 }
 
-/* task is locked and can't drop mm, so we are safe */
-
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
-	struct mm_struct *mm = task->mm;
+	struct mm_struct *mm;
 	int res = 0;
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
 	if (mm) {
 		int len = mm->env_end - mm->env_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->env_start, buffer, len, 0);
+		mmput(mm);
 	}
 	return res;
 }
 
-/* task is locked and can't drop mm, so we are safe */
-
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
 {
-	struct mm_struct *mm = task->mm;
+	struct mm_struct *mm;
 	int res = 0;
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
 	if (mm) {
 		int len = mm->arg_end - mm->arg_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+		mmput(mm);
 	}
 	return res;
 }
@@ -174,7 +196,6 @@
 static int proc_permission(struct inode *inode, int mask)
 {
 	struct dentry *de, *base, *root;
-	struct super_block *our_sb, *sb, *below;
 	struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
 
 	if (standard_permission(inode, mask) != 0)
@@ -187,14 +208,12 @@
 
 	de = root;
 	mnt = vfsmnt;
-	our_sb = base->d_inode->i_sb;
-	sb = de->d_inode->i_sb;
-	while (sb != our_sb) {
-		de = sb->s_root->d_covers;
-		below = de->d_inode->i_sb;
-		if (sb == below)
+
+	while (vfsmnt != our_vfsmnt) {
+		if (vfsmnt == vfsmnt->mnt_parent)
 			goto out;
-		sb = below;
+		de = vfsmnt->mnt_mountpoint;
+		vfsmnt = vfsmnt->mnt_parent;
 	}
 
 	if (!is_subdir(de, base))
@@ -216,10 +235,7 @@
 	struct task_struct *task = inode->u.proc_i.task;
 	ssize_t res;
 
-	if (!task_lock(task))
-		return -EIO;
 	res = proc_pid_read_maps(task, file, buf, count, ppos);
-	task_unlock(task);
 	return res;
 }
 
@@ -243,15 +259,8 @@
 	if (!(page = __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 
-	if (!task_lock(task)) {
-		free_page(page);
-		return -EIO;
-	}
-	
 	length = inode->u.proc_i.op.proc_read(task, (char*)page);
 
-	task_unlock(task);
-
 	if (length < 0) {
 		free_page(page);
 		return length;
@@ -368,10 +377,12 @@
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
+#ifdef NULL_VFSMNT
+	struct vfsmount *dummy = mntget(nd->mnt);
+#endif
 
 	/* We don't need a base pointer in the /proc filesystem */
-	dput(nd->dentry);
-	mntput(nd->mnt);
+	path_release(nd);
 
 	error = proc_permission(inode, MAY_EXEC);
 	if (error)
@@ -379,6 +390,9 @@
 
 	error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
 out:
+#ifdef NULL_VFSMNT
+	mntput(dummy);
+#endif
 	return error;
 }
 
@@ -421,18 +435,19 @@
 {
 	int error;
 	struct inode *inode = dentry->d_inode;
-	struct vfsmount *mnt;
+	struct dentry *de;
+	struct vfsmount *mnt = NULL;
 
 	error = proc_permission(inode, MAY_EXEC);
 	if (error)
 		goto out;
 
-	error = inode->u.proc_i.op.proc_get_link(inode, &dentry, &mnt);
+	error = inode->u.proc_i.op.proc_get_link(inode, &de, &mnt);
 	if (error)
 		goto out;
 
-	error = do_proc_readlink(dentry, mnt, buffer, buflen);
-	dput(dentry);
+	error = do_proc_readlink(de, mnt, buffer, buflen);
+	dput(de);
 	mntput(mnt);
 out:
 	return error;
@@ -496,6 +511,7 @@
 	unsigned int fd, pid, ino;
 	int retval;
 	char buf[NUMBUF];
+	struct files_struct * files;
 
 	retval = 0;
 	pid = p->pid;
@@ -512,12 +528,19 @@
 				goto out;
 			filp->f_pos++;
 		default:
+			task_lock(p);
+			files = p->files;
+			if (files)
+				atomic_inc(&files->count);
+			task_unlock(p);
+			if (!files)
+				goto out;
 			for (fd = filp->f_pos-2;
-			     p->p_pptr && p->files && fd < p->files->max_fds;
+			     fd < files->max_fds;
 			     fd++, filp->f_pos++) {
 				unsigned int i,j;
 
-				if (!fcheck_task(p, fd))
+				if (!fcheck_files(files, fd))
 					continue;
 
 				j = NUMBUF;
@@ -531,8 +554,8 @@
 				ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
 				if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
 					break;
-
 			}
+			put_files_struct(files);
 	}
 out:
 	return retval;
@@ -688,16 +711,20 @@
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd);
 	if (!inode)
 		goto out;
-	/* FIXME */
+	task_lock(task);
 	files = task->files;
-	if (!files)	/* can we ever get here if that's the case? */
+	if (files)
+		atomic_inc(&files->count);
+	task_unlock(task);
+	if (!files)
 		goto out_unlock;
 	read_lock(&files->file_lock);
-	file = inode->u.proc_i.file = fcheck_task(task, fd);
+	file = inode->u.proc_i.file = fcheck_files(files, fd);
 	if (!file)
 		goto out_unlock2;
 	get_file(file);
 	read_unlock(&files->file_lock);
+	put_files_struct(files);
 	inode->i_op = &proc_pid_link_inode_operations;
 	inode->i_size = 64;
 	inode->i_mode = S_IFLNK;
@@ -711,6 +738,7 @@
 	return NULL;
 
 out_unlock2:
+	put_files_struct(files);
 	read_unlock(&files->file_lock);
 out_unlock:
 	iput(inode);
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.3.99-pre6/linux/fs/proc/generic.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/proc/generic.c	Mon May  8 11:17:47 2000
@@ -373,36 +373,30 @@
 static void proc_kill_inodes(struct proc_dir_entry *de)
 {
 	struct list_head *p;
-	struct super_block *sb;
+	struct super_block *sb = proc_mnt->mnt_sb;
 
 	/*
-	 * Actually it's a partial revoke(). We have to go through all
-	 * copies of procfs. proc_super_blocks is protected by the big
-	 * lock for the time being.
+	 * Actually it's a partial revoke().
 	 */
-	for (sb = proc_super_blocks;
-	     sb;
-	     sb = (struct super_block*)sb->u.generic_sbp) {
-		file_list_lock();
-		for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
-			struct file * filp = list_entry(p, struct file, f_list);
-			struct dentry * dentry;
-			struct inode * inode;
+	file_list_lock();
+	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+		struct file * filp = list_entry(p, struct file, f_list);
+		struct dentry * dentry;
+		struct inode * inode;
 
-			dentry = filp->f_dentry;
-			if (!dentry)
-				continue;
-			if (dentry->d_op != &proc_dentry_operations)
-				continue;
-			inode = dentry->d_inode;
-			if (!inode)
-				continue;
-			if (inode->u.generic_ip != de)
-				continue;
-			filp->f_op = NULL;
-		}
-		file_list_unlock();
+		dentry = filp->f_dentry;
+		if (!dentry)
+			continue;
+		if (dentry->d_op != &proc_dentry_operations)
+			continue;
+		inode = dentry->d_inode;
+		if (!inode)
+			continue;
+		if (inode->u.generic_ip != de)
+			continue;
+		filp->f_op = NULL;
 	}
+	file_list_unlock();
 }
 
 struct proc_dir_entry *proc_symlink(const char *name,
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.3.99-pre6/linux/fs/proc/inode.c	Fri Mar 10 16:40:48 2000
+++ linux/fs/proc/inode.c	Mon May  8 11:17:47 2000
@@ -82,18 +82,7 @@
 	}
 }
 
-struct super_block *proc_super_blocks = NULL;
-
-static void proc_put_super(struct super_block *sb)
-{
-	struct super_block **p = &proc_super_blocks;
-	while (*p != sb) {
-		if (!*p)	/* should never happen */
-			return;
-		p = (struct super_block **)&(*p)->u.generic_sbp;
-	}
-	*p = (struct super_block *)(*p)->u.generic_sbp;
-}
+struct vfsmount *proc_mnt;
 
 static void proc_read_inode(struct inode * inode)
 {
@@ -115,7 +104,6 @@
 	read_inode:	proc_read_inode,
 	put_inode:	proc_put_inode,
 	delete_inode:	proc_delete_inode,
-	put_super:	proc_put_super,
 	statfs:		proc_statfs,
 };
 
@@ -222,8 +210,6 @@
 	if (!s->s_root)
 		goto out_no_root;
 	parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
-	s->u.generic_sbp = (void*) proc_super_blocks;
-	proc_super_blocks = s;
 	return s;
 
 out_no_root:
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- v2.3.99-pre6/linux/fs/proc/procfs_syms.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/proc/procfs_syms.c	Mon May  8 11:17:47 2000
@@ -20,16 +20,24 @@
 EXPORT_SYMBOL(proc_bus);
 EXPORT_SYMBOL(proc_root_driver);
 
-static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, 0);
+static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
 
 static int __init init_proc_fs(void)
 {
-	return register_filesystem(&proc_fs_type);
+	int err = register_filesystem(&proc_fs_type);
+	if (!err) {
+		proc_mnt = kern_mount(&proc_fs_type);
+		err = PTR_ERR(proc_mnt);
+		if (!IS_ERR(proc_mnt))
+			err = 0;
+	}
+	return err;
 }
 
 static void __exit exit_proc_fs(void)
 {
 	unregister_filesystem(&proc_fs_type);
+	kern_umount(proc_mnt);
 }
 
 module_init(init_proc_fs)
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.99-pre6/linux/fs/proc/root.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/proc/root.c	Thu Apr 27 15:43:15 2000
@@ -76,32 +76,12 @@
 
 static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
 {
-	struct task_struct *p;
-
 	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
-		extern unsigned long total_forks;
-		static int last_timestamp = 0;
+		int nlink = proc_root.nlink;
 
-		/*
-		 * this one can be a serious 'ps' performance problem if
-		 * there are many threads running - thus we do 'lazy'
-		 * link-recalculation - we change it only if the number
-		 * of threads has increased.
-		 */
-		if (total_forks != last_timestamp) {
-			int nlink = proc_root.nlink;
+		nlink += nr_threads;
 
-			read_lock(&tasklist_lock);
-			last_timestamp = total_forks;
-			for_each_task(p)
-				nlink++;
-			read_unlock(&tasklist_lock);
-			/*
-			 * subtract the # of idle threads which
-			 * do not show up in /proc:
-			 */
-			dir->i_nlink = nlink - smp_num_cpus;
-		}
+		dir->i_nlink = nlink;
 	}
 
 	if (!proc_lookup(dir, dentry))
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.3.99-pre6/linux/fs/qnx4/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/qnx4/inode.c	Mon May  8 13:51:01 2000
@@ -410,11 +410,11 @@
 	return;
 }
 
-static int qnx4_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int qnx4_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,qnx4_get_block);
 }
-static int qnx4_readpage(struct dentry *dentry, struct page *page)
+static int qnx4_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,qnx4_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ramfs/inode.c linux/fs/ramfs/inode.c
--- v2.3.99-pre6/linux/fs/ramfs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/ramfs/inode.c	Mon May  8 13:51:01 2000
@@ -62,7 +62,7 @@
  * Read a page. Again trivial. If it didn't already exist
  * in the page cache, it is zero-filled.
  */
-static int ramfs_readpage(struct dentry *dentry, struct page * page)
+static int ramfs_readpage(struct file *file, struct page * page)
 {
 	if (!Page_Uptodate(page)) {
 		memset((void *) page_address(page), 0, PAGE_CACHE_SIZE);
@@ -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 file *file, struct dentry * dentry, struct page *page)
+static int ramfs_writepage(struct file *file, struct page *page)
 {
 	SetPageDirty(page);
 	return 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.3.99-pre6/linux/fs/romfs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/romfs/inode.c	Mon May  8 14:26:13 2000
@@ -388,9 +388,9 @@
  */
 
 static int
-romfs_readpage(struct dentry * dentry, struct page * page)
+romfs_readpage(struct file *file, struct page * page)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	unsigned long buf;
 	unsigned long offset, avail, readlen;
 	int result = -EIO;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.3.99-pre6/linux/fs/smbfs/file.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/smbfs/file.c	Mon May  8 13:51:01 2000
@@ -56,7 +56,7 @@
 
 	/* We can't replace this with ClearPageError. why? is it a problem? 
 	   fs/buffer.c:brw_page does the same. */
-	/* clear_bit(PG_error, &page->flags); */
+	/* ClearPageError(page); */
 
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
@@ -98,9 +98,10 @@
 }
 
 static int
-smb_readpage(struct dentry *dentry, struct page *page)
+smb_readpage(struct file *file, struct page *page)
 {
 	int		error;
+	struct dentry  *dentry = file->f_dentry;
 
 	pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
 #ifdef SMBFS_PARANOIA
@@ -167,8 +168,9 @@
  * We are called with the page locked and the caller unlocks.
  */
 static int
-smb_writepage(struct file *file, struct dentry *dentry, struct page *page)
+smb_writepage(struct file *file, struct page *page)
 {
+	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset = PAGE_CACHE_SIZE;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/stat.c linux/fs/stat.c
--- v2.3.99-pre6/linux/fs/stat.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/stat.c	Mon May  8 11:17:47 2000
@@ -122,19 +122,16 @@
  */
 asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_old_stat(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_old_stat(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -143,19 +140,16 @@
 
 asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_new_stat(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_new_stat(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -169,19 +163,16 @@
  */
 asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_old_stat(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_old_stat(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -191,19 +182,16 @@
 
 asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_new_stat(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_new_stat(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -257,26 +245,24 @@
 
 asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	if (bufsiz <= 0)
 		return -EINVAL;
 
 	lock_kernel();
-	dentry = lnamei(path);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode * inode = dentry->d_inode;
+	error = user_path_walk_link(path, &nd);
+	if (!error) {
+		struct inode * inode = nd.dentry->d_inode;
 
 		error = -EINVAL;
 		if (inode->i_op && inode->i_op->readlink &&
-		    !(error = do_revalidate(dentry))) {
+		    !(error = do_revalidate(nd.dentry))) {
 			UPDATE_ATIME(inode);
-			error = inode->i_op->readlink(dentry, buf, bufsiz);
+			error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
 		}
-		dput(dentry);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -344,19 +330,16 @@
 
 asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_new_stat64(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_new_stat64(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
@@ -364,19 +347,16 @@
 
 asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
 	int error;
 
 	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
 		if (!error)
-			error = cp_new_stat64(dentry->d_inode, statbuf);
-
-		dput(dentry);
+			error = cp_new_stat64(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
 	}
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/super.c linux/fs/super.c
--- v2.3.99-pre6/linux/fs/super.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/super.c	Tue May  9 16:19:04 2000
@@ -4,9 +4,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  super.c contains code to handle: - mount structures
- *                                   - super-block tables.
+ *                                   - super-block tables
+ *                                   - filesystem drivers list
  *                                   - mount system call
  *                                   - umount system call
+ *                                   - ustat system call
  *
  *  Added options to /proc/mounts
  *  Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
@@ -16,6 +18,7 @@
  *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Added devfs support: Richard Gooch <rgooch@atnf.csiro.au>, 13-JAN-1998
+ *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
  */
 
 #include <linux/config.h>
@@ -74,7 +77,7 @@
  */
 
 static struct file_system_type *file_systems = NULL;
-static spinlock_t file_systems_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
 
 /* WARNING: This can be used only if we _already_ own a reference */
 static void get_filesystem(struct file_system_type *fs)
@@ -120,13 +123,13 @@
 		return -EINVAL;
 	if (fs->next)
 		return -EBUSY;
-	spin_lock(&file_systems_lock);
+	write_lock(&file_systems_lock);
 	p = find_filesystem(fs->name);
 	if (*p)
 		res = -EBUSY;
 	else
 		*p = fs;
-	spin_unlock(&file_systems_lock);
+	write_unlock(&file_systems_lock);
 	return res;
 }
 
@@ -146,18 +149,18 @@
 {
 	struct file_system_type ** tmp;
 
-	spin_lock(&file_systems_lock);
+	write_lock(&file_systems_lock);
 	tmp = &file_systems;
 	while (*tmp) {
 		if (fs == *tmp) {
 			*tmp = fs->next;
 			fs->next = NULL;
-			spin_unlock(&file_systems_lock);
+			write_unlock(&file_systems_lock);
 			return 0;
 		}
 		tmp = &(*tmp)->next;
 	}
-	spin_unlock(&file_systems_lock);
+	write_unlock(&file_systems_lock);
 	return -EINVAL;
 }
 
@@ -173,14 +176,14 @@
 		return err;
 
 	err = -EINVAL;
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
 		if (strcmp(tmp->name,name) == 0) {
 			err = index;
 			break;
 		}
 	}
-	spin_unlock(&file_systems_lock);
+	read_unlock(&file_systems_lock);
 	putname(name);
 	return err;
 }
@@ -190,11 +193,11 @@
 	struct file_system_type * tmp;
 	int len, res;
 
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	for (tmp = file_systems; tmp; tmp = tmp->next, index--)
 		if (index <= 0 && try_inc_mod_count(tmp->owner))
 				break;
-	spin_unlock(&file_systems_lock);
+	read_unlock(&file_systems_lock);
 	if (!tmp)
 		return -EINVAL;
 
@@ -210,10 +213,10 @@
 	struct file_system_type * tmp;
 	int index;
 
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
 		;
-	spin_unlock(&file_systems_lock);
+	read_unlock(&file_systems_lock);
 	return index;
 }
 
@@ -245,7 +248,7 @@
 	int len = 0;
 	struct file_system_type * tmp;
 
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	tmp = file_systems;
 	while (tmp && len < PAGE_SIZE - 80) {
 		len += sprintf(buf+len, "%s\t%s\n",
@@ -253,7 +256,7 @@
 			tmp->name);
 		tmp = tmp->next;
 	}
-	spin_unlock(&file_systems_lock);
+	read_unlock(&file_systems_lock);
 	return len;
 }
 
@@ -261,17 +264,17 @@
 {
 	struct file_system_type *fs;
 	
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	fs = *(find_filesystem(name));
 	if (fs && !try_inc_mod_count(fs->owner))
 		fs = NULL;
-	spin_unlock(&file_systems_lock);
+	read_unlock(&file_systems_lock);
 	if (!fs && (request_module(name) == 0)) {
-		spin_lock(&file_systems_lock);
+		read_lock(&file_systems_lock);
 		fs = *(find_filesystem(name));
 		if (fs && !try_inc_mod_count(fs->owner))
 			fs = NULL;
-		spin_unlock(&file_systems_lock);
+		read_unlock(&file_systems_lock);
 	}
 	return fs;
 }
@@ -279,55 +282,116 @@
 static LIST_HEAD(vfsmntlist);
 
 static struct vfsmount *add_vfsmnt(struct super_block *sb,
-			const char *dev_name, const char *dir_name)
+				struct dentry *mountpoint,
+				struct dentry *root,
+				struct vfsmount *parent,
+				const char *dev_name,
+				const char *dir_name)
 {
 	struct vfsmount *mnt;
 	char *name;
 
-	mnt = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
+	mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
 	if (!mnt)
 		goto out;
 	memset(mnt, 0, sizeof(struct vfsmount));
 
+	atomic_set(&mnt->mnt_count,1);
 	mnt->mnt_sb = sb;
-	mnt->mnt_dev = sb->s_dev;
+	mnt->mnt_mountpoint = dget(mountpoint);
+	mnt->mnt_root = dget(root);
+	mnt->mnt_parent = parent ? mntget(parent) : mnt;
 
 	/* N.B. Is it really OK to have a vfsmount without names? */
 	if (dev_name) {
-		name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
+		name = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
 		if (name) {
 			strcpy(name, dev_name);
 			mnt->mnt_devname = name;
 		}
 	}
-	if (dir_name) {
-		name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
-		if (name) {
-			strcpy(name, dir_name);
-			mnt->mnt_dirname = name;
-		}
+	name = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
+	if (name) {
+		strcpy(name, dir_name);
+		mnt->mnt_dirname = name;
 	}
 
+	if (parent)
+		list_add(&mnt->mnt_child, &parent->mnt_mounts);
+	else
+		INIT_LIST_HEAD(&mnt->mnt_child);
+	INIT_LIST_HEAD(&mnt->mnt_mounts);
+	list_add(&mnt->mnt_instances, &sb->s_mounts);
+	list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 out:
 	return mnt;
 }
 
-void remove_vfsmnt(kdev_t dev)
-{
-	struct list_head *p, *next;
+static void move_vfsmnt(struct vfsmount *mnt,
+			struct dentry *mountpoint,
+			struct vfsmount *parent,
+			const char *dev_name,
+			const char *dir_name)
+{
+	struct dentry *old_mountpoint = mnt->mnt_mountpoint;
+	struct vfsmount *old_parent = mnt->mnt_parent;
+	char *new_devname = NULL, *new_dirname = NULL;
 
-	for (p = vfsmntlist.next; p != &vfsmntlist; p = next) {
-		struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list);
+	if (dev_name) {
+		new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
+		if (new_devname)
+			strcpy(new_devname, dev_name);
+	}
+	if (dir_name) {
+		new_dirname = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
+		if (new_dirname)
+			strcpy(new_dirname, dir_name);
+	}
 
-		next = p->next;
-		if (mnt->mnt_dev != dev)
-			continue;
-		list_del(&mnt->mnt_list);
-		kfree(mnt->mnt_devname);
+	/* flip names */
+	if (new_dirname) {
 		kfree(mnt->mnt_dirname);
-		kfree(mnt);
+		mnt->mnt_dirname = new_dirname;
+	}
+	if (new_devname) {
+		kfree(mnt->mnt_devname);
+		mnt->mnt_devname = new_devname;
 	}
+
+	/* flip the linkage */
+	mnt->mnt_mountpoint = dget(mountpoint);
+	mnt->mnt_parent = parent ? mntget(parent) : mnt;
+	list_del(&mnt->mnt_clash);
+	list_del(&mnt->mnt_child);
+	list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
+	if (parent)
+		list_add(&mnt->mnt_child, &parent->mnt_mounts);
+	else
+		INIT_LIST_HEAD(&mnt->mnt_child);
+
+	/* put the old stuff */
+	dput(old_mountpoint);
+	if (old_parent != mnt)
+		mntput(old_parent);
+}
+
+static void remove_vfsmnt(struct vfsmount *mnt)
+{
+	/* First of all, remove it from all lists */
+	list_del(&mnt->mnt_instances);
+	list_del(&mnt->mnt_clash);
+	list_del(&mnt->mnt_list);
+	list_del(&mnt->mnt_child);
+	/* Now we can work safely */
+	if (mnt->mnt_parent != mnt)
+		mntput(mnt->mnt_parent);
+
+	dput(mnt->mnt_mountpoint);
+	dput(mnt->mnt_root);
+	kfree(mnt->mnt_devname);
+	kfree(mnt->mnt_dirname);
+	kfree(mnt);
 }
 
 static struct proc_fs_info {
@@ -375,9 +439,7 @@
 	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);
+		path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE);
 		if (!path)
 			continue;
 		len += sprintf( buf + len, "%s %s %s %s",
@@ -576,6 +638,7 @@
 		list_add (&s->s_list, super_blocks.prev);
 		init_waitqueue_head(&s->s_wait);
 		INIT_LIST_HEAD(&s->s_files);
+		INIT_LIST_HEAD(&s->s_mounts);
 	}
 	return s;
 }
@@ -647,20 +710,21 @@
 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;
+	struct nameidata nd;
 	kdev_t dev;
-	int error;
+	int error = 0;
 	/* 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;
+	if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		error = path_walk(dev_name, &nd);
+	if (error)
+		return ERR_PTR(error);
+	inode = nd.dentry->d_inode;
 	error = -ENOTBLK;
 	if (!S_ISBLK(inode->i_mode))
 		goto out;
@@ -679,14 +743,10 @@
 		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);
+			path_release(&nd);
 			return sb;
 		}
-		*/
 	} else {
 		mode_t mode = FMODE_READ; /* we always need it ;-) */
 		if (!(flags & MS_RDONLY))
@@ -698,13 +758,13 @@
 		sb = read_super(dev, bdev, fs_type, flags, data, 0);
 		if (sb) {
 			get_filesystem(fs_type);
-			dput(dentry);
+			path_release(&nd);
 			return sb;
 		}
 		blkdev_put(bdev, BDEV_FS);
 	}
 out:
-	dput(dentry);
+	path_release(&nd);
 	up(&mount_sem);
 	return ERR_PTR(error);
 }
@@ -730,10 +790,29 @@
 	return ERR_PTR(error);
 }
 
+static struct super_block *get_sb_single(struct file_system_type *fs_type,
+	int flags, void *data)
+{
+	struct super_block * sb;
+	/*
+	 * Get the superblock of kernel-wide instance, but
+	 * keep the reference to fs_type.
+	 */
+	down(&mount_sem);
+	sb = fs_type->kern_mnt->mnt_sb;
+	if (!sb)
+		BUG();
+	get_filesystem(fs_type);
+	do_remount_sb(sb, flags, data);
+	return sb;
+}
+
 static struct block_device *kill_super(struct super_block *sb, int umount_root)
 {
 	struct block_device *bdev;
 	kdev_t dev;
+	dput(sb->s_root);
+	sb->s_root = NULL;
 	lock_super(sb);
 	if (sb->s_op) {
 		if (sb->s_op->write_super && sb->s_dirt)
@@ -803,48 +882,79 @@
 	return 0;
 }
 
-static int d_umount(struct super_block * sb)
+struct vfsmount *kern_mount(struct file_system_type *type)
 {
-	struct dentry * root = sb->s_root;
-	struct dentry * covered = root->d_covers;
-
-	if (root->d_count != 1)
-		return -EBUSY;
+	kdev_t dev = get_unnamed_dev();
+	struct super_block *sb;
+	struct vfsmount *mnt;
+	if (!dev)
+		return ERR_PTR(-EMFILE);
+	sb = read_super(dev, NULL, type, 0, NULL, 0);
+	if (!sb) {
+		put_unnamed_dev(dev);
+		return ERR_PTR(-EINVAL);
+	}
+	mnt = add_vfsmnt(sb, sb->s_root, sb->s_root, NULL, "none", type->name);
+	if (!mnt) {
+		kill_super(sb, 0);
+		return ERR_PTR(-ENOMEM);
+	}
+	type->kern_mnt = mnt;
+	return mnt;
+}
 
-	if (root->d_inode->i_state)
-		return -EBUSY;
+/* Call only after unregister_filesystem() - it's a final cleanup */
 
+void kern_umount(struct vfsmount *mnt)
+{
+	struct super_block *sb = mnt->mnt_sb;
+	struct dentry *root = sb->s_root;
+	remove_vfsmnt(mnt);
+	dput(root);
 	sb->s_root = NULL;
+	kill_super(sb, 0);
+}
 
-	if (covered != root) {
-		root->d_covers = root;
-		covered->d_mounts = covered;
-		dput(covered);
-	}
-	dput(root);
+/*
+ * Doesn't take quota and stuff into account. IOW, in some cases it will
+ * give false negatives. The main reason why it's here is that we need
+ * a non-destructive way to look for easily umountable filesystems.
+ */
+int may_umount(struct vfsmount *mnt)
+{
+	if (atomic_read(&mnt->mnt_count) > 2)
+		return -EBUSY;
 	return 0;
 }
 
-static void d_mount(struct dentry *covered, struct dentry *dentry)
+static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
 {
-	if (covered->d_mounts != covered) {
-		printk("VFS: mount - already mounted\n");
-		return;
+	struct super_block * sb = mnt->mnt_sb;
+
+	if (mnt == current->fs->rootmnt && !umount_root) {
+		int retval = 0;
+		/*
+		 * Special case for "unmounting" root ...
+		 * we just try to remount it readonly.
+		 */
+		mntput(mnt);
+		if (!(sb->s_flags & MS_RDONLY))
+			retval = do_remount_sb(sb, MS_RDONLY, 0);
+		return retval;
 	}
-	covered->d_mounts = dentry;
-	dentry->d_covers = covered;
-}
 
-static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
-{
-	struct super_block * sb;
-	struct block_device *bdev;
-	int retval;
-	
-	retval = -ENOENT;
-	sb = get_super(dev);
-	if (!sb || !sb->s_root)
-		goto out;
+	if (atomic_read(&mnt->mnt_count) > 2) {
+		mntput(mnt);
+		return -EBUSY;
+	}
+
+	if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
+		if (sb->s_type->fs_flags & FS_SINGLE)
+			put_filesystem(sb->s_type);
+		mntput(mnt);
+		remove_vfsmnt(mnt);
+		return 0;
+	}
 
 	/*
 	 * Before checking whether the filesystem is still busy,
@@ -853,7 +963,7 @@
 	 * are no quotas running any more. Just turn them on again.
 	 */
 	DQUOT_OFF(sb);
-	acct_auto_close(dev);
+	acct_auto_close(sb->s_dev);
 
 	/*
 	 * If we may have to abort operations to get out of this
@@ -864,7 +974,7 @@
 	 * must return, and the like. Thats for the mount program to worry
 	 * about for the moment.
 	 */
-	 
+
 	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
 		sb->s_op->umount_begin(sb);
 
@@ -875,52 +985,26 @@
 	 * clean.
 	 */
 	shrink_dcache_sb(sb);
-	fsync_dev(dev);
-
-	if (sb == current->fs->root->d_sb && !unmount_root) {
-		/*
-		 * Special case for "unmounting" root ...
-		 * we just try to remount it readonly.
-		 */
-		retval = 0;
-		if (!(sb->s_flags & MS_RDONLY))
-			retval = do_remount_sb(sb, MS_RDONLY, 0);
-		return ERR_PTR(retval);
-	}
-
-	retval = d_umount(sb);
-	if (retval)
-		goto out;
-	remove_vfsmnt(dev);
-	bdev = kill_super(sb, unmount_root);
+	fsync_dev(sb->s_dev);
 
-	return bdev;
-
-out:
-	return ERR_PTR(retval);
-}
-
-static int umount_dev(kdev_t dev, int flags)
-{
-	int retval;
-	struct block_device *bdev;
+	/* Something might grab it again - redo checks */
 
-	retval = -ENXIO;
-	if (MAJOR(dev) >= MAX_BLKDEV)
-		goto out;
+	if (atomic_read(&mnt->mnt_count) > 2) {
+		mntput(mnt);
+		return -EBUSY;
+	}
 
-	fsync_dev(dev);
+	if (sb->s_root->d_inode->i_state) {
+		mntput(mnt);
+		return -EBUSY;
+	}
 
-	down(&mount_sem);
+	/* OK, that's the point of no return */
+	mntput(mnt);
+	remove_vfsmnt(mnt);
 
-	bdev = do_umount(dev, 0, flags);
-	if (IS_ERR(bdev))
-		retval = PTR_ERR(bdev);
-	else
-		retval = 0;
-	up(&mount_sem);
-out:
-	return retval;
+	kill_super(sb, umount_root);
+	return 0;
 }
 
 /*
@@ -933,36 +1017,38 @@
 
 asmlinkage long sys_umount(char * name, int flags)
 {
-	struct dentry * dentry;
+	struct nameidata nd;
+	char *kname;
 	int retval;
+	struct super_block *sb;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	lock_kernel();
-	dentry = namei(name);
-	retval = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct inode * inode = dentry->d_inode;
-		kdev_t dev = inode->i_rdev;
-
-		retval = 0;		
-		if (S_ISBLK(inode->i_mode)) {
-			if (IS_NODEV(inode))
-				retval = -EACCES;
-		} else {
-			struct super_block *sb = inode->i_sb;
-			retval = -EINVAL;
-			if (sb && inode == sb->s_root->d_inode) {
-				dev = sb->s_dev;
-				retval = 0;
-			}
-		}
-		dput(dentry);
-
-		if (!retval)
-			retval = umount_dev(dev, flags);
-	}
+	kname = getname(name);
+	retval = PTR_ERR(kname);
+	if (IS_ERR(kname))
+		goto out;
+	retval = 0;
+	if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
+		retval = path_walk(kname, &nd);
+	putname(kname);
+	if (retval)
+		goto out;
+	sb = nd.dentry->d_inode->i_sb;
+	retval = -EINVAL;
+	if (nd.dentry!=nd.mnt->mnt_root)
+		goto dput_and_out;
+	dput(nd.dentry);
+	/* puts nd.mnt */
+	down(&mount_sem);
+	retval = do_umount(nd.mnt, 0, flags);
+	up(&mount_sem);
+	goto out;
+dput_and_out:
+	path_release(&nd);
+out:
 	unlock_kernel();
 	return retval;
 }
@@ -977,16 +1063,47 @@
 }
 
 /*
- * Check whether we can mount the specified device.
+ * do loopback mount.
  */
-int fs_may_mount(kdev_t dev)
+static int do_loopback(char *old_name, char *new_name)
 {
-	struct super_block * sb = get_super(dev);
-	int busy;
-
-	busy = sb && sb->s_root &&
-	       (sb->s_root->d_count != 1 || sb->s_root->d_covers != sb->s_root);
-	return !busy;
+	struct nameidata old_nd, new_nd;
+	int err = 0;
+	if (!old_name || !*old_name)
+		return -EINVAL;
+	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &old_nd))
+		err = path_walk(old_name, &old_nd);
+	if (err)
+		goto out;
+	if (path_init(new_name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &new_nd))
+		err = path_walk(new_name, &new_nd);
+	if (err)
+		goto out1;
+	err = -EPERM;
+	if (!capable(CAP_SYS_ADMIN) &&
+	     current->uid != new_nd.dentry->d_inode->i_uid)
+		goto out2;
+	down(&mount_sem);
+	err = -ENOENT;
+	if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
+		goto out3;
+	if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
+		goto out3;
+	/* there we go */
+	err = -ENOMEM;
+	if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
+		get_filesystem(old_nd.mnt->mnt_sb->s_type);
+	if (add_vfsmnt(old_nd.mnt->mnt_sb, new_nd.dentry, old_nd.dentry,
+	               new_nd.mnt, old_nd.mnt->mnt_devname, new_name))
+		err = 0;
+out3:
+	up(&mount_sem);
+out2:
+	path_release(&new_nd);
+out1:
+	path_release(&old_nd);
+out:
+	return err;
 }
 
 /*
@@ -997,20 +1114,20 @@
 
 static int do_remount(const char *dir,int flags,char *data)
 {
-	struct dentry *dentry;
-	int retval;
+	struct nameidata nd;
+	int retval = 0;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-	retval = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		struct super_block * sb = dentry->d_inode->i_sb;
+	if (path_init(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		retval = path_walk(dir, &nd);
+	if (!retval) {
+		struct super_block * sb = nd.dentry->d_inode->i_sb;
 		retval = -ENODEV;
 		if (sb) {
 			retval = -EINVAL;
-			if (dentry == sb->s_root) {
+			if (nd.dentry == sb->s_root) {
 				/*
 				 * Shrink the dcache and sync the device.
 				 */
@@ -1021,7 +1138,7 @@
 				retval = do_remount_sb(sb, flags, data);
 			}
 		}
-		dput(dentry);
+		path_release(&nd);
 	}
 	return retval;
 }
@@ -1073,10 +1190,10 @@
 		  unsigned long new_flags, void *data_page)
 {
 	struct file_system_type * fstype;
-	struct dentry * dir_d;
+	struct nameidata nd;
 	struct vfsmount *mnt;
 	struct super_block *sb;
-	int retval;
+	int retval = 0;
 	unsigned long flags = 0;
  
 	/* Basic sanity checks */
@@ -1099,7 +1216,8 @@
 		flags = new_flags & ~MS_MGC_MSK;
 
 	/* loopback mount? This is special - requires fewer capabilities */
-	/* MOUNT_REWRITE: ... and is yet to be merged */
+	if (strcmp(type_page, "bind")==0)
+		return do_loopback(dev_name, dir_name);
 
 	/* for the rest we _really_ need capabilities... */
 	if (!capable(CAP_SYS_ADMIN))
@@ -1111,14 +1229,18 @@
 		return -ENODEV;
 
 	/* ... 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))
+	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+		retval = path_walk(dir_name, &nd);
+	if (retval)
 		goto fs_out;
 
 	/* get superblock, locks mount_sem on success */
-	if (fstype->fs_flags & FS_REQUIRES_DEV)
+	if (fstype->fs_flags & FS_NOMOUNT)
+		sb = ERR_PTR(-EINVAL);
+	else if (fstype->fs_flags & FS_REQUIRES_DEV)
 		sb = get_sb_bdev(fstype, dev_name,flags, data_page);
+	else if (fstype->fs_flags & FS_SINGLE)
+		sb = get_sb_single(fstype, flags, data_page);
 	else
 		sb = get_sb_nodev(fstype, flags, data_page);
 
@@ -1127,44 +1249,29 @@
 		goto dput_out;
 
 	retval = -ENOENT;
-	if (d_unhashed(dir_d))
+	if (d_unhashed(nd.dentry) && !IS_ROOT(nd.dentry))
 		goto fail;
 
-	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;
+	/* Something was mounted here while we slept */
+	while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
+		;
 
 	retval = -ENOMEM;
-	mnt = add_vfsmnt(sb, dev_name, dir_name);
+	mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, 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);
+	path_release(&nd);
 fs_out:
 	put_filesystem(fstype);
 	return retval;
 
 fail:
-	dput(sb->s_root);
-	sb->s_root = NULL;
-	kill_super(sb, 0);
+	if (list_empty(&sb->s_mounts))
+		kill_super(sb, 0);
 	goto unlock_out;
 }
 
@@ -1220,7 +1327,7 @@
 {
 	struct file_system_type * fs_type;
 	struct super_block * sb;
-	struct vfsmount *vfsmnt = NULL;
+	struct vfsmount *vfsmnt;
 	struct block_device *bdev = NULL;
 	mode_t mode;
 	int retval;
@@ -1330,33 +1437,29 @@
 	}
 
 	check_disk_change(ROOT_DEV);
+	sb = get_super(ROOT_DEV);
+	if (sb) {
+		fs_type = sb->s_type;
+		goto mount_it;
+	}
 
-	spin_lock(&file_systems_lock);
+	read_lock(&file_systems_lock);
 	for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
   		if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
   			continue;
 		if (!try_inc_mod_count(fs_type->owner))
 			continue;
-		spin_unlock(&file_systems_lock);
-		sb = get_super(ROOT_DEV);
-		if (sb) {
-			/* Shouldn't we fail here? Oh, well... */
-			sb->s_bdev = bdev;
-			goto mount_it;
-		}
+		read_unlock(&file_systems_lock);
   		sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);
 		if (sb) 
 			goto mount_it;
-		spin_lock(&file_systems_lock);
+		read_lock(&file_systems_lock);
 		put_filesystem(fs_type);
 	}
-	spin_unlock(&file_systems_lock);
-	panic("VFS: Unable to mount root fs on %s",
-		kdevname(ROOT_DEV));
+	read_unlock(&file_systems_lock);
+	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
 
 mount_it:
-	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" : "");
@@ -1366,11 +1469,15 @@
 				  path + 5 + path_start, 0,
 				  NULL, NULL);
 		memcpy (path + path_start, "/dev/", 5);
-		vfsmnt = add_vfsmnt (sb, path + path_start,
-				     "/");
+		vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
+					path + path_start, "/");
 	}
-	else vfsmnt = add_vfsmnt (sb, "/dev/root", "/");
+	else
+		vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
+					"/dev/root", "/");
 	if (vfsmnt) {
+		set_fs_root(current->fs, vfsmnt, sb->s_root);
+		set_fs_pwd(current->fs, vfsmnt, sb->s_root);
 		if (bdev)
 			bdput(bdev); /* sb holds a reference */
 		return;
@@ -1420,68 +1527,79 @@
 {
 	struct dentry *root = current->fs->root;
 	struct vfsmount *root_mnt = current->fs->rootmnt;
-	struct dentry *d_new_root, *d_put_old, *covered;
-	struct dentry *root_dev_root, *new_root_dev_root;
-	struct dentry *walk, *next;
-	struct vfsmount *new_root_mnt = NULL;
+	struct vfsmount *tmp;
+	struct nameidata new_nd, old_nd;
+	char *name;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	lock_kernel();
-	d_new_root = namei(new_root);
-	if (IS_ERR(d_new_root)) {
-		error = PTR_ERR(d_new_root);
+
+	name = getname(new_root);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
 		goto out0;
-	}
-	d_put_old = namei(put_old);
-	if (IS_ERR(d_put_old)) {
-		error = PTR_ERR(d_put_old);
+	error = 0;
+	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))
+		error = path_walk(name, &new_nd);
+	putname(name);
+	if (error)
+		goto out0;
+
+	name = getname(put_old);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto out0;
+	error = 0;
+	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
+		error = path_walk(name, &old_nd);
+	putname(name);
+	if (error)
 		goto out1;
-	}
+
 	down(&mount_sem);
-	if (!d_new_root->d_inode || !d_put_old->d_inode) {
-		error = -ENOENT;
+	error = -ENOENT;
+	if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
 		goto out2;
-	}
-	if (!S_ISDIR(d_new_root->d_inode->i_mode) ||
-	    !S_ISDIR(d_put_old->d_inode->i_mode)) {
-		error = -ENOTDIR;
+	if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
 		goto out2;
-	}
 	error = -EBUSY;
-	if (d_new_root->d_sb == root->d_sb || d_put_old->d_sb == root->d_sb)
+	if (new_nd.mnt == root_mnt || old_nd.mnt == root_mnt)
 		goto out2; /* loop */
-	if (d_put_old != d_put_old->d_covers)
-		goto out2; /* mount point is busy */
 	error = -EINVAL;
-	walk = d_put_old; /* make sure we can reach put_old from new_root */
-	for (;;) {
-		next = walk->d_covers->d_parent;
-		if (next == walk)
+	tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
+	if (tmp != new_nd.mnt) {
+		for (;;) {
+			if (tmp->mnt_parent == tmp)
+				goto out2;
+			if (tmp->mnt_parent == new_nd.mnt)
+				break;
+			tmp = tmp->mnt_parent;
+		}
+		if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry))
 			goto out2;
-		if (next == d_new_root)
-			break;
-		walk = next;
-	}
+	} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
+		goto out2;
+
+	error = -ENOMEM;
+	name = __getname();
+	if (!name)
+		goto out2;
 
-	new_root_dev_root = d_new_root->d_sb->s_root;
-	covered = new_root_dev_root->d_covers;
-	new_root_dev_root->d_covers = new_root_dev_root;
-	dput(covered);
-	covered->d_mounts = covered;
-
-	root_dev_root = root->d_sb->s_root;
-	root_dev_root->d_covers = dget(d_put_old);
-	d_put_old->d_mounts = root_dev_root;
-	chroot_fs_refs(root,root_mnt,d_new_root,new_root_mnt);
+	move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/");
+	move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL,
+			__d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry,
+				new_nd.mnt, name, PAGE_SIZE));
+	putname(name);
+	chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt);
 	error = 0;
 out2:
 	up(&mount_sem);
-	dput(d_put_old);
+	path_release(&old_nd);
 out1:
-	dput(d_new_root);
+	path_release(&new_nd);
 out0:
 	unlock_kernel();
 	return error;
@@ -1492,76 +1610,57 @@
 
 int __init change_root(kdev_t new_root_dev,const char *put_old)
 {
-	kdev_t old_root_dev;
-	struct vfsmount *vfsmnt;
-	struct dentry *old_root,*old_pwd,*dir_d = NULL;
-	int error;
+	kdev_t old_root_dev = ROOT_DEV;
+	struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt);
+	struct nameidata devfs_nd, nd;
+	int error = 0;
 
-	old_root = current->fs->root;
-	old_pwd = current->fs->pwd;
-	old_root_dev = ROOT_DEV;
-	if (!fs_may_mount(new_root_dev)) {
-		printk(KERN_CRIT "New root is busy. Staying in initrd.\n");
-		return -EBUSY;
-	}
 	/*  First unmount devfs if mounted  */
-	dir_d = lookup_dentry ("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-	if (!IS_ERR(dir_d)) {
-		struct super_block *sb = dir_d->d_inode->i_sb;
-
-		if (sb && (dir_d->d_inode == sb->s_root->d_inode) &&
-		    (sb->s_magic == DEVFS_SUPER_MAGIC)) {
-			dput (dir_d);
-			do_umount (sb->s_dev, 0, 0);
-		}
-		else dput (dir_d);
+	if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
+		error = path_walk("/dev", &devfs_nd);
+	if (!error) {
+		struct super_block *sb = devfs_nd.dentry->d_inode->i_sb;
+
+		if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC &&
+		    devfs_nd.dentry == devfs_nd.mnt->mnt_root) {
+			dput(devfs_nd.dentry);
+			down(&mount_sem);
+			/* puts devfs_nd.mnt */
+			do_umount(devfs_nd.mnt, 0, 0);
+			up(&mount_sem);
+		} else 
+			path_release(&devfs_nd);
 	}
 	ROOT_DEV = new_root_dev;
 	mount_root();
-	dput(old_root);
-	dput(old_pwd);
 #if 1
 	shrink_dcache();
-	printk("change_root: old root has d_count=%d\n", old_root->d_count);
+	printk("change_root: old root has d_count=%d\n", 
+	       old_rootmnt->mnt_root->d_count);
 #endif
 	mount_devfs_fs ();
 	/*
 	 * Get the new mount directory
 	 */
-	dir_d = lookup_dentry(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-	if (IS_ERR(dir_d)) {
-		error = PTR_ERR(dir_d);
-	} else {
-		error = 0;
-	}
-	if (!error && dir_d->d_covers != dir_d) {
-		dput(dir_d);
-		error = -EBUSY;
-	}
-	if (!error && !S_ISDIR(dir_d->d_inode->i_mode)) {
-		dput(dir_d);
-		error = -ENOTDIR;
-	}
+	error = 0;
+	if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+		error = path_walk(put_old, &nd);
 	if (error) {
-		struct block_device *bdev;
+		int blivet;
 
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
-		bdev = do_umount(old_root_dev,1, 0);
-		if (!IS_ERR(bdev)) {
+		blivet = do_umount(old_rootmnt, 1, 0);
+		if (!blivet) {
 			printk("okay\n");
 			return 0;
 		}
-		printk(KERN_ERR "error %ld\n",PTR_ERR(bdev));
+		printk(KERN_ERR "error %ld\n",blivet);
 		return error;
 	}
-	remove_vfsmnt(old_root_dev);
-	vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old);
-	if (vfsmnt) {
-		d_mount(dir_d,old_root);
-		return 0;
-	}
-	printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
-	return -ENOMEM;
+	move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old);
+	mntput(old_rootmnt);
+	path_release(&nd);
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.99-pre6/linux/fs/sysv/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/sysv/inode.c	Mon May  8 13:51:01 2000
@@ -939,11 +939,11 @@
 	return NULL;
 }
 
-static int sysv_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int sysv_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,sysv_get_block);
 }
-static int sysv_readpage(struct dentry *dentry, struct page *page)
+static int sysv_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,sysv_get_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.99-pre6/linux/fs/udf/file.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/udf/file.c	Mon May  8 13:51:01 2000
@@ -42,7 +42,7 @@
 #include "udf_i.h"
 #include "udf_sb.h"
 
-static int udf_adinicb_readpage(struct dentry *dentry, struct page * page)
+static int udf_adinicb_readpage(struct file *file, struct page * page)
 {
 	struct inode *inode = (struct inode *)page->mapping->host;
 
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-static int udf_adinicb_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int udf_adinicb_writepage(struct file *file, struct page *page)
 {
 	struct inode *inode = (struct inode *)page->mapping->host;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.99-pre6/linux/fs/udf/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/udf/inode.c	Wed May 10 16:56:43 2000
@@ -125,12 +125,12 @@
 		udf_trunc(inode);
 }
 
-static int udf_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int udf_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page, udf_get_block);
 }
 
-static int udf_readpage(struct dentry *dentry, struct page *page)
+static int udf_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page, udf_get_block);
 }
@@ -202,7 +202,7 @@
 	mark_buffer_dirty(bh, 1);
 	udf_release_data(bh);
 
-	inode->i_data.a_ops->writepage(NULL, NULL, page);
+	inode->i_data.a_ops->writepage(NULL, page);
 	UnlockPage(page);
 	page_cache_release(page);
 
@@ -397,7 +397,7 @@
 	int c = 1;
 	int lbcount = 0, b_off = 0, offset = 0;
 	Uint32 newblocknum, newblock;
-	char etype;
+	int etype;
 	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
 	char lastblock = 0;
 
@@ -1885,7 +1885,7 @@
 	struct buffer_head *obh;
 	lb_addr obloc;
 	int oextoffset, adsize;
-	char type;
+	int type;
 	struct AllocExtDesc *aed;
 
 	if (!(nbh))
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/udf/symlink.c linux/fs/udf/symlink.c
--- v2.3.99-pre6/linux/fs/udf/symlink.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/udf/symlink.c	Mon May  8 14:26:31 2000
@@ -76,9 +76,9 @@
 		p[0] = '\0';
 }
 
-static int udf_symlink_filler(struct dentry * dentry, struct page *page)
+static int udf_symlink_filler(struct file *file, struct page *page)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = (struct inode*)page->mapping->host;
 	struct buffer_head *bh = NULL;
 	char *symlink;
 	int err = -EIO;
diff -u --recursive --new-file v2.3.99-pre6/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.3.99-pre6/linux/fs/ufs/inode.c	Wed Apr 26 16:34:09 2000
+++ linux/fs/ufs/inode.c	Mon May  8 13:51:01 2000
@@ -540,11 +540,11 @@
 	return NULL;
 }
 
-static int ufs_writepage(struct file *file, struct dentry *dentry, struct page *page)
+static int ufs_writepage(struct file *file, struct page *page)
 {
 	return block_write_full_page(page,ufs_getfrag_block);
 }
-static int ufs_readpage(struct dentry *dentry, struct page *page)
+static int ufs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,ufs_getfrag_block);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- v2.3.99-pre6/linux/include/asm-alpha/atomic.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-alpha/atomic.h	Mon May  8 22:00:01 2000
@@ -1,6 +1,8 @@
 #ifndef _ALPHA_ATOMIC_H
 #define _ALPHA_ATOMIC_H
 
+#include <linux/config.h>
+
 /*
  * Atomic operations that C can't guarantee us.  Useful for
  * resource counting etc...
@@ -9,7 +11,7 @@
  * than regular operations.
  */
 
-#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-pre6/linux/include/asm-alpha/delay.h linux/include/asm-alpha/delay.h
--- v2.3.99-pre6/linux/include/asm-alpha/delay.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-alpha/delay.h	Mon May  8 22:00:01 2000
@@ -1,6 +1,7 @@
 #ifndef __ALPHA_DELAY_H
 #define __ALPHA_DELAY_H
 
+#include <linux/config.h>
 #include <asm/smp.h>
 
 /*
@@ -37,7 +38,7 @@
 	__delay((long)usecs >> 32);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define udelay(u)  __udelay((u), cpu_data[smp_processor_id()].loops_per_sec)
 #else
 #define udelay(u)  __udelay((u), loops_per_sec)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.3.99-pre6/linux/include/asm-alpha/hardirq.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-alpha/hardirq.h	Mon May  8 22:00:01 2000
@@ -3,9 +3,10 @@
 
 /* Initially just a straight copy of the i386 code.  */
 
+#include <linux/config.h>
 #include <linux/threads.h>
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern int __local_irq_count;
 #define local_irq_count(cpu)  ((void)(cpu), __local_irq_count)
 extern unsigned long __irq_attempt[];
@@ -28,7 +29,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)	((void) 0)
@@ -88,5 +89,5 @@
 
 extern void synchronize_irq(void);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #endif /* _ALPHA_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h
--- v2.3.99-pre6/linux/include/asm-alpha/mmu_context.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-alpha/mmu_context.h	Mon May  8 22:00:01 2000
@@ -84,16 +84,16 @@
  * +-------------+----------------+--------------+
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #include <asm/smp.h>
 #define cpu_last_asn(cpuid)	(cpu_data[cpuid].last_asn)
 #else
 extern unsigned long last_asn;
 #define cpu_last_asn(cpuid)	last_asn
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #define WIDTH_HARDWARE_ASN	8
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define WIDTH_THIS_PROCESSOR	5
 #else
 #define WIDTH_THIS_PROCESSOR	0
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h
--- v2.3.99-pre6/linux/include/asm-alpha/pgalloc.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-alpha/pgalloc.h	Mon May  8 22:00:01 2000
@@ -30,7 +30,7 @@
    icache flushing.  While functional, it is _way_ overkill.  The
    icache is tagged with ASNs and it suffices to allocate a new ASN
    for the process.  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 #define flush_icache_range(start, end)		imb()
 #else
 #define flush_icache_range(start, end)		smp_imb()
@@ -45,7 +45,7 @@
    that icache entries are tagged with the ASN and load a new mm context.  */
 /* ??? Ought to use this in arch/alpha/kernel/signal.c too.  */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 static inline void
 flush_icache_page(struct vm_area_struct *vma, struct page *page)
 {
@@ -154,7 +154,7 @@
 {
 }
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 /*
  * Flush everything (kernel mapping may also have
  * changed due to vmalloc/vfree)
@@ -204,21 +204,21 @@
 	flush_tlb_mm(mm);
 }
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 /*      
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
 	unsigned long *pte_cache;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.3.99-pre6/linux/include/asm-alpha/smp.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-alpha/smp.h	Mon May  8 22:00:01 2000
@@ -1,6 +1,7 @@
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 
+#include <linux/config.h>
 #include <asm/pal.h>
 
 /* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
@@ -17,7 +18,7 @@
 	return __r0;
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #include <linux/threads.h>
 #include <asm/irq.h>
@@ -56,7 +57,7 @@
 
 extern unsigned long cpu_present_mask;
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #define NO_PROC_ID	(-1)
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.3.99-pre6/linux/include/asm-alpha/softirq.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-alpha/softirq.h	Mon May  8 22:00:01 2000
@@ -1,11 +1,12 @@
 #ifndef _ALPHA_SOFTIRQ_H
 #define _ALPHA_SOFTIRQ_H
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern int __local_bh_count;
 #define local_bh_count(cpu)	((void)(cpu), __local_bh_count)
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/string.h linux/include/asm-alpha/string.h
--- v2.3.99-pre6/linux/include/asm-alpha/string.h	Fri Aug  6 10:41:47 1999
+++ linux/include/asm-alpha/string.h	Mon May  8 15:55:00 2000
@@ -11,7 +11,10 @@
  */
 
 #define __HAVE_ARCH_MEMCPY
+extern void * memcpy(void *, const void *, size_t);
 #define __HAVE_ARCH_MEMMOVE
+extern void * memmove(void *, const void *, size_t);
+
 /* For backward compatibility with modules.  Unused otherwise.  */
 extern void * __memcpy(void *, const void *, size_t);
 
@@ -22,6 +25,7 @@
 #define __HAVE_ARCH_MEMSET
 extern void * __constant_c_memset(void *, unsigned long, size_t);
 extern void * __memset(void *, int, size_t);
+extern void * memset(void *, int, size_t);
 
 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
 #define memset(s, c, n)							    \
@@ -38,13 +42,21 @@
 #endif
 
 #define __HAVE_ARCH_STRCPY
+extern char * strcpy(char *,const char *);
 #define __HAVE_ARCH_STRNCPY
+extern char * strncpy(char *, const char *, size_t);
 #define __HAVE_ARCH_STRCAT
+extern char * strcat(char *, const char *);
 #define __HAVE_ARCH_STRNCAT
+extern char * strncat(char *, const char *, size_t);
 #define __HAVE_ARCH_STRCHR
+extern char * strchr(const char *,int);
 #define __HAVE_ARCH_STRRCHR
+extern char * strrchr(const char *,int);
 #define __HAVE_ARCH_STRLEN
+extern size_t strlen(const char *);
 #define __HAVE_ARCH_MEMCHR
+extern void * memchr(const void *, int, size_t);
 
 /* The following routine is like memset except that it writes 16-bit
    aligned values.  The DEST and COUNT parameters must be even for 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.3.99-pre6/linux/include/asm-alpha/system.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-alpha/system.h	Mon May  8 22:00:01 2000
@@ -290,7 +290,7 @@
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 extern int global_irq_holder;
 
@@ -306,7 +306,7 @@
 #define save_flags(flags)	((flags) = __global_save_flags())
 #define restore_flags(flags)    __global_restore_flags(flags)
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 #define cli()			__cli()
 #define sti()			__sti()
@@ -314,7 +314,7 @@
 #define save_and_cli(flags)	__save_and_cli(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 /*
  * TB routines..
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h
--- v2.3.99-pre6/linux/include/asm-i386/spinlock.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-i386/spinlock.h	Thu May 11 11:26:54 2000
@@ -12,7 +12,7 @@
  * initialize their spinlocks properly, tsk tsk.
  * Remember to turn this off in 2.4. -ben
  */
-#define SPINLOCK_DEBUG	1
+#define SPINLOCK_DEBUG	0
 
 /*
  * Your basic SMP spinlocks, allowing only a single CPU anywhere
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.3.99-pre6/linux/include/asm-i386/string.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-i386/string.h	Thu May 11 11:26:54 2000
@@ -30,7 +30,7 @@
  */
 
 #define __HAVE_ARCH_STRCPY
-extern inline char * strcpy(char * dest,const char *src)
+static inline char * strcpy(char * dest,const char *src)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -44,7 +44,7 @@
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern inline char * strncpy(char * dest,const char *src,size_t count)
+static inline char * strncpy(char * dest,const char *src,size_t count)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -63,7 +63,7 @@
 }
 
 #define __HAVE_ARCH_STRCAT
-extern inline char * strcat(char * dest,const char * src)
+static inline char * strcat(char * dest,const char * src)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -80,7 +80,7 @@
 }
 
 #define __HAVE_ARCH_STRNCAT
-extern inline char * strncat(char * dest,const char * src,size_t count)
+static inline char * strncat(char * dest,const char * src,size_t count)
 {
 int d0, d1, d2, d3;
 __asm__ __volatile__(
@@ -103,7 +103,7 @@
 }
 
 #define __HAVE_ARCH_STRCMP
-extern inline int strcmp(const char * cs,const char * ct)
+static inline int strcmp(const char * cs,const char * ct)
 {
 int d0, d1;
 register int __res;
@@ -124,7 +124,7 @@
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
+static inline int strncmp(const char * cs,const char * ct,size_t count)
 {
 register int __res;
 int d0, d1, d2;
@@ -147,7 +147,7 @@
 }
 
 #define __HAVE_ARCH_STRCHR
-extern inline char * strchr(const char * s, int c)
+static inline char * strchr(const char * s, int c)
 {
 int d0;
 register char * __res;
@@ -166,7 +166,7 @@
 }
 
 #define __HAVE_ARCH_STRRCHR
-extern inline char * strrchr(const char * s, int c)
+static inline char * strrchr(const char * s, int c)
 {
 int d0, d1;
 register char * __res;
@@ -183,7 +183,7 @@
 }
 
 #define __HAVE_ARCH_STRLEN
-extern inline size_t strlen(const char * s)
+static inline size_t strlen(const char * s)
 {
 int d0;
 register int __res;
@@ -196,7 +196,7 @@
 return __res;
 }
 
-extern inline void * __memcpy(void * to, const void * from, size_t n)
+static inline void * __memcpy(void * to, const void * from, size_t n)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -218,7 +218,7 @@
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
-extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
+static inline void * __constant_memcpy(void * to, const void * from, size_t n)
 {
 	switch (n) {
 		case 0:
@@ -300,7 +300,7 @@
  *	This CPU favours 3DNow strongly (eg AMD Athlon)
  */
 
-extern inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
+static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
 {
 	if(len<512 || in_interrupt())
 		return __constant_memcpy(to, from, len);
@@ -349,7 +349,7 @@
 })
 
 #define __HAVE_ARCH_MEMMOVE
-extern inline void * memmove(void * dest,const void * src, size_t n)
+static inline void * memmove(void * dest,const void * src, size_t n)
 {
 int d0, d1, d2;
 if (dest<src)
@@ -376,7 +376,7 @@
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-extern inline void * memchr(const void * cs,int c,size_t count)
+static inline void * memchr(const void * cs,int c,size_t count)
 {
 int d0;
 register void * __res;
@@ -392,7 +392,7 @@
 return __res;
 }
 
-extern inline void * __memset_generic(void * s, char c,size_t count)
+static inline void * __memset_generic(void * s, char c,size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -412,7 +412,7 @@
  * things 32 bits at a time even when we don't know the size of the
  * area at compile-time..
  */
-extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -432,7 +432,7 @@
 
 /* Added by Gertjan van Wingerde to make minix and sysv module work */
 #define __HAVE_ARCH_STRNLEN
-extern inline size_t strnlen(const char * s, size_t count)
+static inline size_t strnlen(const char * s, size_t count)
 {
 int d0;
 register int __res;
@@ -453,7 +453,7 @@
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-extern inline char * strstr(const char * cs,const char * ct)
+static inline char * strstr(const char * cs,const char * ct)
 {
 int	d0, d1;
 register char * __res;
@@ -486,7 +486,7 @@
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
  */
-extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
 {
 	switch (count) {
 		case 0:
@@ -545,7 +545,7 @@
  * find the first occurrence of byte 'c', or 1 past the area if none
  */
 #define __HAVE_ARCH_MEMSCAN
-extern inline void * memscan(void * addr, int c, size_t size)
+static inline void * memscan(void * addr, int c, size_t size)
 {
 	if (!size)
 		return addr;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-m68k/string.h linux/include/asm-m68k/string.h
--- v2.3.99-pre6/linux/include/asm-m68k/string.h	Thu Dec 17 09:06:25 1998
+++ linux/include/asm-m68k/string.h	Thu Apr 27 15:55:09 2000
@@ -5,7 +5,7 @@
 #include <asm/page.h>
 
 #define __HAVE_ARCH_STRCPY
-extern inline char * strcpy(char * dest,const char *src)
+static inline char * strcpy(char * dest,const char *src)
 {
   char *xdest = dest;
 
@@ -18,7 +18,7 @@
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern inline char * strncpy(char *dest, const char *src, size_t n)
+static inline char * strncpy(char *dest, const char *src, size_t n)
 {
   char *xdest = dest;
 
@@ -38,7 +38,7 @@
 }
 
 #define __HAVE_ARCH_STRCAT
-extern inline char * strcat(char * dest, const char * src)
+static inline char * strcat(char * dest, const char * src)
 {
 	char *tmp = dest;
 
@@ -51,7 +51,7 @@
 }
 
 #define __HAVE_ARCH_STRNCAT
-extern inline char * strncat(char *dest, const char *src, size_t count)
+static inline char * strncat(char *dest, const char *src, size_t count)
 {
 	char *tmp = dest;
 
@@ -70,7 +70,7 @@
 }
 
 #define __HAVE_ARCH_STRCHR
-extern inline char * strchr(const char * s, int c)
+static inline char * strchr(const char * s, int c)
 {
   const char ch = c;
   
@@ -81,7 +81,7 @@
 }
 
 #define __HAVE_ARCH_STRPBRK
-extern inline char * strpbrk(const char * cs,const char * ct)
+static inline char * strpbrk(const char * cs,const char * ct)
 {
   const char *sc1,*sc2;
   
@@ -93,7 +93,7 @@
 }
 
 #define __HAVE_ARCH_STRSPN
-extern inline size_t strspn(const char *s, const char *accept)
+static inline size_t strspn(const char *s, const char *accept)
 {
   const char *p;
   const char *a;
@@ -114,7 +114,7 @@
 }
 
 #define __HAVE_ARCH_STRTOK
-extern inline char * strtok(char * s,const char * ct)
+static inline char * strtok(char * s,const char * ct)
 {
   char *sbegin, *send;
   
@@ -137,7 +137,7 @@
 /* strstr !! */
 
 #define __HAVE_ARCH_STRLEN
-extern inline size_t strlen(const char * s)
+static inline size_t strlen(const char * s)
 {
   const char *sc;
   for (sc = s; *sc != '\0'; ++sc) ;
@@ -147,7 +147,7 @@
 /* strnlen !! */
 
 #define __HAVE_ARCH_STRCMP
-extern inline int strcmp(const char * cs,const char * ct)
+static inline int strcmp(const char * cs,const char * ct)
 {
   char __res;
 
@@ -166,7 +166,7 @@
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
+static inline int strncmp(const char * cs,const char * ct,size_t count)
 {
   char __res;
 
@@ -199,7 +199,7 @@
  * 680[46]0 doesn't really care due to their copy-back caches.
  *						10/09/96 - Jes Sorensen
  */
-extern inline void * __memset_g(void * s, int c, size_t count)
+static inline void * __memset_g(void * s, int c, size_t count)
 {
   void *xs = s;
   size_t temp;
@@ -304,7 +304,7 @@
  * caveat is that the destination address must be 16-byte aligned.
  *                                            01/09/96 - Jes Sorensen
  */
-extern inline void * __memset_page(void * s,int c,size_t count)
+static inline void * __memset_page(void * s,int c,size_t count)
 {
   unsigned long data, tmp;
   void *xs, *sp;
@@ -381,7 +381,7 @@
  * both source and destination must be 16-byte aligned, if not we fall
  * back to the generic memcpy function.  - Jes
  */
-extern inline void * __memcpy_page(void * to, const void * from, size_t count)
+static inline void * __memcpy_page(void * to, const void * from, size_t count)
 {
   unsigned long tmp;
   void *xto = to;
@@ -429,7 +429,7 @@
  memcpy((to),(from),(n)))
 
 #define __HAVE_ARCH_MEMMOVE
-extern inline void * memmove(void * dest,const void * src, size_t n)
+static inline void * memmove(void * dest,const void * src, size_t n)
 {
   void *xdest = dest;
   size_t temp;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-mips/atomic.h linux/include/asm-mips/atomic.h
--- v2.3.99-pre6/linux/include/asm-mips/atomic.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-mips/atomic.h	Mon May  8 22:00:01 2000
@@ -18,7 +18,7 @@
 
 #include <linux/config.h>
 
-#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-pre6/linux/include/asm-mips/delay.h linux/include/asm-mips/delay.h
--- v2.3.99-pre6/linux/include/asm-mips/delay.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/delay.h	Mon May  8 22:00:01 2000
@@ -10,6 +10,8 @@
 #ifndef _ASM_DELAY_H
 #define _ASM_DELAY_H
 
+#include <linux/config.h>
+
 extern __inline__ void
 __delay(unsigned long loops)
 {
@@ -42,7 +44,7 @@
 	__delay(usecs);
 }
 
-#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-pre6/linux/include/asm-mips/hardirq.h linux/include/asm-mips/hardirq.h
--- v2.3.99-pre6/linux/include/asm-mips/hardirq.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/hardirq.h	Mon May  8 22:00:01 2000
@@ -10,6 +10,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];
@@ -22,7 +23,7 @@
 	(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)
@@ -36,5 +37,5 @@
 
 #error No habla MIPS SMP
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #endif /* _ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-mips/pgalloc.h linux/include/asm-mips/pgalloc.h
--- v2.3.99-pre6/linux/include/asm-mips/pgalloc.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/pgalloc.h	Mon May  8 22:00:01 2000
@@ -10,6 +10,8 @@
 #ifndef _ASM_PGALLOC_H
 #define _ASM_PGALLOC_H
 
+#include <linux/config.h>
+
 /* TLB flushing:
  *
  *  - flush_tlb_all() flushes all processes TLB entries
@@ -188,7 +190,7 @@
 {
 	struct task_struct * p;
 	pgd_t *pgd;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int i;
 #endif	
 
@@ -199,7 +201,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-pre6/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.3.99-pre6/linux/include/asm-mips/processor.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/processor.h	Mon May  8 22:00:01 2000
@@ -14,6 +14,8 @@
 
 #include <asm/isadep.h>
 
+#include <linux/config.h>
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -45,7 +47,7 @@
 extern struct mips_cpuinfo boot_cpu_data;
 extern unsigned int vced_count, vcei_count;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern struct mips_cpuinfo cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-mips64/atomic.h linux/include/asm-mips64/atomic.h
--- v2.3.99-pre6/linux/include/asm-mips64/atomic.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/atomic.h	Mon May  8 22:00:01 2000
@@ -15,9 +15,10 @@
 #ifndef _ASM_ATOMIC_H
 #define _ASM_ATOMIC_H
 
+#include <linux/config.h>
 #include <asm/sgidefs.h>
 
-#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-pre6/linux/include/asm-mips64/delay.h linux/include/asm-mips64/delay.h
--- v2.3.99-pre6/linux/include/asm-mips64/delay.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/delay.h	Mon May  8 22:00:01 2000
@@ -11,6 +11,8 @@
 #ifndef _ASM_DELAY_H
 #define _ASM_DELAY_H
 
+#include <linux/config.h>
+
 extern __inline__ void
 __delay(unsigned long loops)
 {
@@ -43,7 +45,7 @@
 	__delay(usecs);
 }
 
-#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-pre6/linux/include/asm-mips64/hardirq.h linux/include/asm-mips64/hardirq.h
--- v2.3.99-pre6/linux/include/asm-mips64/hardirq.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/hardirq.h	Mon May  8 22:00:01 2000
@@ -10,6 +10,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];
@@ -22,7 +23,7 @@
 	(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)
@@ -36,5 +37,5 @@
 
 #error No habla MIPS SMP
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #endif /* _ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h
--- v2.3.99-pre6/linux/include/asm-mips64/pgalloc.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/pgalloc.h	Mon May  8 22:00:01 2000
@@ -10,6 +10,8 @@
 #ifndef _ASM_PGALLOC_H
 #define _ASM_PGALLOC_H
 
+#include <linux/config.h>
+
 /* TLB flushing:
  *
  *  - flush_tlb_all() flushes all processes TLB entries
@@ -206,7 +208,7 @@
 {
 	struct task_struct * p;
 	pgd_t *pgd;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int i;
 #endif	
         
@@ -217,7 +219,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-pre6/linux/include/asm-mips64/processor.h linux/include/asm-mips64/processor.h
--- v2.3.99-pre6/linux/include/asm-mips64/processor.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/processor.h	Mon May  8 22:00:01 2000
@@ -18,6 +18,7 @@
  */
 #define current_text_addr() ({ __label__ _l; _l: &&_l;})
 
+#include <linux/config.h>
 #if !defined (_LANGUAGE_ASSEMBLY)
 #include <asm/cachectl.h>
 #include <asm/mipsregs.h>
@@ -45,7 +46,7 @@
 extern struct mips_cpuinfo boot_cpu_data;
 extern unsigned int vced_count, vcei_count;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern struct mips_cpuinfo cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.3.99-pre6/linux/include/asm-ppc/atomic.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-ppc/atomic.h	Tue May  2 13:05:40 2000
@@ -18,94 +18,60 @@
 #define atomic_read(v)		((v)->counter)
 #define atomic_set(v,i)		(((v)->counter) = (i))
 
-extern void atomic_add(int a, atomic_t *v);
-extern int  atomic_add_return(int a, atomic_t *v);
-extern void atomic_sub(int a, atomic_t *v);
-extern void atomic_inc(atomic_t *v);
-extern int  atomic_inc_return(atomic_t *v);
-extern void atomic_dec(atomic_t *v);
-extern int  atomic_dec_return(atomic_t *v);
-extern int  atomic_dec_and_test(atomic_t *v);
-
 extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
 extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
 
-#if 0	/* for now */
-extern __inline__ void atomic_add(atomic_t a, atomic_t *v)
+extern __inline__ int atomic_add_return(int a, atomic_t *v)
 {
-	atomic_t t;
+	int t;
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3\n\
 	add	%0,%2,%0\n\
 	stwcx.	%0,0,%3\n\
-	bne	1b"
+	bne-	1b"
 	: "=&r" (t), "=m" (*v)
-	: "r" (a), "r" (v)
+	: "r" (a), "r" (v), "m" (*v)
 	: "cc");
-}
 
-extern __inline__ void atomic_sub(atomic_t a, atomic_t *v)
-{
-	atomic_t t;
-
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%3\n\
-	subf	%0,%2,%0\n\
-	stwcx.	%0,0,%3\n\
-	bne	1b"
-	: "=&r" (t), "=m" (*v)
-	: "r" (a), "r" (v)
-	: "cc");
+	return t;
 }
 
-extern __inline__ int atomic_sub_and_test(atomic_t a, atomic_t *v)
+extern __inline__ int atomic_sub_return(int a, atomic_t *v)
 {
-	atomic_t t;
+	int t;
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3\n\
 	subf	%0,%2,%0\n\
 	stwcx.	%0,0,%3\n\
-	bne	1b"
+	bne-	1b"
 	: "=&r" (t), "=m" (*v)
-	: "r" (a), "r" (v)
+	: "r" (a), "r" (v), "m" (*v)
 	: "cc");
 
-	return t == 0;
+	return t;
 }
 
-extern __inline__ void atomic_inc(atomic_t *v)
+extern __inline__ int atomic_inc_return(atomic_t *v)
 {
-	atomic_t t;
+	int t;
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%2\n\
 	addic	%0,%0,1\n\
 	stwcx.	%0,0,%2\n\
-	bne	1b"
+	bne-	1b"
 	: "=&r" (t), "=m" (*v)
-	: "r" (v)
+	: "r" (v), "m" (*v)
 	: "cc");
-}
-
-extern __inline__ void atomic_dec(atomic_t *v)
-{
-	atomic_t t;
 
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%2\n\
-	addic	%0,%0,-1\n\
-	stwcx.	%0,0,%2\n\
-	bne	1b"
-	: "=&r" (t), "=m" (*v)
-	: "r" (v)
-	: "cc");
+	return t;
 }
 
-extern __inline__ int atomic_dec_and_test(atomic_t *v)
+extern __inline__ int atomic_dec_return(atomic_t *v)
 {
-	atomic_t t;
+	int t;
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%2\n\
@@ -113,11 +79,17 @@
 	stwcx.	%0,0,%2\n\
 	bne	1b"
 	: "=&r" (t), "=m" (*v)
-	: "r" (v)
+	: "r" (v), "m" (*v)
 	: "cc");
 
-	return t == 0;
+	return t;
 }
-#endif /* 0 */
+
+#define atomic_add(a, v)		((void) atomic_add_return((a), (v)))
+#define atomic_sub(a, v)		((void) atomic_sub_return((a), (v)))
+#define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
+#define atomic_inc(v)			((void) atomic_inc_return((v)))
+#define atomic_dec(v)			((void) atomic_dec_return((v)))
+#define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
 
 #endif /* _ASM_PPC_ATOMIC_H_ */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.3.99-pre6/linux/include/asm-ppc/bitops.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ppc/bitops.h	Wed May  3 01:47:57 2000
@@ -6,6 +6,7 @@
 #ifndef _PPC_BITOPS_H
 #define _PPC_BITOPS_H
 
+#include <linux/config.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
 
@@ -16,15 +17,18 @@
 extern int test_and_clear_bit(int nr, volatile void *addr);
 extern int test_and_change_bit(int nr, volatile void *addr);
 
-
-/* Returns the number of 0's to the left of the most significant 1 bit */
-extern __inline__  int cntlzw(int bits)
-{
-	int lz;
-
-	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
-	return lz;
-}
+/*
+ * Arguably these bit operations don't imply any memory barrier or
+ * SMP ordering, but in fact a lot of drivers expect them to imply
+ * both, since they do on x86 cpus.
+ */
+#ifdef CONFIG_SMP
+#define SMP_WMB		"eieio\n"
+#define SMP_MB		"\nsync"
+#else
+#define SMP_WMB
+#define SMP_MB
+#endif /* CONFIG_SMP */
 
 /*
  * These are if'd out here because using : "cc" as a constraint
@@ -95,15 +99,20 @@
 	return ((p[nr >> 5] >> (nr & 0x1f)) & 1) != 0;
 }
 
-extern __inline__ int ffz(unsigned int x)
+/* Return the bit position of the most significant 1 bit in a word */
+extern __inline__ int __ilog2(unsigned int x)
 {
-	int n;
+	int lz;
 
-	if (x == ~0)
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	return 31 - lz;
+}
+
+extern __inline__ int ffz(unsigned int x)
+{
+	if ((x = ~x) == 0)
 		return 32;
-	x = ~x & (x+1);		/* set LS zero to 1, other bits to 0 */
-	__asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
-	return 31 - n;
+	return __ilog2(x & -x);
 }
 
 #ifdef __KERNEL__
@@ -113,19 +122,10 @@
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
-
-#define ffs(x) generic_ffs(x)
-
-#if 0
-/* untested, someone with PPC knowledge? */
-/* From Alexander Kjeldaas <astor@guardian.no> */
 extern __inline__ int ffs(int x)
 {
-        int result;
-        asm ("cntlzw %0,%1" : "=r" (result) : "r" (x));
-        return 32 - result; /* IBM backwards ordering of bits */
+	return __ilog2(x & -x) + 1;
 }
-#endif
 
 /*
  * hweightN: returns the hamming weight (i.e. the number
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/cache.h linux/include/asm-ppc/cache.h
--- v2.3.99-pre6/linux/include/asm-ppc/cache.h	Mon Dec 20 18:48:22 1999
+++ linux/include/asm-ppc/cache.h	Tue May  2 13:05:40 2000
@@ -8,11 +8,16 @@
 #include <asm/processor.h>
 
 /* bytes per L1 cache line */
-#define        L1_CACHE_BYTES  32      
-#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-#define L1_CACHE_PAGES		8
+#if !defined(CONFIG_8xx) || defined(CONFIG_8260)
+#define	L1_CACHE_BYTES  32
+#else
+#define	L1_CACHE_BYTES	16
+#endif /* !8xx || 8260 */
 
-#define        SMP_CACHE_BYTES L1_CACHE_BYTES
+#define	L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+#define	L1_CACHE_PAGES		8
+
+#define	SMP_CACHE_BYTES L1_CACHE_BYTES
 
 #ifdef MODULE
 #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/cpm_8260.h linux/include/asm-ppc/cpm_8260.h
--- v2.3.99-pre6/linux/include/asm-ppc/cpm_8260.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/cpm_8260.h	Tue May  2 13:05:40 2000
@@ -0,0 +1,551 @@
+
+/*
+ * MPC8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ *
+ * This file contains structures and information for the communication
+ * processor channels found in the dual port RAM or parameter RAM.
+ * All CPM control and status is available through the MPC8260 internal
+ * memory map.  See immap.h for details.
+ */
+#ifndef __CPM_82XX__
+#define __CPM_82XX__
+
+#include <asm/immap_8260.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST	((uint)0x80000000)
+#define CPM_CR_PAGE	((uint)0x7c000000)
+#define CPM_CR_SBLOCK	((uint)0x03e00000)
+#define CPM_CR_FLG	((uint)0x00010000)
+#define CPM_CR_MCN	((uint)0x00003fc0)
+#define CPM_CR_OPCODE	((uint)0x0000000f)
+
+/* Device sub-block and page codes.
+*/
+#define CPM_CR_SCC1_SBLOCK	(0x04)
+#define CPM_CR_SCC2_SBLOCK	(0x05)
+#define CPM_CR_SCC3_SBLOCK	(0x06)
+#define CPM_CR_SCC4_SBLOCK	(0x07)
+#define CPM_CR_SMC1_SBLOCK	(0x08)
+#define CPM_CR_SMC2_SBLOCK	(0x09)
+#define CPM_CR_SPI_SBLOCK	(0x0a)
+#define CPM_CR_I2C_SBLOCK	(0x0b)
+#define CPM_CR_TIMER_SBLOCK	(0x0f)
+#define CPM_CR_RAND_SBLOCK	(0x0e)
+#define CPM_CR_FCC1_SBLOCK	(0x10)
+#define CPM_CR_FCC2_SBLOCK	(0x11)
+#define CPM_CR_FCC3_SBLOCK	(0x12)
+#define CPM_CR_IDMA1_SBLOCK	(0x14)
+#define CPM_CR_IDMA2_SBLOCK	(0x15)
+#define CPM_CR_IDMA3_SBLOCK	(0x16)
+#define CPM_CR_IDMA4_SBLOCK	(0x17)
+#define CPM_CR_MCC1_SBLOCK	(0x1c)
+
+#define CPM_CR_SCC1_PAGE	(0x00)
+#define CPM_CR_SCC2_PAGE	(0x01)
+#define CPM_CR_SCC3_PAGE	(0x02)
+#define CPM_CR_SCC4_PAGE	(0x03)
+#define CPM_CR_SMC1_PAGE	(0x07)
+#define CPM_CR_SMC2_PAGE	(0x08)
+#define CPM_CR_SPI_PAGE		(0x09)
+#define CPM_CR_I2C_PAGE		(0x0a)
+#define CPM_CR_TIMER_PAGE	(0x0a)
+#define CPM_CR_RAND_PAGE	(0x0a)
+#define CPM_CR_FCC1_PAGE	(0x04)
+#define CPM_CR_FCC2_PAGE	(0x05)
+#define CPM_CR_FCC3_PAGE	(0x06)
+#define CPM_CR_IDMA1_PAGE	(0x07)
+#define CPM_CR_IDMA2_PAGE	(0x08)
+#define CPM_CR_IDMA3_PAGE	(0x09)
+#define CPM_CR_IDMA4_PAGE	(0x0a)
+#define CPM_CR_MCC1_PAGE	(0x07)
+#define CPM_CR_MCC2_PAGE	(0x08)
+
+/* Some opcodes (there are more...later)
+*/
+#define CPM_CR_INIT_TRX		((ushort)0x0000)
+#define CPM_CR_INIT_RX		((ushort)0x0001)
+#define CPM_CR_INIT_TX		((ushort)0x0002)
+#define CPM_CR_HUNT_MODE	((ushort)0x0003)
+#define CPM_CR_STOP_TX		((ushort)0x0004)
+#define CPM_CR_RESTART_TX	((ushort)0x0006)
+#define CPM_CR_SET_GADDR	((ushort)0x0008)
+
+#define mk_cr_cmd(PG, SBC, MCN, OP) \
+	((PG << 26) | (SBC << 21) | (MCN << 6) | OP)
+
+/* Dual Port RAM addresses.  The first 16K is available for almost
+ * any CPM use, so we put the BDs there.  The first 128 bytes are
+ * used for SMC1 and SMC2 parameter RAM, so we start allocating
+ * BDs above that.  All of this must change when we start
+ * downloading RAM microcode.
+ */
+#define CPM_DATAONLY_BASE	((uint)128)
+#define CPM_DATAONLY_SIZE	((uint)(16 * 1024) - CPM_DATAONLY_BASE)
+#define CPM_DP_NOSPACE		((uint)0x7fffffff)
+
+/* The number of pages of host memory we allocate for CPM.  This is
+ * done early in kernel initialization to get physically contiguous
+ * pages.
+ */
+#define NUM_CPM_HOST_PAGES	2
+
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern	cpm8260_t	*cpmp;		/* Pointer to comm processor */
+uint		m8260_cpm_dpalloc(uint size);
+uint		m8260_cpm_hostalloc(uint size);
+void		m8260_cpm_setbrg(uint brg, uint rate);
+void		m8260_cpm_fastbrg(uint brg, uint rate, int div16);
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+	ushort	cbd_sc;		/* Status and Control */
+	ushort	cbd_datlen;	/* Data length in buffer */
+	uint	cbd_bufaddr;	/* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY	((ushort)0x8000)	/* Recieve is empty */
+#define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */
+#define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */
+#define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */
+#define BD_SC_LAST	((ushort)0x0800)	/* Last buffer in frame */
+#define BD_SC_CM	((ushort)0x0200)	/* Continous mode */
+#define BD_SC_ID	((ushort)0x0100)	/* Rec'd too many idles */
+#define BD_SC_P		((ushort)0x0100)	/* xmt preamble */
+#define BD_SC_BR	((ushort)0x0020)	/* Break received */
+#define BD_SC_FR	((ushort)0x0010)	/* Framing error */
+#define BD_SC_PR	((ushort)0x0008)	/* Parity error */
+#define BD_SC_OV	((ushort)0x0002)	/* Overrun */
+#define BD_SC_CD	((ushort)0x0001)	/* ?? */
+
+/* Parameter RAM offsets from the base.
+*/
+#define PROFF_SCC1		((uint)0x8000)
+#define PROFF_SCC2		((uint)0x8100)
+#define PROFF_SCC3		((uint)0x8200)
+#define PROFF_SCC4		((uint)0x8300)
+#define PROFF_FCC1		((uint)0x8400)
+#define PROFF_FCC2		((uint)0x8500)
+#define PROFF_FCC3		((uint)0x8600)
+#define PROFF_MCC1		((uint)0x8700)
+#define PROFF_SMC1_BASE		((uint)0x87fc)
+#define PROFF_IDMA1_BASE	((uint)0x87fe)
+#define PROFF_MCC2		((uint)0x8800)
+#define PROFF_SMC2_BASE		((uint)0x88fc)
+#define PROFF_IDMA2_BASE	((uint)0x88fe)
+#define PROFF_SPI_BASE		((uint)0x89fc)
+#define PROFF_IDMA3_BASE	((uint)0x89fe)
+#define PROFF_TIMERS		((uint)0x8ae0)
+#define PROFF_REVNUM		((uint)0x8af0)
+#define PROFF_RAND		((uint)0x8af8)
+#define PROFF_I2C_BASE		((uint)0x8afc)
+#define PROFF_IDMA4_BASE	((uint)0x89fe)
+
+/* The SMCs are relocated to any of the first eight DPRAM pages.
+ * We will fix these at the first locations of DPRAM, until we
+ * get some microcode patches :-).
+ * The parameter ram space for the SMCs is fifty-some bytes, and
+ * they are required to start on a 64 byte boundary.
+ */
+#define PROFF_SMC1	(0)
+#define PROFF_SMC2	(64)
+
+
+/* Define enough so I can at least use the serial port as a UART.
+ */
+typedef struct smc_uart {
+	ushort	smc_rbase;	/* Rx Buffer descriptor base address */
+	ushort	smc_tbase;	/* Tx Buffer descriptor base address */
+	u_char	smc_rfcr;	/* Rx function code */
+	u_char	smc_tfcr;	/* Tx function code */
+	ushort	smc_mrblr;	/* Max receive buffer length */
+	uint	smc_rstate;	/* Internal */
+	uint	smc_idp;	/* Internal */
+	ushort	smc_rbptr;	/* Internal */
+	ushort	smc_ibc;	/* Internal */
+	uint	smc_rxtmp;	/* Internal */
+	uint	smc_tstate;	/* Internal */
+	uint	smc_tdp;	/* Internal */
+	ushort	smc_tbptr;	/* Internal */
+	ushort	smc_tbc;	/* Internal */
+	uint	smc_txtmp;	/* Internal */
+	ushort	smc_maxidl;	/* Maximum idle characters */
+	ushort	smc_tmpidl;	/* Temporary idle counter */
+	ushort	smc_brklen;	/* Last received break length */
+	ushort	smc_brkec;	/* rcv'd break condition counter */
+	ushort	smc_brkcr;	/* xmt break count register */
+	ushort	smc_rmask;	/* Temporary bit mask */
+	uint	smc_stmp;	/* SDMA Temp */
+} smc_uart_t;
+
+/* Function code bits.
+*/
+#define SMC_GBL	((u_char)0x20)	/* Set memory snooping */
+#define SMC_EB	((u_char)0x10)	/* Set big endian byte order */
+#define SMC_TC2	((u_char)0x04)	/* Transfer code 2 value */
+#define SMC_DTB	((u_char)0x02)	/* Use local bus when set */
+
+/* SMC uart mode register (Internal memory map).
+*/
+#define	SMCMR_REN	((ushort)0x0001)
+#define SMCMR_TEN	((ushort)0x0002)
+#define SMCMR_DM	((ushort)0x000c)
+#define SMCMR_SM_GCI	((ushort)0x0000)
+#define SMCMR_SM_UART	((ushort)0x0020)
+#define SMCMR_SM_TRANS	((ushort)0x0030)
+#define SMCMR_SM_MASK	((ushort)0x0030)
+#define SMCMR_PM_EVEN	((ushort)0x0100)	/* Even parity, else odd */
+#define SMCMR_REVD	SMCMR_PM_EVEN
+#define SMCMR_PEN	((ushort)0x0200)	/* Parity enable */
+#define SMCMR_BS	SMCMR_PEN
+#define SMCMR_SL	((ushort)0x0400)	/* Two stops, else one */
+#define SMCR_CLEN_MASK	((ushort)0x7800)	/* Character length */
+#define smcr_mk_clen(C)	(((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC Event and Mask register.
+*/
+#define	SMCM_TXE	((unsigned char)0x10)
+#define	SMCM_BSY	((unsigned char)0x04)
+#define	SMCM_TX		((unsigned char)0x02)
+#define	SMCM_RX		((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST		((uint)0x00020000)
+#define CPM_BRG_EN		((uint)0x00010000)
+#define CPM_BRG_EXTC_INT	((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK3_9	((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK5_15	((uint)0x00008000)
+#define CPM_BRG_ATB		((uint)0x00002000)
+#define CPM_BRG_CD_MASK		((uint)0x00001ffe)
+#define CPM_BRG_DIV16		((uint)0x00000001)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP		((uint)0x00040000)
+#define SCC_GSMRH_GDE		((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT	((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC	((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC	((uint)0x00000000)
+#define SCC_GSMRH_REVD		((uint)0x00002000)
+#define SCC_GSMRH_TRX		((uint)0x00001000)
+#define SCC_GSMRH_TTX		((uint)0x00000800)
+#define SCC_GSMRH_CDP		((uint)0x00000400)
+#define SCC_GSMRH_CTSP		((uint)0x00000200)
+#define SCC_GSMRH_CDS		((uint)0x00000100)
+#define SCC_GSMRH_CTSS		((uint)0x00000080)
+#define SCC_GSMRH_TFL		((uint)0x00000040)
+#define SCC_GSMRH_RFW		((uint)0x00000020)
+#define SCC_GSMRH_TXSY		((uint)0x00000010)
+#define SCC_GSMRH_SYNL16	((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8		((uint)0x00000008)
+#define SCC_GSMRH_SYNL4		((uint)0x00000004)
+#define SCC_GSMRH_RTSM		((uint)0x00000002)
+#define SCC_GSMRH_RSYN		((uint)0x00000001)
+
+#define SCC_GSMRL_SIR		((uint)0x80000000)	/* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE	((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG	((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS	((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH	((uint)0x00000000)
+#define SCC_GSMRL_TCI		((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3	((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4	((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14	((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF	((uint)0x00000000)
+#define SCC_GSMRL_RINV		((uint)0x02000000)
+#define SCC_GSMRL_TINV		((uint)0x01000000)
+#define SCC_GSMRL_TPL_128	((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64	((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48	((uint)0x00800000)
+#define SCC_GSMRL_TPL_32	((uint)0x00600000)
+#define SCC_GSMRL_TPL_16	((uint)0x00400000)
+#define SCC_GSMRL_TPL_8		((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE	((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1	((uint)0x00180000)
+#define SCC_GSMRL_TPP_01	((uint)0x00100000)
+#define SCC_GSMRL_TPP_10	((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS	((uint)0x00000000)
+#define SCC_GSMRL_TEND		((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32	((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16	((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8	((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1	((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32	((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16	((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8	((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1	((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN	((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH	((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0	((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI	((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ	((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN	((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH	((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0	((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI	((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ	((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE	((uint)0x000000c0)	/* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO	((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP	((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM	((uint)0x00000000)
+#define SCC_GSMRL_ENR		((uint)0x00000020)
+#define SCC_GSMRL_ENT		((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET	((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP	((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC	((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14	((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC	((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS	((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART	((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7	((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK	((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC	((uint)0x00000000)
+
+#define SCC_TODR_TOD		((ushort)0x8000)
+
+/* SCC Event and Mask register.
+*/
+#define	SCCM_TXE	((unsigned char)0x10)
+#define	SCCM_BSY	((unsigned char)0x04)
+#define	SCCM_TX		((unsigned char)0x02)
+#define	SCCM_RX		((unsigned char)0x01)
+
+typedef struct scc_param {
+	ushort	scc_rbase;	/* Rx Buffer descriptor base address */
+	ushort	scc_tbase;	/* Tx Buffer descriptor base address */
+	u_char	scc_rfcr;	/* Rx function code */
+	u_char	scc_tfcr;	/* Tx function code */
+	ushort	scc_mrblr;	/* Max receive buffer length */
+	uint	scc_rstate;	/* Internal */
+	uint	scc_idp;	/* Internal */
+	ushort	scc_rbptr;	/* Internal */
+	ushort	scc_ibc;	/* Internal */
+	uint	scc_rxtmp;	/* Internal */
+	uint	scc_tstate;	/* Internal */
+	uint	scc_tdp;	/* Internal */
+	ushort	scc_tbptr;	/* Internal */
+	ushort	scc_tbc;	/* Internal */
+	uint	scc_txtmp;	/* Internal */
+	uint	scc_rcrc;	/* Internal */
+	uint	scc_tcrc;	/* Internal */
+} sccp_t;
+
+/* Function code bits.
+*/
+#define SCC_EB	((u_char)0x10)	/* Set big endian byte order */
+
+/* CPM Ethernet through SCC1.
+ */
+typedef struct scc_enet {
+	sccp_t	sen_genscc;
+	uint	sen_cpres;	/* Preset CRC */
+	uint	sen_cmask;	/* Constant mask for CRC */
+	uint	sen_crcec;	/* CRC Error counter */
+	uint	sen_alec;	/* alignment error counter */
+	uint	sen_disfc;	/* discard frame counter */
+	ushort	sen_pads;	/* Tx short frame pad character */
+	ushort	sen_retlim;	/* Retry limit threshold */
+	ushort	sen_retcnt;	/* Retry limit counter */
+	ushort	sen_maxflr;	/* maximum frame length register */
+	ushort	sen_minflr;	/* minimum frame length register */
+	ushort	sen_maxd1;	/* maximum DMA1 length */
+	ushort	sen_maxd2;	/* maximum DMA2 length */
+	ushort	sen_maxd;	/* Rx max DMA */
+	ushort	sen_dmacnt;	/* Rx DMA counter */
+	ushort	sen_maxb;	/* Max BD byte count */
+	ushort	sen_gaddr1;	/* Group address filter */
+	ushort	sen_gaddr2;
+	ushort	sen_gaddr3;
+	ushort	sen_gaddr4;
+	uint	sen_tbuf0data0;	/* Save area 0 - current frame */
+	uint	sen_tbuf0data1;	/* Save area 1 - current frame */
+	uint	sen_tbuf0rba;	/* Internal */
+	uint	sen_tbuf0crc;	/* Internal */
+	ushort	sen_tbuf0bcnt;	/* Internal */
+	ushort	sen_paddrh;	/* physical address (MSB) */
+	ushort	sen_paddrm;
+	ushort	sen_paddrl;	/* physical address (LSB) */
+	ushort	sen_pper;	/* persistence */
+	ushort	sen_rfbdptr;	/* Rx first BD pointer */
+	ushort	sen_tfbdptr;	/* Tx first BD pointer */
+	ushort	sen_tlbdptr;	/* Tx last BD pointer */
+	uint	sen_tbuf1data0;	/* Save area 0 - current frame */
+	uint	sen_tbuf1data1;	/* Save area 1 - current frame */
+	uint	sen_tbuf1rba;	/* Internal */
+	uint	sen_tbuf1crc;	/* Internal */
+	ushort	sen_tbuf1bcnt;	/* Internal */
+	ushort	sen_txlen;	/* Tx Frame length counter */
+	ushort	sen_iaddr1;	/* Individual address filter */
+	ushort	sen_iaddr2;
+	ushort	sen_iaddr3;
+	ushort	sen_iaddr4;
+	ushort	sen_boffcnt;	/* Backoff counter */
+
+	/* NOTE: Some versions of the manual have the following items
+	 * incorrectly documented.  Below is the proper order.
+	 */
+	ushort	sen_taddrh;	/* temp address (MSB) */
+	ushort	sen_taddrm;
+	ushort	sen_taddrl;	/* temp address (LSB) */
+} scc_enet_t;
+
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA	((ushort)0x0080)	/* Graceful stop complete */
+#define SCCE_ENET_TXE	((ushort)0x0010)	/* Transmit Error */
+#define SCCE_ENET_RXF	((ushort)0x0008)	/* Full frame received */
+#define SCCE_ENET_BSY	((ushort)0x0004)	/* All incoming buffers full */
+#define SCCE_ENET_TXB	((ushort)0x0002)	/* A buffer was transmitted */
+#define SCCE_ENET_RXB	((ushort)0x0001)	/* A buffer was received */
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_HBC	((ushort)0x8000)	/* Enable heartbeat */
+#define SCC_PMSR_FC	((ushort)0x4000)	/* Force collision */
+#define SCC_PMSR_RSH	((ushort)0x2000)	/* Receive short frames */
+#define SCC_PMSR_IAM	((ushort)0x1000)	/* Check individual hash */
+#define SCC_PMSR_ENCRC	((ushort)0x0800)	/* Ethernet CRC mode */
+#define SCC_PMSR_PRO	((ushort)0x0200)	/* Promiscuous mode */
+#define SCC_PMSR_BRO	((ushort)0x0100)	/* Catch broadcast pkts */
+#define SCC_PMSR_SBT	((ushort)0x0080)	/* Special backoff timer */
+#define SCC_PMSR_LPB	((ushort)0x0040)	/* Set Loopback mode */
+#define SCC_PMSR_SIP	((ushort)0x0020)	/* Sample Input Pins */
+#define SCC_PMSR_LCW	((ushort)0x0010)	/* Late collision window */
+#define SCC_PMSR_NIB22	((ushort)0x000a)	/* Start frame search */
+#define SCC_PMSR_FDE	((ushort)0x0001)	/* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY	((ushort)0x8000)
+#define BD_ENET_RX_WRAP		((ushort)0x2000)
+#define BD_ENET_RX_INTR		((ushort)0x1000)
+#define BD_ENET_RX_LAST		((ushort)0x0800)
+#define BD_ENET_RX_FIRST	((ushort)0x0400)
+#define BD_ENET_RX_MISS		((ushort)0x0100)
+#define BD_ENET_RX_LG		((ushort)0x0020)
+#define BD_ENET_RX_NO		((ushort)0x0010)
+#define BD_ENET_RX_SH		((ushort)0x0008)
+#define BD_ENET_RX_CR		((ushort)0x0004)
+#define BD_ENET_RX_OV		((ushort)0x0002)
+#define BD_ENET_RX_CL		((ushort)0x0001)
+#define BD_ENET_RX_STATS	((ushort)0x013f)	/* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY	((ushort)0x8000)
+#define BD_ENET_TX_PAD		((ushort)0x4000)
+#define BD_ENET_TX_WRAP		((ushort)0x2000)
+#define BD_ENET_TX_INTR		((ushort)0x1000)
+#define BD_ENET_TX_LAST		((ushort)0x0800)
+#define BD_ENET_TX_TC		((ushort)0x0400)
+#define BD_ENET_TX_DEF		((ushort)0x0200)
+#define BD_ENET_TX_HB		((ushort)0x0100)
+#define BD_ENET_TX_LC		((ushort)0x0080)
+#define BD_ENET_TX_RL		((ushort)0x0040)
+#define BD_ENET_TX_RCMASK	((ushort)0x003c)
+#define BD_ENET_TX_UN		((ushort)0x0002)
+#define BD_ENET_TX_CSL		((ushort)0x0001)
+#define BD_ENET_TX_STATS	((ushort)0x03ff)	/* All status bits */
+
+/* SCC as UART
+*/
+typedef struct scc_uart {
+	sccp_t	scc_genscc;
+	uint	scc_res1;	/* Reserved */
+	uint	scc_res2;	/* Reserved */
+	ushort	scc_maxidl;	/* Maximum idle chars */
+	ushort	scc_idlc;	/* temp idle counter */
+	ushort	scc_brkcr;	/* Break count register */
+	ushort	scc_parec;	/* receive parity error counter */
+	ushort	scc_frmec;	/* receive framing error counter */
+	ushort	scc_nosec;	/* receive noise counter */
+	ushort	scc_brkec;	/* receive break condition counter */
+	ushort	scc_brkln;	/* last received break length */
+	ushort	scc_uaddr1;	/* UART address character 1 */
+	ushort	scc_uaddr2;	/* UART address character 2 */
+	ushort	scc_rtemp;	/* Temp storage */
+	ushort	scc_toseq;	/* Transmit out of sequence char */
+	ushort	scc_char1;	/* control character 1 */
+	ushort	scc_char2;	/* control character 2 */
+	ushort	scc_char3;	/* control character 3 */
+	ushort	scc_char4;	/* control character 4 */
+	ushort	scc_char5;	/* control character 5 */
+	ushort	scc_char6;	/* control character 6 */
+	ushort	scc_char7;	/* control character 7 */
+	ushort	scc_char8;	/* control character 8 */
+	ushort	scc_rccm;	/* receive control character mask */
+	ushort	scc_rccr;	/* receive control character register */
+	ushort	scc_rlbc;	/* receive last break character */
+} scc_uart_t;
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR		((ushort)0x1000)
+#define UART_SCCM_GLT		((ushort)0x0800)
+#define UART_SCCM_AB		((ushort)0x0200)
+#define UART_SCCM_IDL		((ushort)0x0100)
+#define UART_SCCM_GRA		((ushort)0x0080)
+#define UART_SCCM_BRKE		((ushort)0x0040)
+#define UART_SCCM_BRKS		((ushort)0x0020)
+#define UART_SCCM_CCR		((ushort)0x0008)
+#define UART_SCCM_BSY		((ushort)0x0004)
+#define UART_SCCM_TX		((ushort)0x0002)
+#define UART_SCCM_RX		((ushort)0x0001)
+
+/* The SCC PMSR when used as a UART.
+*/
+#define SCU_PMSR_FLC		((ushort)0x8000)
+#define SCU_PMSR_SL		((ushort)0x4000)
+#define SCU_PMSR_CL		((ushort)0x3000)
+#define SCU_PMSR_UM		((ushort)0x0c00)
+#define SCU_PMSR_FRZ		((ushort)0x0200)
+#define SCU_PMSR_RZS		((ushort)0x0100)
+#define SCU_PMSR_SYN		((ushort)0x0080)
+#define SCU_PMSR_DRT		((ushort)0x0040)
+#define SCU_PMSR_PEN		((ushort)0x0010)
+#define SCU_PMSR_RPM		((ushort)0x000c)
+#define SCU_PMSR_REVP		((ushort)0x0008)
+#define SCU_PMSR_TPM		((ushort)0x0003)
+#define SCU_PMSR_TEVP		((ushort)0x0003)
+
+/* CPM Transparent mode SCC.
+ */
+typedef struct scc_trans {
+	sccp_t	st_genscc;
+	uint	st_cpres;	/* Preset CRC */
+	uint	st_cmask;	/* Constant mask for CRC */
+} scc_trans_t;
+
+#define BD_SCC_TX_LAST		((ushort)0x0800)
+
+/* IIC parameter RAM.
+*/
+typedef struct iic {
+	ushort	iic_rbase;	/* Rx Buffer descriptor base address */
+	ushort	iic_tbase;	/* Tx Buffer descriptor base address */
+	u_char	iic_rfcr;	/* Rx function code */
+	u_char	iic_tfcr;	/* Tx function code */
+	ushort	iic_mrblr;	/* Max receive buffer length */
+	uint	iic_rstate;	/* Internal */
+	uint	iic_rdp;	/* Internal */
+	ushort	iic_rbptr;	/* Internal */
+	ushort	iic_rbc;	/* Internal */
+	uint	iic_rxtmp;	/* Internal */
+	uint	iic_tstate;	/* Internal */
+	uint	iic_tdp;	/* Internal */
+	ushort	iic_tbptr;	/* Internal */
+	ushort	iic_tbc;	/* Internal */
+	uint	iic_txtmp;	/* Internal */
+} iic_t;
+
+#define BD_IIC_START		((ushort)0x0400)
+
+#endif /* __CPM_82XX__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/est8260.h linux/include/asm-ppc/est8260.h
--- v2.3.99-pre6/linux/include/asm-ppc/est8260.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/est8260.h	Tue May  2 13:05:40 2000
@@ -0,0 +1,20 @@
+
+#define IMAP_ADDR	((uint)0xf0000000)
+
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in MHz */
+	unsigned int	bi_cpmfreq;	/* CPM Freq, in MHz */
+	unsigned int	bi_brgfreq;	/* BRG Freq, in MHz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- v2.3.99-pre6/linux/include/asm-ppc/feature.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ppc/feature.h	Tue May  2 13:05:40 2000
@@ -32,8 +32,8 @@
 	FEATURE_Mediabay_reset,
 	FEATURE_Mediabay_power,
 	FEATURE_Mediabay_PCI_enable,
-	FEATURE_Mediabay_IDE_enable,	/* Also IDE 1 */
-	FEATURE_Mediabay_IDE_reset,	/* Also IDE 1 */
+	FEATURE_IDE1_enable,		/* MediaBay IDE */
+	FEATURE_IDE1_reset,		/* MediaBay IDE */
 	FEATURE_Mediabay_floppy_enable,
 	FEATURE_BMac_reset,
 	FEATURE_BMac_IO_enable,
@@ -43,6 +43,8 @@
 	FEATURE_Sound_CLK_enable,
 	FEATURE_IDE2_enable,
 	FEATURE_IDE2_reset,
+	FEATURE_Mediabay_IDE_switch,	/* MB IDE bus switch */
+	FEATURE_Mediabay_content,	/* MB content indicator enable */
 	FEATURE_last,
 };
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/gemini_serial.h linux/include/asm-ppc/gemini_serial.h
--- v2.3.99-pre6/linux/include/asm-ppc/gemini_serial.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/gemini_serial.h	Tue May  2 13:05:40 2000
@@ -14,10 +14,10 @@
 #define BASE_BAUD  (24576000 / 16)
 
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
 #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST)
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
 #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
 #endif
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/heathrow.h linux/include/asm-ppc/heathrow.h
--- v2.3.99-pre6/linux/include/asm-ppc/heathrow.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ppc/heathrow.h	Tue May  2 13:05:40 2000
@@ -13,7 +13,7 @@
  * Bits in feature control register.
  * Bits postfixed with a _N are in inverse logic
  */
-#define HRW_RESET_SCC		1		/* Named in_use_led in OF ??? */
+#define HRW_MODEM_POWER_N	1		/* turns off modem power */
 #define HRW_BAY_POWER_N		2
 #define HRW_BAY_PCI_ENABLE	4
 #define HRW_BAY_IDE_ENABLE	8
@@ -38,8 +38,11 @@
 #define HRW_ARB_BYPASS		0x400000	/* ??? (0 on main, 1 on gatwick) */
 #define HRW_IDE1_RESET_N	0x800000	/* Media bay */
 #define HRW_SLOW_SCC_PCLK	0x1000000	/* ??? (0) */
-#define HRW_MODEM_POWER_N	0x2000000	/* Used by internal modem on wallstreet */
+#define HRW_RESET_SCC		0x2000000	/* perhaps? */
 #define HRW_MFDC_CELL_ENABLE	0x4000000	/* ??? (0) */
 #define HRW_USE_MFDC		0x8000000	/* ??? (0) */
 #define HRW_BMAC_IO_ENABLE	0x60000000	/* two bits, not documented in OF */
 #define HRW_BMAC_RESET		0x80000000	/* not documented in OF */
+
+
+#define PADD_MODEM_POWER_N	0x00000001	/* modem power on paddington */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.3.99-pre6/linux/include/asm-ppc/ide.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/ide.h	Tue May  2 13:05:40 2000
@@ -63,6 +63,7 @@
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
+#if 0
 #undef insw
 #define insw(port, buf, ns) 	do {				\
 	ppc_ide_md.insw((port), (buf), (ns));			\
@@ -72,6 +73,7 @@
 #define outsw(port, buf, ns) 	do {				\
 	ppc_ide_md.outsw((port), (buf), (ns));			\
 } while (0)
+#endif
 
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/immap_8260.h linux/include/asm-ppc/immap_8260.h
--- v2.3.99-pre6/linux/include/asm-ppc/immap_8260.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/immap_8260.h	Tue May  2 13:05:40 2000
@@ -0,0 +1,433 @@
+
+/*
+ * MPC8260 Internal Memory Map
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ *
+ * The Internal Memory Map of the 8260.  I don't know how generic
+ * this will be, as I don't have any knowledge of the subsequent
+ * parts at this time.  I copied this from the 8xx_immap.h.
+ */
+#ifndef __IMMAP_82XX__
+#define __IMMAP_82XX__
+
+/* System configuration registers.
+*/
+typedef	struct sys_conf {
+	uint	sc_siumcr;
+	uint	sc_sypcr;
+	char	res1[6];
+	ushort	sc_swsr;
+	char	res2[20];
+	uint	sc_bcr;
+	u_char	sc_ppc_acr;
+	char	res3[3];
+	uint	sc_ppc_alrh;
+	uint	sc_ppc_alrl;
+	u_char	sc_lcl_acr;
+	char	res4[3];
+	uint	sc_lcl_alrh;
+	uint	sc_lcl_alrl;
+	uint	sc_tescr1;
+	uint	sc_tescr2;
+	uint	sc_ltescr1;
+	uint	sc_ltescr2;
+	uint	sc_pdtea;
+	u_char	sc_pdtem;
+	char	res5[3];
+	uint	sc_ldtea;
+	u_char	sc_ldtem;
+	char	res6[163];
+} sysconf8260_t;
+
+
+/* Memory controller registers.
+*/
+typedef struct	mem_ctlr {
+	uint	memc_br0;
+	uint	memc_or0;
+	uint	memc_br1;
+	uint	memc_or1;
+	uint	memc_br2;
+	uint	memc_or2;
+	uint	memc_br3;
+	uint	memc_or3;
+	uint	memc_br4;
+	uint	memc_or4;
+	uint	memc_br5;
+	uint	memc_or5;
+	uint	memc_br6;
+	uint	memc_or6;
+	uint	memc_br7;
+	uint	memc_or7;
+	uint	memc_br8;
+	uint	memc_or8;
+	uint	memc_br9;
+	uint	memc_or9;
+	uint	memc_br10;
+	uint	memc_or10;
+	uint	memc_br11;
+	uint	memc_or11;
+	char	res1[8];
+	uint	memc_mar;
+	char	res2[4];
+	uint	memc_mamr;
+	uint	memc_mbmr;
+	uint	memc_mcmr;
+	char	res3[8];
+	ushort	memc_mptpr;
+	char	res4[2];
+	uint	memc_mdr;
+	char	res5[4];
+	uint	memc_psdmr;
+	uint	memc_lsdmr;
+	u_char	memc_purt;
+	char	res6[3];
+	u_char	memc_psrt;
+	char	res7[3];
+	u_char	memc_lurt;
+	char	res8[3];
+	u_char	memc_lsrt;
+	char	res9[3];
+	uint	memc_immr;
+	char	res10[84];
+} memctl8260_t;
+
+/* System Integration Timers.
+*/
+typedef struct	sys_int_timers {
+	char	res1[32];
+	ushort	sit_tmcntsc;
+	char	res2[2];
+	uint	sit_tmcnt;
+	char	res3[4];
+	uint	sit_tmcntal;
+	char	res4[16];
+	ushort	sit_piscr;
+	char	res5[2];
+	uint	sit_pitc;
+	uint	sit_pitr;
+	char	res6[94];
+	char	res7[2390];
+} sit8260_t;
+
+#define PISCR_PIRQ_MASK		((ushort)0xff00)
+#define PISCR_PS		((ushort)0x0080)
+#define PISCR_PIE		((ushort)0x0004)
+#define PISCR_PTF		((ushort)0x0002)
+#define PISCR_PTE		((ushort)0x0001)
+
+/* Interrupt Controller.
+*/
+typedef struct interrupt_controller {
+	ushort	ic_sicr;
+	char	res1[2];
+	uint	ic_sivec;
+	uint	ic_sipnrh;
+	uint	ic_sipnrl;
+	uint	ic_siprr;
+	uint	ic_scprrh;
+	uint	ic_scprrl;
+	uint	ic_simrh;
+	uint	ic_simrl;
+	uint	ic_siexr;
+	char	res2[88];
+} intctl8260_t;
+
+/* Clocks and Reset.
+*/
+typedef struct clk_and_reset {
+	uint	car_sccr;
+	char	res1[4];
+	uint	car_scmr;
+	char	res2[4];
+	uint	car_rsr;
+	uint	car_rmr;
+	char	res[104];
+} car8260_t;
+
+/* Input/Output Port control/status registers.
+ * Names consistent with processor manual, although they are different
+ * from the original 8xx names.......
+ */
+typedef struct io_port {
+	uint	iop_pdira;
+	uint	iop_ppara;
+	uint	iop_psora;
+	uint	iop_podra;
+	uint	iop_pdata;
+	char	res1[12];
+	uint	iop_pdirb;
+	uint	iop_pparb;
+	uint	iop_psorb;
+	uint	iop_podrb;
+	uint	iop_pdatb;
+	char	res2[12];
+	uint	iop_pdirc;
+	uint	iop_pparc;
+	uint	iop_psorc;
+	uint	iop_podrc;
+	uint	iop_pdatc;
+	char	res3[12];
+	uint	iop_pdird;
+	uint	iop_ppard;
+	uint	iop_psord;
+	uint	iop_podrd;
+	uint	iop_pdatd;
+	char	res4[12];
+} iop8260_t;
+
+/* Communication Processor Module Timers
+*/
+typedef struct cpm_timers {
+	u_char	cpmt_tgcr1;
+	char	res1[3];
+	u_char	cpmt_tgcr2;
+	char	res2[11];
+	ushort	cpmt_tmr1;
+	ushort	cpmt_tmr2;
+	ushort	cpmt_trr1;
+	ushort	cpmt_trr2;
+	ushort	cpmt_tcr1;
+	ushort	cpmt_tcr2;
+	ushort	cpmt_tcn1;
+	ushort	cpmt_tcn2;
+	ushort	cpmt_tmr3;
+	ushort	cpmt_tmr4;
+	ushort	cpmt_trr3;
+	ushort	cpmt_trr4;
+	ushort	cpmt_tcr3;
+	ushort	cpmt_tcr4;
+	ushort	cpmt_tcn3;
+	ushort	cpmt_tcn4;
+	ushort	cpmt_ter1;
+	ushort	cpmt_ter2;
+	ushort	cpmt_ter3;
+	ushort	cpmt_ter4;
+	char	res3[584];
+} cpmtimer8260_t;
+
+/* DMA control/status registers.
+*/
+typedef struct sdma_csr {
+	char	res0[24];
+	u_char	sdma_sdsr;
+	char	res1[3];
+	u_char	sdma_sdmr;
+	char	res2[3];
+	u_char	sdma_idsr1;
+	char	res3[3];
+	u_char	sdma_idmr1;
+	char	res4[3];
+	u_char	sdma_idsr2;
+	char	res5[3];
+	u_char	sdma_idmr2;
+	char	res6[3];
+	u_char	sdma_idsr3;
+	char	res7[3];
+	u_char	sdma_idmr3;
+	char	res8[3];
+	u_char	sdma_idsr4;
+	char	res9[3];
+	u_char	sdma_idmr4;
+	char	res10[707];
+} sdma8260_t;
+
+/* Fast controllers
+*/
+typedef struct fcc {
+	uint	fcc_gfmr;
+	uint	fcc_fpsmr;
+	ushort	fcc_ftodr;
+	char	res1[2];
+	ushort	fcc_fdsr;
+	char	res2[2];
+	uint	fcc_fcce;
+	uint	fcc_fccm;
+	u_char	fcc_fccs;
+	char	res3[3];
+	u_char	fcc_ftirr_phy[4];
+} fcc_t;
+
+/* I2C
+*/
+typedef struct i2c {
+	u_char	i2c_i2mod;
+	char	res1[3];
+	u_char	i2c_i2add;
+	char	res2[3];
+	u_char	i2c_i2brg;
+	char	res3[3];
+	u_char	i2c_i2com;
+	char	res4[3];
+	u_char	i2c_i2cer;
+	char	res5[3];
+	u_char	i2c_i2cmr;
+	char	res6[331];
+} i2c8260_t;
+
+typedef struct scc {		/* Serial communication channels */
+	uint	scc_gsmrl;
+	uint	scc_gsmrh;
+	ushort	scc_pmsr;
+	char	res1[2];
+	ushort	scc_todr;
+	ushort	scc_dsr;
+	ushort	scc_scce;
+	char	res2[2];
+	ushort	scc_sccm;
+	char	res3;
+	u_char	scc_sccs;
+	char	res4[8];
+} scc_t;
+
+typedef struct smc {		/* Serial management channels */
+	char	res1[2];
+	ushort	smc_smcmr;
+	char	res2[2];
+	u_char	smc_smce;
+	char	res3[3];
+	u_char	smc_smcm;
+	char	res4[5];
+} smc_t;
+
+/* Serial Peripheral Interface.
+*/
+typedef struct spi {
+	ushort	spi_spmode;
+	char	res1[4];
+	u_char	spi_spie;
+	char	res2[3];
+	u_char	spi_spim;
+	char	res3[2];
+	u_char	spi_spcom;
+	char	res4[82];
+} spi_t;
+
+/* CPM Mux.
+*/
+typedef struct cpmux {
+	u_char	cmx_si1cr;
+	char	res1;
+	u_char	cmx_si2cr;
+	char	res2;
+	uint	cmx_fcr;
+	uint	cmx_scr;
+	u_char	cmx_smr;
+	char	res3;
+	ushort	cmx_uar;
+	char	res4[16];
+} cpmux_t;
+
+/* SIRAM control
+*/
+typedef struct siram {
+	ushort	si_amr;
+	ushort	si_bmr;
+	ushort	si_cmr;
+	ushort	si_dmr;
+	u_char	si_gmr;
+	char	res1;
+	u_char	si_cmdr;
+	char	res2;
+	u_char	si_str;
+	char	res3;
+	ushort	si_rsr;
+} siramctl_t;
+
+typedef struct mcc {
+	ushort	mcc_mcce;
+	char	res1[2];
+	ushort	mcc_mccm;
+	char	res2[2];
+	u_char	mcc_mccf;
+	char	res3[7];
+} mcc_t;
+
+typedef struct comm_proc {
+	uint	cp_cpcr;
+	uint	cp_rccr;
+	char	res1[14];
+	ushort	cp_rter;
+	char	res2[2];
+	ushort	cp_rtmr;
+	ushort	cp_rtscr;
+	char	res3[2];
+	uint	cp_rtsr;
+	char	res4[12];
+} cpm8260_t;
+
+/* ...and the whole thing wrapped up....
+*/
+typedef struct immap {
+	/* Some references are into the unique and known dpram spaces,
+	 * others are from the generic base.
+	 */
+#define im_dprambase	im_dpram1
+	u_char		im_dpram1[16*1024];
+	char		res1[16*1024];
+	u_char		im_dpram2[4*1024];
+	char		res2[8*1024];
+	u_char		im_dpram3[4*1024];
+	char		res3[16*1024];
+
+	sysconf8260_t	im_siu_conf;	/* SIU Configuration */
+	memctl8260_t	im_memctl;	/* Memory Controller */
+	sit8260_t	im_sit;		/* System Integration Timers */
+	intctl8260_t	im_intctl;	/* Interrupt Controller */
+	car8260_t	im_clkrst;	/* Clocks and reset */
+	iop8260_t	im_ioport;	/* IO Port control/status */
+	cpmtimer8260_t	im_cpmtimer;	/* CPM timers */
+	sdma8260_t	im_sdma;	/* SDMA control/status */
+
+	fcc_t		im_fcc[3];	/* Three FCCs */
+
+	char		res4[159];
+
+	/* First set of baud rate generators.
+	*/
+	char		res4a[496];
+	uint		im_brgc5;
+	uint		im_brgc6;
+	uint		im_brgc7;
+	uint		im_brgc8;
+
+	char		res5[608];
+
+	i2c8260_t	im_i2c;		/* I2C control/status */
+	cpm8260_t	im_cpm;		/* Communication processor */
+
+	/* Second set of baud rate generators.
+	*/
+	uint		im_brgc1;
+	uint		im_brgc2;
+	uint		im_brgc3;
+	uint		im_brgc4;
+
+	scc_t		im_scc[4];	/* Four SCCs */
+	smc_t		im_smc[2];	/* Couple of SMCs */
+	spi_t		im_spi;		/* A SPI */
+	cpmux_t		im_cpmux;	/* CPM clock route mux */
+	siramctl_t	im_siramctl1;	/* First SI RAM Control */
+	mcc_t		im_mcc1;	/* First MCC */
+	siramctl_t	im_siramctl2;	/* Second SI RAM Control */
+	mcc_t		im_mcc2;	/* Second MCC */
+
+	char		res6[1184];
+
+	ushort		im_si1txram[256];
+	char		res7[512];
+	ushort		im_si1rxram[256];
+	char		res8[512];
+	ushort		im_si2txram[256];
+	char		res9[512];
+	ushort		im_si2rxram[256];
+	char		res10[512];
+	char		res11[4096];
+} immap_t;
+
+/* The 8260 relies heavily on the IMMR, so we keep it around as a
+ * kernel global symbol now.  Should have done this for the 8xx......
+ */
+immap_t	*immr;
+
+#endif /* __IMMAP_82XX__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.3.99-pre6/linux/include/asm-ppc/io.h	Sat Feb 26 22:31:58 2000
+++ linux/include/asm-ppc/io.h	Tue May  2 13:05:40 2000
@@ -23,6 +23,8 @@
 #include <asm/board.h>
 #elif defined(CONFIG_8xx)
 #include <asm/mpc8xx.h>
+#elif defined(CONFIG_8260)
+#include <asm/mpc8260.h>
 #else
 #ifdef CONFIG_APUS
 #define _IO_BASE 0
@@ -52,12 +54,18 @@
 #define writel(b,addr) out_le32((volatile u32 *)(addr),(b))
 #endif
 
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case.  - paulus
+ */
 #define insb(port, buf, ns)	_insb((u8 *)((port)+_IO_BASE), (buf), (ns))
 #define outsb(port, buf, ns)	_outsb((u8 *)((port)+_IO_BASE), (buf), (ns))
-#define insw(port, buf, ns)	_insw((u16 *)((port)+_IO_BASE), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw((u16 *)((port)+_IO_BASE), (buf), (ns))
-#define insl(port, buf, nl)	_insl((u32 *)((port)+_IO_BASE), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define insw(port, buf, ns)	_insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl)	_insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
 
 #define inb(port)		in_8((u8 *)((port)+_IO_BASE))
 #define outb(val, port)		out_8((u8 *)((port)+_IO_BASE), (val))
@@ -86,19 +94,21 @@
 extern void _outsw(volatile u16 *port, const void *buf, int ns);
 extern void _insl(volatile u32 *port, void *buf, int nl);
 extern void _outsl(volatile u32 *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
 
 /*
  * The *_ns versions below don't do byte-swapping.
+ * Neither do the standard versions now, these are just here
+ * for older code.
  */
 #define insw_ns(port, buf, ns)	_insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
 #define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
 #define insl_ns(port, buf, nl)	_insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
 #define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
 
-extern void _insw_ns(volatile u16 *port, void *buf, int ns);
-extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
-extern void _insl_ns(volatile u32 *port, void *buf, int nl);
-extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
 
 #define IO_SPACE_LIMIT ~0
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.3.99-pre6/linux/include/asm-ppc/irq.h	Sat Feb 26 22:31:58 2000
+++ linux/include/asm-ppc/irq.h	Tue May  2 13:05:40 2000
@@ -57,21 +57,15 @@
  * There are eight external interrupts (IRQs) that can be configured
  * as either level or edge sensitive. 
  *
- * The 82xx can have up to 64 interrupts on the internal controller.
- *
  * On some implementations, there is also the possibility of an 8259
  * through the PCI and PCI-ISA bridges.
  */
-#ifdef CONFIG_82xx
-#define NR_SIU_INTS	64
-#else
 #define NR_SIU_INTS	16
-#endif
 
 #define NR_IRQS	(NR_SIU_INTS + NR_8259_INTS)
 
 /* These values must be zero-based and map 1:1 with the SIU configuration.
- * They are used throughout the 8xx/82xx I/O subsystem to generate
+ * They are used throughout the 8xx I/O subsystem to generate
  * interrupt masks, flags, and other control patterns.  This is why the
  * current kernel assumption of the 8259 as the base controller is such
  * a pain in the butt.
@@ -166,10 +160,36 @@
  */
 #define NR_IRQS			256
 
+#ifndef CONFIG_8260
+
 #define NUM_8259_INTERRUPTS	16
 #define IRQ_8259_CASCADE	16
 #define openpic_to_irq(n)	((n)+NUM_8259_INTERRUPTS)
 #define irq_to_openpic(n)	((n)-NUM_8259_INTERRUPTS)
+
+#else /* CONFIG_8260 */
+
+/* The 8260 has an internal interrupt controller with a maximum of
+ * 64 IRQs.  We will use NR_IRQs from above since it is large enough.
+ * Don't be confused by the 8260 documentation where they list an
+ * "interrupt number" and "interrupt vector".  We are only interested
+ * in the interrupt vector.  There are "reserved" holes where the
+ * vector number increases, but the interrupt number in the table does not.
+ * (Document errata updates have fixed this...make sure you have up to
+ * date processor documentation -- Dan).
+ */
+#define NR_SIU_INTS	64
+
+/* There are many more than these, we will add them as we need them.
+*/
+#define	SIU_INT_SMC1		((uint)0x04)
+#define	SIU_INT_SMC2		((uint)0x05)
+#define	SIU_INT_SCC1		((uint)0x28)
+#define	SIU_INT_SCC2		((uint)0x29)
+#define	SIU_INT_SCC3		((uint)0x2a)
+#define	SIU_INT_SCC4		((uint)0x2b)
+
+#endif /* CONFIG_8260 */
 
 /*
  * This gets called from serial.c, which is now used on
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/mpc8260.h linux/include/asm-ppc/mpc8260.h
--- v2.3.99-pre6/linux/include/asm-ppc/mpc8260.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/mpc8260.h	Wed May  3 01:47:57 2000
@@ -0,0 +1,42 @@
+
+/* This is the single file included by all MPC8260 build options.
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each.  Rather than change every
+ * file that has to include MPC8260 configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifndef __CONFIG_8260_DEFS
+#define __CONFIG_8260_DEFS
+
+#include <linux/config.h>
+
+#ifdef CONFIG_8260
+
+#ifdef CONFIG_EST8260
+#include <asm/est8260.h>
+#endif
+
+/* I don't yet have the ISA or PCI stuff done....no 8260 with
+ * such thing.....
+ */
+#define _IO_BASE        0
+#define _ISA_MEM_BASE   0
+#define PCI_DRAM_OFFSET 0
+
+/* The "residual" data board information structure the boot loader
+ * hands to us.
+ */
+extern unsigned char __res[];
+
+/* I need this to get pt_regs.......
+*/
+#include <asm/ptrace.h>
+
+extern int request_8xxirq(unsigned int irq,
+		       void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flags, 
+		       const char *device,
+		       void *dev_id);
+
+#endif /* CONFIG_8260 */
+#endif
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h
--- v2.3.99-pre6/linux/include/asm-ppc/nvram.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-ppc/nvram.h	Tue May  2 13:05:40 2000
@@ -30,4 +30,30 @@
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
 
+/* PowerMac specific nvram stuffs */
+
+enum {
+	pmac_nvram_OF,		/* Open Firmware partition */
+	pmac_nvram_XPRAM,	/* MacOS XPRAM partition */
+	pmac_nvram_NR		/* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int	pmac_get_partition(int partition);
+
+/* Direct access to XPRAM */
+extern u8	pmac_xpram_read(int xpaddr);
+extern void	pmac_xpram_write(int xpaddr, u8 data);
+
+/* Some offsets in XPRAM */
+#define PMAC_XPRAM_MACHINE_LOC	0xe4
+#define PMAC_XPRAM_SOUND_VOLUME	0x08
+
+/* Machine location structure in XPRAM */
+struct pmac_machine_location {
+	u32	latitude;	/* 2+30 bit Fractional number */
+	u32	longitude;	/* 2+30 bit Fractional number */
+	u32	delta;		/* mix of GMT delta and DLS */
+};
+
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.99-pre6/linux/include/asm-ppc/pgtable.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-ppc/pgtable.h	Tue May  2 13:05:40 2000
@@ -65,12 +65,11 @@
 #define flush_cache_mm(mm)		do { } while (0)
 #define flush_cache_range(mm, a, b)	do { } while (0)
 #define flush_cache_page(vma, p)	do { } while (0)
+#define flush_icache_page(vma, page)	do { } while (0)
 
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void __flush_page_to_ram(unsigned long page_va);
 #define flush_page_to_ram(page)	__flush_page_to_ram(page_address(page))
-extern void __flush_icache_page(unsigned long page_va);
-#define flush_icache_page(vma, page) __flush_icache_page(page_address(page))
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
@@ -197,22 +196,18 @@
 #define _PAGE_NO_CACHE	0x0002	/* I: cache inhibit */
 #define _PAGE_SHARED	0x0004	/* No ASID (context) compare */
 
-/* These four software bits must be masked out when the entry is loaded
+/* These five software bits must be masked out when the entry is loaded
  * into the TLB.
  */
+#define _PAGE_DIRTY	0x0008	/* software: page changed */
 #define _PAGE_GUARDED	0x0010	/* software: guarded access */
 #define _PAGE_WRITETHRU 0x0020	/* software: use writethrough cache */
 #define _PAGE_RW	0x0040	/* software: user write access allowed */
 #define _PAGE_ACCESSED	0x0080	/* software: page referenced */
 
-#define _PAGE_DIRTY	0x0100	/* C: page changed (write protect) */
+#define _PAGE_HWWRITE	0x0100	/* C: page changed (write protect) */
 #define _PAGE_USER	0x0800	/* One of the PP bits, the other must be 0 */
 
-/* This is used to enable or disable the actual hardware write
- * protection.
- */
-#define _PAGE_HWWRITE	_PAGE_DIRTY
-
 #else /* CONFIG_6xx */
 /* Definitions for 60x, 740/750, etc. */
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
@@ -432,6 +427,7 @@
 }
 
 extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
 
 /*
  * Page tables may have changed.  We don't need to do anything here
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/posix_types.h linux/include/asm-ppc/posix_types.h
--- v2.3.99-pre6/linux/include/asm-ppc/posix_types.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-ppc/posix_types.h	Tue May  2 13:05:40 2000
@@ -1,6 +1,8 @@
 #ifndef _PPC_POSIX_TYPES_H
 #define _PPC_POSIX_TYPES_H
 
+#include <linux/config.h>	/* for CONFIG_PPC64 */
+
 /*
  * This file is generally used by user-level software, so you need to
  * be a little careful about namespace pollution etc.  Also, we cannot
@@ -15,8 +17,17 @@
 typedef int		__kernel_pid_t;
 typedef unsigned int	__kernel_uid_t;
 typedef unsigned int	__kernel_gid_t;
+
+/* Grrr... gcc thinks size_t is unsigned int, so we either
+   have to have this nonsense or use -fno-builtin. - paulus */
+#ifdef CONFIG_PPC64
 typedef unsigned long	__kernel_size_t;
 typedef long		__kernel_ssize_t;
+#else
+typedef unsigned int	__kernel_size_t;
+typedef int		__kernel_ssize_t;
+#endif /* CONFIG_PPC64 */
+
 typedef long		__kernel_ptrdiff_t;
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.3.99-pre6/linux/include/asm-ppc/processor.h	Sat Feb 26 22:31:58 2000
+++ linux/include/asm-ppc/processor.h	Tue May  2 13:05:40 2000
@@ -483,6 +483,14 @@
 #define	PVR_8260	PVR_8240
 
 
+/* I am just adding a single entry for 8260 boards.  I think we may be
+ * able to combine mbx, fads, rpxlite, bseip, and classic into a single
+ * generic 8xx as well.  The boards containing these processors are either
+ * identical at the processor level (due to the high integration) or so
+ * wildly different that testing _machine at run time is best replaced by
+ * conditional compilation by board type (found in their respective .h file).
+ *	-- Dan
+ */
 #define _MACH_prep	0x00000001
 #define _MACH_Pmac	0x00000002	/* pmac or pmac clone (non-chrp) */
 #define _MACH_chrp	0x00000004	/* chrp machine */
@@ -496,6 +504,7 @@
 #define _MACH_classic	0x00000400	/* RPCG RPX-Classic 8xx board */
 #define _MACH_oak	0x00000800	/* IBM "Oak" 403 eval. board */
 #define _MACH_walnut	0x00001000	/* IBM "Walnut" 405GP eval. board */
+#define _MACH_8260	0x00002000	/* Generic 8260 */
 
 
 /* see residual.h for these */
@@ -706,6 +715,9 @@
 #define have_of 0
 #elif defined(CONFIG_GEMINI)
 #define _machine _MACH_gemini
+#define have_of 0
+#elif defined(CONFIG_8260)
+#define _machine _MACH_8260
 #define have_of 0
 #else
 #error "Machine not defined correctly"
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h
--- v2.3.99-pre6/linux/include/asm-ppc/resource.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-ppc/resource.h	Tue May  2 13:05:40 2000
@@ -14,14 +14,14 @@
 
 #define RLIM_NLIMITS	10
 
+#ifdef __KERNEL__
+
 /*
  * SuS says limits have to be unsigned.
  * Which makes a ton more sense anyway.
  */
 #define RLIM_INFINITY	(~0UL)
 
-
-#ifdef __KERNEL__
 
 #define INIT_RLIMITS							\
 {									\
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/rpxclassic.h linux/include/asm-ppc/rpxclassic.h
--- v2.3.99-pre6/linux/include/asm-ppc/rpxclassic.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/rpxclassic.h	Tue May  2 13:05:40 2000
@@ -62,6 +62,6 @@
 
 /* Machine type
 */
-#define _MACH_8xx (_MACH_rpxclassic)
+#define _MACH_8xx (_MACH_classic)
 
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.3.99-pre6/linux/include/asm-ppc/semaphore.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-ppc/semaphore.h	Tue May  2 13:05:40 2000
@@ -12,6 +12,7 @@
 #ifdef __KERNEL__
 
 #include <asm/atomic.h>
+#include <asm/system.h>
 #include <linux/wait.h>
 
 struct semaphore {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.99-pre6/linux/include/asm-ppc/system.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-ppc/system.h	Tue May  2 13:05:40 2000
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/kdev_t.h>
+#include <linux/bitops.h>
 
 #include <asm/processor.h>
 #include <asm/atomic.h>
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-ppc/termbits.h linux/include/asm-ppc/termbits.h
--- v2.3.99-pre6/linux/include/asm-ppc/termbits.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/termbits.h	Tue May  2 13:05:40 2000
@@ -57,12 +57,9 @@
 #define ICRNL	0000400
 #define IXON	0001000
 #define IXOFF	0002000
-#if defined(__KERNEL__) || defined(__USE_BSD)
-  /* POSIX.1 doesn't want these... */
-# define IXANY		0004000
-# define IUCLC		0010000
-# define IMAXBEL	0020000
-#endif
+#define IXANY		0004000
+#define IUCLC		0010000
+#define IMAXBEL	0020000
 
 /* c_oflag bits */
 #define OPOST	0000001
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.3.99-pre6/linux/include/asm-sparc/asm_offsets.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc/asm_offsets.h	Mon May  8 22:21:57 2000
@@ -184,8 +184,8 @@
 #define ASIZ_task_parent_exec_id	0x00000004
 #define AOFF_task_self_exec_id	0x000005fc
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000600
-#define ASIZ_task_exit_sem	0x00000020
+#define AOFF_task_alloc_lock	0x00000600
+#define ASIZ_task_alloc_lock	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
 #define AOFF_mm_mmap_avl	0x00000004
@@ -228,25 +228,21 @@
 #define ASIZ_mm_env_start	0x00000004
 #define AOFF_mm_env_end	0x0000006c
 #define ASIZ_mm_env_end	0x00000004
-#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 AOFF_mm_rss	0x00000070
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x0000007c
+#define AOFF_mm_total_vm	0x00000074
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000080
+#define AOFF_mm_locked_vm	0x00000078
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000084
+#define AOFF_mm_def_flags	0x0000007c
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000088
+#define AOFF_mm_cpu_vm_mask	0x00000080
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x0000008c
+#define AOFF_mm_swap_cnt	0x00000084
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000090
+#define AOFF_mm_swap_address	0x00000088
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x00000094
+#define AOFF_mm_segments	0x0000008c
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
@@ -469,8 +465,8 @@
 #define ASIZ_task_parent_exec_id	0x00000004
 #define AOFF_task_self_exec_id	0x00000700
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000704
-#define ASIZ_task_exit_sem	0x00000024
+#define AOFF_task_alloc_lock	0x00000704
+#define ASIZ_task_alloc_lock	0x00000008
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
 #define AOFF_mm_mmap_avl	0x00000004
@@ -513,25 +509,21 @@
 #define ASIZ_mm_env_start	0x00000004
 #define AOFF_mm_env_end	0x00000074
 #define ASIZ_mm_env_end	0x00000004
-#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 AOFF_mm_rss	0x00000078
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x00000084
+#define AOFF_mm_total_vm	0x0000007c
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000088
+#define AOFF_mm_locked_vm	0x00000080
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x0000008c
+#define AOFF_mm_def_flags	0x00000084
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000090
+#define AOFF_mm_cpu_vm_mask	0x00000088
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x00000094
+#define AOFF_mm_swap_cnt	0x0000008c
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000098
+#define AOFF_mm_swap_address	0x00000090
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x0000009c
+#define AOFF_mm_segments	0x00000094
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h
--- v2.3.99-pre6/linux/include/asm-sparc/atomic.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc/atomic.h	Mon May  8 22:00:01 2000
@@ -6,7 +6,9 @@
 #ifndef __ARCH_SPARC_ATOMIC__
 #define __ARCH_SPARC_ATOMIC__
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 /* This is a temporary measure. -DaveM */
 typedef struct { volatile int counter; } atomic_t;
 #define ATOMIC_INIT(i)	{ (i << 8) }
@@ -19,7 +21,7 @@
 #include <asm/system.h>
 #include <asm/psr.h>
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define atomic_read(v)          ((v)->counter)
 #define atomic_set(v, i)        (((v)->counter) = i)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/atops.h linux/include/asm-sparc/atops.h
--- v2.3.99-pre6/linux/include/asm-sparc/atops.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc/atops.h	Mon May  8 22:00:01 2000
@@ -5,7 +5,9 @@
 #ifndef _SPARC_ATOPS_H
 #define _SPARC_ATOPS_H
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 
 extern __inline__ __volatile__ unsigned char ldstub(volatile unsigned char *lock)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.3.99-pre6/linux/include/asm-sparc/bitops.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc/bitops.h	Mon May  8 22:00:01 2000
@@ -8,6 +8,7 @@
 #ifndef _SPARC_BITOPS_H
 #define _SPARC_BITOPS_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <asm/byteorder.h>
 
@@ -82,7 +83,7 @@
 
 #include <asm/system.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define __SMPVOL volatile
 #else
 #define __SMPVOL
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h
--- v2.3.99-pre6/linux/include/asm-sparc/hardirq.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-sparc/hardirq.h	Mon May  8 22:00:01 2000
@@ -7,9 +7,10 @@
 #ifndef __SPARC_HARDIRQ_H
 #define __SPARC_HARDIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern unsigned int local_irq_count;
 
 /*
@@ -81,6 +82,6 @@
 
 extern void synchronize_irq(void);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* __SPARC_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h
--- v2.3.99-pre6/linux/include/asm-sparc/irq.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/irq.h	Mon May  8 22:00:01 2000
@@ -7,6 +7,7 @@
 #ifndef _SPARC_IRQ_H
 #define _SPARC_IRQ_H
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/threads.h>     /* For NR_CPUS */
 
@@ -21,7 +22,7 @@
 #define NR_IRQS    15
 
 /* IRQ handler dispatch entry and exit. */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern unsigned int local_irq_count[NR_CPUS];
 #define irq_enter(cpu, irq)                     \
 do {    hardirq_enter(cpu);                     \
@@ -63,7 +64,7 @@
 			   int irq,
 			   unsigned int timeout);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
 BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
 BTFIXUPDEF_CALL(void, set_irq_udt, int)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h
--- v2.3.99-pre6/linux/include/asm-sparc/pgalloc.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc/pgalloc.h	Mon May  8 22:00:01 2000
@@ -2,6 +2,7 @@
 #ifndef _SPARC_PGALLOC_H
 #define _SPARC_PGALLOC_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -9,7 +10,7 @@
 #include <asm/btfixup.h>
 
 /* Fine grained cache/tlb flushing. */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 BTFIXUPDEF_CALL(void, local_flush_cache_all, void)
 BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *)
 BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/semaphore-helper.h linux/include/asm-sparc/semaphore-helper.h
--- v2.3.99-pre6/linux/include/asm-sparc/semaphore-helper.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc/semaphore-helper.h	Mon May  8 22:00:01 2000
@@ -1,6 +1,8 @@
 #ifndef _SPARC_SEMAPHORE_HELPER_H
 #define _SPARC_SEMAPHORE_HELPER_H
 
+#include <linux/config.h>
+
 /*
  * (barely) SMP- and interrupt-safe semaphore helper functions, sparc version.
  *
@@ -12,7 +14,7 @@
 {
 	int ret;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int tmp;
 
 	__asm__ __volatile__("
@@ -62,7 +64,7 @@
 {
 	int ret;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int tmp;
 
 	__asm__ __volatile__("
@@ -115,7 +117,7 @@
 {
 	int ret;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int tmp;
 
 	__asm__ __volatile__("
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/sfp-machine.h linux/include/asm-sparc/sfp-machine.h
--- v2.3.99-pre6/linux/include/asm-sparc/sfp-machine.h	Tue Jan  4 13:57:19 2000
+++ linux/include/asm-sparc/sfp-machine.h	Mon May  8 22:00:01 2000
@@ -24,6 +24,8 @@
 
 #ifndef _SFP_MACHINE_H
 #define _SFP_MACHINE_H
+
+#include <linux/config.h>
    
 #define _FP_W_TYPE_SIZE		32
 #define _FP_W_TYPE		unsigned long
@@ -174,13 +176,13 @@
 	     "3" ((USItype)(x0))					\
 	   : "cc")
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern struct task_struct *last_task_used_math;
 #endif
 
 /* Obtain the current rounding mode. */
 #ifndef FP_ROUNDMODE
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define FP_ROUNDMODE	((current->thread.fsr >> 30) & 0x3)
 #else
 #define FP_ROUNDMODE	((last_task_used_math->thread.fsr >> 30) & 0x3)
@@ -196,7 +198,7 @@
 
 #define FP_HANDLE_EXCEPTIONS return _fex
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define FP_INHIBIT_RESULTS ((current->thread.fsr >> 23) & _fex)
 #else
 #define FP_INHIBIT_RESULTS ((last_task_used_math->thread.fsr >> 23) & _fex)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.3.99-pre6/linux/include/asm-sparc/smp.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/smp.h	Mon May  8 22:00:01 2000
@@ -6,6 +6,7 @@
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/head.h>
 #include <asm/btfixup.h>
@@ -23,7 +24,7 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #ifndef __ASSEMBLY__
 
@@ -183,7 +184,7 @@
 
 #define PROC_CHANGE_PENALTY     15
 
-#endif /* !(__SMP__) */
+#endif /* !(CONFIG_SMP) */
 
 #define NO_PROC_ID            0xFF
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h
--- v2.3.99-pre6/linux/include/asm-sparc/softirq.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc/softirq.h	Mon May  8 22:00:01 2000
@@ -7,6 +7,7 @@
 #ifndef __SPARC_SOFTIRQ_H
 #define __SPARC_SOFTIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>	/* For NR_CPUS */
 
 #include <asm/atomic.h>
@@ -14,7 +15,7 @@
 #include <asm/hardirq.h>
 
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern unsigned int local_bh_count[NR_CPUS];
 
 #define local_bh_disable()	(local_bh_count[smp_processor_id()]++)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h
--- v2.3.99-pre6/linux/include/asm-sparc/string.h	Tue Apr 14 17:44:24 1998
+++ linux/include/asm-sparc/string.h	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.34 1998/01/30 10:59:55 jj Exp $
+/* $Id: string.h,v 1.35 2000/05/02 01:47:01 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -34,7 +34,7 @@
 
 #define __HAVE_ARCH_MEMCPY
 
-extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
 	extern void __copy_1page(void *, const void *);
 
@@ -53,7 +53,7 @@
 	return to;
 }
 
-extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
 	__memcpy(to, from, n);
 	return to;
@@ -67,7 +67,7 @@
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
+static inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
 {
 	extern void bzero_1page(void *);
 	extern __kernel_size_t __bzero(void *, __kernel_size_t);
@@ -83,7 +83,7 @@
 	return s;
 }
 
-extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
+static inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
 {
 	extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -94,7 +94,7 @@
 	return s;
 }
 
-extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
+static inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 {
 	__memset(s, c, count);
 	return s;
@@ -134,7 +134,7 @@
 
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
-extern inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
+static inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
 {
 	register int retval;
 	switch(count) {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.3.99-pre6/linux/include/asm-sparc/system.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-sparc/system.h	Mon May  8 22:00:01 2000
@@ -66,7 +66,7 @@
 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 		   void *fpqueue, unsigned long *fpqdepth);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define SWITCH_ENTER \
 	if(prev->flags & PF_USEDFPU) { \
 		put_psr(get_psr() | PSR_EF); \
@@ -249,7 +249,7 @@
 #define local_irq_save(flags)		__save_and_cli(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 extern unsigned char global_irq_holder;
 
@@ -285,13 +285,13 @@
 #define nop() __asm__ __volatile__ ("nop");
 
 /* This has special calling conventions */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 BTFIXUPDEF_CALL(void, ___xchg32, void)
 #endif
 
 extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	__asm__ __volatile__("swap [%2], %0"
 			     : "=&r" (val)
 			     : "0" (val), "r" (m));
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h
--- v2.3.99-pre6/linux/include/asm-sparc/winmacro.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/winmacro.h	Mon May  8 22:00:01 2000
@@ -7,6 +7,7 @@
 #ifndef _SPARC_WINMACRO_H
 #define _SPARC_WINMACRO_H
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 
@@ -111,7 +112,7 @@
         add      %scratch, 1, %scratch; \
         st       %scratch, [%cur_reg + AOFF_task_thread + AOFF_thread_w_saved];
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define LOAD_CURRENT4M(dest_reg, idreg) \
         rd       %tbr, %idreg; \
 	sethi    %hi(C_LABEL(current_set)), %dest_reg; \
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.99-pre6/linux/include/asm-sparc64/asm_offsets.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/asm_offsets.h	Mon May  8 22:21:57 2000
@@ -190,9 +190,9 @@
 #define ASIZ_task_parent_exec_id	0x00000004
 #define AOFF_task_self_exec_id	0x00000834
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000838
-#define ASIZ_task_exit_sem	0x00000038
-#define ASIZ_task	0x00000870
+#define AOFF_task_alloc_lock	0x00000838
+#define ASIZ_task_alloc_lock	0x00000004
+#define ASIZ_task	0x00000840
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -235,27 +235,23 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#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 AOFF_mm_rss	0x000000d0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000e8
+#define AOFF_mm_total_vm	0x000000d8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000f0
+#define AOFF_mm_locked_vm	0x000000e0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000f8
+#define AOFF_mm_def_flags	0x000000e8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x00000100
+#define AOFF_mm_cpu_vm_mask	0x000000f0
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x00000108
+#define AOFF_mm_swap_cnt	0x000000f8
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000110
+#define AOFF_mm_swap_address	0x00000100
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000118
+#define AOFF_mm_segments	0x00000108
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000120
+#define ASIZ_mm	0x00000110
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -488,9 +484,9 @@
 #define ASIZ_task_parent_exec_id	0x00000004
 #define AOFF_task_self_exec_id	0x00000a24
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000a28
-#define ASIZ_task_exit_sem	0x00000038
-#define ASIZ_task	0x00000a60
+#define AOFF_task_alloc_lock	0x00000a28
+#define ASIZ_task_alloc_lock	0x00000001
+#define ASIZ_task	0x00000a30
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -533,27 +529,23 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#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 AOFF_mm_rss	0x000000d0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000e8
+#define AOFF_mm_total_vm	0x000000d8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000f0
+#define AOFF_mm_locked_vm	0x000000e0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000f8
+#define AOFF_mm_def_flags	0x000000e8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x00000100
+#define AOFF_mm_cpu_vm_mask	0x000000f0
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x00000108
+#define AOFF_mm_swap_cnt	0x000000f8
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000110
+#define AOFF_mm_swap_address	0x00000100
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000118
+#define AOFF_mm_segments	0x00000108
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000120
+#define ASIZ_mm	0x00000110
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -784,9 +776,9 @@
 #define ASIZ_task_parent_exec_id	0x00000004
 #define AOFF_task_self_exec_id	0x00000a3c
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_exit_sem	0x00000a40
-#define ASIZ_task_exit_sem	0x00000040
-#define ASIZ_task	0x00000a80
+#define AOFF_task_alloc_lock	0x00000a40
+#define ASIZ_task_alloc_lock	0x0000000c
+#define ASIZ_task	0x00000a50
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -829,27 +821,23 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000d8
 #define ASIZ_mm_env_end	0x00000008
-#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 AOFF_mm_rss	0x000000e0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000f8
+#define AOFF_mm_total_vm	0x000000e8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x00000100
+#define AOFF_mm_locked_vm	0x000000f0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x00000108
+#define AOFF_mm_def_flags	0x000000f8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x00000110
+#define AOFF_mm_cpu_vm_mask	0x00000100
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x00000118
+#define AOFF_mm_swap_cnt	0x00000108
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000120
+#define AOFF_mm_swap_address	0x00000110
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000128
+#define AOFF_mm_segments	0x00000118
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000130
+#define ASIZ_mm	0x00000120
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h
--- v2.3.99-pre6/linux/include/asm-sparc64/delay.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/delay.h	Mon May  8 22:00:01 2000
@@ -7,7 +7,8 @@
 #ifndef __SPARC64_DELAY_H
 #define __SPARC64_DELAY_H
 
-#ifdef __SMP__
+#include <linux/config.h>
+#ifdef CONFIG_SMP
 #include <linux/sched.h>
 #include <asm/smp.h>
 #endif 
@@ -39,7 +40,7 @@
 	__delay(usecs);
 }
 
-#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-pre6/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.3.99-pre6/linux/include/asm-sparc64/hardirq.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/hardirq.h	Mon May  8 22:00:01 2000
@@ -6,11 +6,12 @@
 #ifndef __SPARC64_HARDIRQ_H
 #define __SPARC64_HARDIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/brlock.h>
 #include <linux/spinlock.h>
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern unsigned int local_irq_count;
 #define irq_enter(cpu, irq)	(local_irq_count++)
 #define irq_exit(cpu, irq)	(local_irq_count--)
@@ -29,7 +30,7 @@
 /* This tests only the local processors hw IRQ context disposition.  */
 #define in_irq() (local_irq_count != 0)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define hardirq_trylock(cpu)	((void)(cpu), local_irq_count == 0)
 #define hardirq_endlock(cpu)	do { (void)(cpu); } while(0)
@@ -39,7 +40,7 @@
 
 #define synchronize_irq()	barrier()
 
-#else /* (__SMP__) */
+#else /* (CONFIG_SMP) */
 
 static __inline__ int irqs_running(void)
 {
@@ -74,6 +75,6 @@
 
 extern void synchronize_irq(void);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* !(__SPARC64_HARDIRQ_H) */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- v2.3.99-pre6/linux/include/asm-sparc64/irq.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/irq.h	Mon May  8 22:00:01 2000
@@ -8,6 +8,7 @@
 #ifndef _SPARC64_IRQ_H
 #define _SPARC64_IRQ_H
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/kernel.h>
 
@@ -113,7 +114,7 @@
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 extern unsigned int psycho_build_irq(void *psycho, int imap_off, int ino, int need_dma_sync);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern void set_cpu_int(int, int);
 extern void clear_cpu_int(int, int);
 extern void set_irq_udt(int);
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- v2.3.99-pre6/linux/include/asm-sparc64/oplib.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/oplib.h	Mon May  8 22:00:01 2000
@@ -9,6 +9,7 @@
 #ifndef __SPARC64_OPLIB_H
 #define __SPARC64_OPLIB_H
 
+#include <linux/config.h>
 #include <asm/openprom.h>
 
 /* Enumeration to describe the prom major version we have detected. */
@@ -175,7 +176,7 @@
 extern enum prom_output_device prom_query_output_device(void);
 
 /* Multiprocessor operations... */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /* Start the CPU with the given device tree node, context table, and context
  * at the passed program counter.
  */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.3.99-pre6/linux/include/asm-sparc64/pgalloc.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/pgalloc.h	Mon May  8 22:00:01 2000
@@ -2,6 +2,7 @@
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -32,7 +33,7 @@
 			      unsigned long pgsz, unsigned long size);
 extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r);
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define flush_cache_all()	__flush_cache_all()
 #define flush_tlb_all()		__flush_tlb_all()
@@ -59,7 +60,7 @@
 			 SECONDARY_CONTEXT); \
 } while(0)
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 extern void smp_flush_cache_all(void);
 extern void smp_flush_tlb_all(void);
@@ -76,7 +77,7 @@
 #define flush_tlb_page(vma, page) \
 	smp_flush_tlb_page((vma)->vm_mm, page)
 
-#endif /* ! __SMP__ */
+#endif /* ! CONFIG_SMP */
 
 /* This will change for Cheetah and later chips. */
 #define VPTE_BASE	0xfffffffe00000000
@@ -101,7 +102,7 @@
 }
 
 /* Page table allocation/freeing. */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /* Sliiiicck */
 #define pgt_quicklists	cpu_data[smp_processor_id()]
 #else
@@ -118,7 +119,7 @@
 #define pgtable_cache_size	(pgt_quicklists.pgcache_size)
 #define pgd_cache_size		(pgt_quicklists.pgdcache_size)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
@@ -167,7 +168,7 @@
         return (pgd_t *)ret;
 }
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
@@ -197,7 +198,7 @@
 	free_page((unsigned long)pgd);
 }
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.99-pre6/linux/include/asm-sparc64/pgtable.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/pgtable.h	Mon May  8 22:21:57 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.125 2000/04/12 08:10:26 davem Exp $
+/* $Id: pgtable.h,v 1.126 2000/05/05 21:57:03 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -196,6 +196,7 @@
  * Undefined behaviour if not..
  */
 #define pte_read(pte)		(pte_val(pte) & _PAGE_READ)
+#define pte_exec(pte)		pte_read(pte)
 #define pte_write(pte)		(pte_val(pte) & _PAGE_WRITE)
 #define pte_dirty(pte)		(pte_val(pte) & _PAGE_MODIFIED)
 #define pte_young(pte)		(pte_val(pte) & _PAGE_ACCESSED)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.3.99-pre6/linux/include/asm-sparc64/processor.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/processor.h	Mon May  8 22:00:01 2000
@@ -13,6 +13,7 @@
  */
 #define current_text_addr() ({ void *pc; __asm__("rd %%pc, %0" : "=r" (pc)); pc; })
 
+#include <linux/config.h>
 #include <asm/asi.h>
 #include <asm/a.out.h>
 #include <asm/pstate.h>
@@ -127,7 +128,7 @@
 }
 
 /* On Uniprocessor, even in RMO processes see TSO semantics */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define TSTATE_INITIAL_MM	TSTATE_TSO
 #else
 #define TSTATE_INITIAL_MM	TSTATE_RMO
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.3.99-pre6/linux/include/asm-sparc64/smp.h	Wed Apr 26 16:34:09 2000
+++ linux/include/asm-sparc64/smp.h	Mon May  8 22:00:01 2000
@@ -6,6 +6,7 @@
 #ifndef _SPARC64_SMP_H
 #define _SPARC64_SMP_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/asi.h>
 
@@ -24,7 +25,7 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #ifndef __ASSEMBLY__
 
@@ -122,7 +123,7 @@
 
 #define PROC_CHANGE_PENALTY	20
 
-#endif /* !(__SMP__) */
+#endif /* !(CONFIG_SMP) */
 
 #define NO_PROC_ID		0xFF
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.3.99-pre6/linux/include/asm-sparc64/softirq.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sparc64/softirq.h	Mon May  8 22:00:01 2000
@@ -6,11 +6,12 @@
 #ifndef __SPARC64_SOFTIRQ_H
 #define __SPARC64_SOFTIRQ_H
 
+#include <linux/config.h>
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 #include <asm/system.h>		/* for membar() */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 extern unsigned int local_bh_count;
 #else
 #define local_bh_count		(cpu_data[smp_processor_id()].bh_count)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.3.99-pre6/linux/include/asm-sparc64/string.h	Tue Jan  4 13:57:21 2000
+++ linux/include/asm-sparc64/string.h	Wed May  3 01:47:57 2000
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.15 1999/12/23 17:02:20 jj Exp $
+/* $Id: string.h,v 1.16 2000/05/02 01:47:01 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -41,7 +41,7 @@
 
 #define __HAVE_ARCH_MEMCPY
 
-extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
 	if(n) {
 		if(n <= 32) {
@@ -53,7 +53,7 @@
 	return to;
 }
 
-extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
+static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
 	__memcpy(to, from, n);
 	return to;
@@ -67,7 +67,7 @@
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_memset(void *s, int c, __kernel_size_t count)
+static inline void *__constant_memset(void *s, int c, __kernel_size_t count)
 {
 	extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -127,7 +127,7 @@
 
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
-extern inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
+static inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count)
 {
 	register int retval;
 	switch(count) {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.3.99-pre6/linux/include/asm-sparc64/system.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/system.h	Mon May  8 22:00:01 2000
@@ -1,7 +1,8 @@
-/* $Id: system.h,v 1.57 2000/03/27 10:38:57 davem Exp $ */
+/* $Id: system.h,v 1.58 2000/05/05 18:47:41 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/asm_offsets.h>
@@ -71,7 +72,7 @@
 #define local_irq_save(flags)		__save_and_cli(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 #define cli() __cli()
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
@@ -256,6 +257,61 @@
 }
 
 extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
+/* 
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+extern __inline__ unsigned long
+__cmpxchg_u32(volatile int *m, int old, int new)
+{
+	__asm__ __volatile__("cas [%2], %3, %0"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+extern __inline__ unsigned long
+__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+{
+	__asm__ __volatile__("casx [%2], %3, %0"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+		case 4:
+			return __cmpxchg_u32(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/asm-sparc64/timer.h linux/include/asm-sparc64/timer.h
--- v2.3.99-pre6/linux/include/asm-sparc64/timer.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc64/timer.h	Mon May  8 22:00:01 2000
@@ -23,6 +23,8 @@
  * and also profiling if enabled.
  */
 
+#include <linux/config.h>
+
 /* Two timers, traditionally steered to PIL's 10 and 14 respectively.
  * But since INO packets are used on sun5, we could use any PIL level
  * we like, however for now we use the normal ones.
@@ -48,7 +50,7 @@
  */
 #define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern unsigned long timer_tick_offset;
 extern void timer_tick_interrupt(struct pt_regs *);
 #endif
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h
--- v2.3.99-pre6/linux/include/linux/arcdevice.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/arcdevice.h	Tue May  2 12:36:09 2000
@@ -72,7 +72,8 @@
 #define D_TX	        256	/* show tx packets                        */
 #define D_RX		512	/* show rx packets                        */
 #define D_SKB		1024	/* show skb's                             */
-#define D_TIMING	2048	/* show time needed to copy buffers to card */
+#define D_SKB_SIZE	2048	/* show skb sizes			  */
+#define D_TIMING	4096	/* show time needed to copy buffers to card */
 
 #ifndef ARCNET_DEBUG_MAX
 #define ARCNET_DEBUG_MAX (~0)	/* enable ALL debug messages       */
@@ -174,6 +175,13 @@
 #define NORMALconf      0x00	/* 1-249 byte packets */
 #define EXTconf         0x08	/* 250-504 byte packets */
 
+/* card feature flags, set during auto-detection.
+ * (currently only used by com20020pci)
+ */
+#define ARC_IS_5MBIT    1   /* card default speed is 5MBit */
+#define ARC_CAN_10MBIT  2   /* card uses COM20022, supporting 10MBit,
+				 but default is 2.5MBit. */
+
 
 /* information needed to define an encapsulation driver */
 struct ArcProto {
@@ -227,8 +235,10 @@
 	uint8_t config,		/* current value of CONFIG register */
 		timeout,	/* Extended timeout for COM20020 */
 		backplane,	/* Backplane flag for COM20020 */
-		clock,		/* COM20020 clock speed flag */
-		setup,		/* Contents of setup register */
+		clockp,		/* COM20020 clock divider */
+		clockm,		/* COM20020 clock multiplier flag */
+		setup,		/* Contents of setup1 register */
+		setup2,		/* Contents of setup2 register */
 		intmask;	/* current value of INTMASK register */
 	uint8_t default_proto[256];	/* default encap to use for each host */
 	int cur_tx,		/* buffer used by current transmit, or -1 */
@@ -236,7 +246,8 @@
 		cur_rx;		/* current receive buffer */
 	int lastload_dest,	/* can last loaded packet be acked? */
 		lasttrans_dest;	/* can last TX'd packet be acked? */
-	int basename_len;	/* name length without suffix ('arc0e' -> 4) */
+	char *card_name;	/* card ident string */
+	int card_flags;		/* special card features */
 
 	/*
 	 * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h
--- v2.3.99-pre6/linux/include/linux/coda_linux.h	Sat Feb 26 22:32:03 2000
+++ linux/include/linux/coda_linux.h	Sat Apr 29 09:59:53 2000
@@ -102,7 +102,7 @@
   if (coda_debug & mask) {                                        \
     printk("(%s,l. %d): ",  __FUNCTION__, __LINE__);              \
     printk(format, ## a); }                                       \
-} while (0) ;                            
+} while (0)
 
 #define ENTRY    \
     if(coda_print_entry) printk("Process %d entered %s\n",current->pid,__FUNCTION__)
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/com20020.h linux/include/linux/com20020.h
--- v2.3.99-pre6/linux/include/linux/com20020.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/com20020.h	Tue May  2 12:36:09 2000
@@ -29,6 +29,7 @@
 
 int com20020_check(struct net_device *dev);
 int com20020_found(struct net_device *dev, int shared);
+void com20020_remove(struct net_device *dev);
 
 /* The number of low I/O ports used by the card. */
 #define ARCNET_TOTAL_SIZE 9
@@ -41,8 +42,10 @@
 #define _ADDR_HI  (ioaddr+2)	/* control registers for IO-mapped memory */
 #define _ADDR_LO  (ioaddr+3)
 #define _MEMDATA  (ioaddr+4)	/* data port for IO-mapped memory */
+#define _SUBADR   (ioaddr+5)	/* the extended port _XREG refers to */
 #define _CONFIG   (ioaddr+6)	/* configuration register */
-#define _SETUP    (ioaddr+7)	/* setup register */
+#define _XREG     (ioaddr+7)	/* extra registers (indexed by _CONFIG 
+					or _SUBADR) */
 
 /* in the ADDR_HI register */
 #define RDDATAflag	0x80	/* next access is a read (not a write) */
@@ -57,10 +60,28 @@
 /* in SETUP register */
 #define PROMISCset	0x10	/* enable RCV_ALL */
 
-#define REGTENTID (lp->config &= ~3);
-#define REGNID (lp->config = (lp->config&~2)|1);
-#define REGSETUP (lp->config = (lp->config&~1)|2);
-#define REGNXTID (lp->config |= 3);
+/* COM2002x */
+#define SUB_TENTATIVE	0	/* tentative node ID */
+#define SUB_NODE	1	/* node ID */
+#define SUB_SETUP1	2	/* various options */
+#define SUB_TEST	3	/* test/diag register */
+
+/* COM20022 only */
+#define SUB_SETUP2	4	/* sundry options */
+#define SUB_BUSCTL	5	/* bus control options */
+#define SUB_DMACOUNT	6	/* DMA count options */
+
+#define SET_SUBADR(x) do { \
+	if ((x) < 4) \
+	{ \
+		lp->config = (lp->config & ~0x03) | (x); \
+		SETCONF; \
+	} \
+	else \
+	{ \
+		outb(x, _SUBADR); \
+	} \
+} while (0)
 
 #undef ARCRESET
 #undef ASTATUS
@@ -80,6 +101,6 @@
 #define ACOMMAND(cmd)	outb((cmd),_COMMAND)
 #define AINTMASK(msk)	outb((msk),_INTMASK)
 
-#define SETCONF(cfg)	outb(cfg, _CONFIG)
+#define SETCONF		outb(lp->config, _CONFIG)
 
 #endif /* __COM20020_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.99-pre6/linux/include/linux/dcache.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/dcache.h	Thu May 11 11:26:54 2000
@@ -61,8 +61,7 @@
 	unsigned int d_flags;
 	struct inode  * d_inode;	/* Where the name belongs to - NULL is negative */
 	struct dentry * d_parent;	/* parent directory */
-	struct dentry * d_mounts;	/* mount information */
-	struct dentry * d_covers;
+	struct list_head d_vfsmnt;
 	struct list_head d_hash;	/* lookup hash list */
 	struct list_head d_lru;		/* d_count = 0 LRU list */
 	struct list_head d_child;	/* child of parent list */
@@ -151,18 +150,18 @@
 #define shrink_dcache() prune_dcache(0)
 struct zone_struct;
 /* dcache memory management */
-extern int shrink_dcache_memory(int, unsigned int, struct zone_struct *);
+extern int shrink_dcache_memory(int, unsigned int);
 extern void prune_dcache(int);
 
 /* icache memory management (defined in linux/fs/inode.c) */
-extern int shrink_icache_memory(int, int, struct zone_struct *);
+extern int shrink_icache_memory(int, int);
 extern void prune_icache(int);
 
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode *);
 
 /* test whether root is busy without destroying dcache */
-extern int is_root_busy(struct dentry *);
+extern int d_active_refs(struct dentry *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
@@ -235,10 +234,9 @@
 
 extern void dput(struct dentry *);
 
-/* MOUNT_REWRITE: replace with the check for d_vfsmnt */
 static __inline__ int d_mountpoint(struct dentry *dentry)
 {
-	return dentry != dentry->d_mounts;
+	return !list_empty(&dentry->d_vfsmnt);
 }
 
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.99-pre6/linux/include/linux/file.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/file.h	Tue May  9 16:18:28 2000
@@ -7,23 +7,19 @@
 
 extern void _fput(struct file *);
 
-/*
- * Check whether the specified task has the fd open. Since the task
- * may not have a files_struct, we must test for p->files != NULL.
- */
-extern inline struct file * fcheck_task(struct task_struct *p, unsigned int fd)
+static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
 {
 	struct file * file = NULL;
 
-	if (fd < p->files->max_fds)
-		file = p->files->fd[fd];
+	if (fd < files->max_fds)
+		file = files->fd[fd];
 	return file;
 }
 
 /*
  * Check whether the specified fd has an open file.
  */
-extern inline struct file * fcheck(unsigned int fd)
+static inline struct file * fcheck(unsigned int fd)
 {
 	struct file * file = NULL;
 	struct files_struct *files = current->files;
@@ -33,7 +29,7 @@
 	return file;
 }
 
-extern inline struct file * frip(struct files_struct *files, unsigned int fd)
+static inline struct file * frip(struct files_struct *files, unsigned int fd)
 {
 	struct file * file = NULL;
 
@@ -42,7 +38,7 @@
 	return file;
 }
 
-extern inline struct file * fget(unsigned int fd)
+static inline struct file * fget(unsigned int fd)
 {
 	struct file * file = NULL;
 	struct files_struct *files = current->files;
@@ -58,10 +54,10 @@
 /*
  * 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: 
  * 
- * Since those functions where calling other functions, it was compleatly 
- * bogous to make them all "extern inline".
+ * Since those functions where calling other functions, it was completely 
+ * bogus to make them all "extern inline".
  *
- * The removal of this pseudo optimization saved me scandaleous:
+ * The removal of this pseudo optimization saved me scandalous:
  *
  * 		3756 (i386 arch) 
  *
@@ -71,7 +67,7 @@
  * I suspect there are many other similar "optimizations" across the
  * kernel...
  */
-extern inline void fput(struct file * file)
+static inline void fput(struct file * file)
 {
 	if (atomic_dec_and_test(&file->f_count))
 		_fput(file);
@@ -88,7 +84,7 @@
  * fput() the struct file we are about to overwrite in this case.
  */
 
-extern inline void fd_install(unsigned int fd, struct file * file)
+static inline void fd_install(unsigned int fd, struct file * file)
 {
 	struct files_struct *files = current->files;
 	struct file * result;
@@ -99,5 +95,7 @@
 	if (result)
 		fput(result);
 }
+
+void put_files_struct(struct files_struct *fs);
 
 #endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/filter.h linux/include/linux/filter.h
--- v2.3.99-pre6/linux/include/linux/filter.h	Mon Mar  8 13:05:01 1999
+++ linux/include/linux/filter.h	Thu Apr 27 15:55:09 2000
@@ -38,7 +38,7 @@
         struct sock_filter     	insns[0];
 };
 
-extern __inline__ unsigned int sk_filter_len(struct sk_filter *fp)
+static inline unsigned int sk_filter_len(struct sk_filter *fp)
 {
 	return fp->len*sizeof(struct sock_filter) + sizeof(*fp);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.99-pre6/linux/include/linux/fs.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/fs.h	Thu May 11 11:26:54 2000
@@ -20,6 +20,7 @@
 #include <linux/stat.h>
 #include <linux/cache.h>
 #include <linux/stddef.h>
+#include <linux/string.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -78,7 +79,11 @@
 #define FS_NO_PRELIM	4 /* prevent preloading of dentries, even if
 			   * FS_NO_DCACHE is not set.
 			   */
-
+#define FS_SINGLE	8 /*
+			   * Filesystem that can have only one superblock;
+			   * kernel-wide vfsmnt is kept in ->kern_mnt.
+			   */
+#define FS_NOMOUNT	16 /* Never mount from userland */
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
@@ -173,7 +178,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/string.h>
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 
@@ -251,7 +255,7 @@
 
 extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset);
 
-#define touch_buffer(bh)	set_bit(PG_referenced, &bh->b_page->flags)
+#define touch_buffer(bh)	SetPageReferenced(bh->b_page)
 
 
 #include <linux/pipe_fs_i.h>
@@ -338,8 +342,8 @@
 struct address_space;
 
 struct address_space_operations {
-	int (*writepage)(struct file *, struct dentry *, struct page *);
-	int (*readpage)(struct dentry *, struct page *);
+	int (*writepage)(struct file *, struct page *);
+	int (*readpage)(struct file *, 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);
@@ -625,6 +629,7 @@
 	struct list_head	s_files;
 
 	struct block_device	*s_bdev;
+	struct list_head	s_mounts;	/* vfsmount(s) of this one */
 	struct quota_mount_options s_dquot;	/* Diskquota specific options */
 
 	union {
@@ -769,6 +774,7 @@
 	int fs_flags;
 	struct super_block *(*read_super) (struct super_block *, void *, int);
 	struct module *owner;
+	struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */
 	struct file_system_type * next;
 };
 
@@ -785,16 +791,11 @@
 
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
+extern struct vfsmount *kern_mount(struct file_system_type *);
+extern void kern_umount(struct vfsmount *);
+extern int may_umount(struct vfsmount *);
 
-static inline int vfs_statfs(struct super_block *sb, struct statfs *buf)
-{
-	if (!sb)
-		return -ENODEV;
-	if (!sb->s_op || !sb->s_op->statfs)
-		return -ENOSYS;
-	memset(buf, 0, sizeof(struct statfs));
-	return sb->s_op->statfs(sb, buf);
-}
+extern int vfs_statfs(struct super_block *, struct statfs *);
 
 /* Return value for VFS lock functions - tells locks.c to lock conventionally
  * REALLY kosha for root NFS and nfs_lock
@@ -821,7 +822,7 @@
 	return 0;
 }
 
-extern inline int locks_verify_area(int read_write, struct inode *inode,
+static inline int locks_verify_area(int read_write, struct inode *inode,
 				    struct file *filp, loff_t offset,
 				    size_t count)
 {
@@ -830,7 +831,7 @@
 	return 0;
 }
 
-extern inline int locks_verify_truncate(struct inode *inode,
+static inline int locks_verify_truncate(struct inode *inode,
 				    struct file *filp,
 				    loff_t size)
 {
@@ -898,7 +899,6 @@
 extern struct file_operations rdwr_pipe_fops;
 
 extern int fs_may_remount_ro(struct super_block *);
-extern int fs_may_mount(kdev_t);
 
 extern int try_to_free_buffers(struct page *);
 extern void refile_buffer(struct buffer_head * buf);
@@ -912,7 +912,7 @@
 /*
  * This is called by bh->b_end_io() handlers when I/O has completed.
  */
-extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
+static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
 {
 	if (on)
 		set_bit(BH_Uptodate, &bh->b_state);
@@ -922,12 +922,12 @@
 
 #define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
 
-extern inline void __mark_buffer_clean(struct buffer_head *bh)
+static inline void __mark_buffer_clean(struct buffer_head *bh)
 {
 	refile_buffer(bh);
 }
 
-extern inline void mark_buffer_clean(struct buffer_head * bh)
+static inline void mark_buffer_clean(struct buffer_head * bh)
 {
 	if (atomic_set_buffer_clean(bh))
 		__mark_buffer_clean(bh);
@@ -935,12 +935,12 @@
 
 #define atomic_set_buffer_protected(bh) test_and_set_bit(BH_Protected, &(bh)->b_state)
 
-extern inline void __mark_buffer_protected(struct buffer_head *bh)
+static inline void __mark_buffer_protected(struct buffer_head *bh)
 {
 	refile_buffer(bh);
 }
 
-extern inline void mark_buffer_protected(struct buffer_head * bh)
+static inline void mark_buffer_protected(struct buffer_head * bh)
 {
 	if (!atomic_set_buffer_protected(bh))
 		__mark_buffer_protected(bh);
@@ -968,7 +968,6 @@
 extern int permission(struct inode *, int);
 extern int get_write_access(struct inode *);
 extern void put_write_access(struct inode *);
-extern struct dentry * do_mknod(const char *, int, dev_t);
 extern int do_pipe(int *);
 
 extern int open_namei(const char *, int, int, struct nameidata *);
@@ -1031,14 +1030,16 @@
 /* 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 *, struct nameidata *);
+extern int __user_walk(const char *, unsigned, struct nameidata *);
+extern int path_init(const char *, unsigned, struct nameidata *);
+extern int path_walk(const char *, struct nameidata *);
+extern void path_release(struct nameidata *);
+extern int follow_down(struct vfsmount **, struct dentry **);
+extern int follow_up(struct vfsmount **, struct dentry **);
 extern struct dentry * lookup_one(const char *, struct dentry *);
-extern struct dentry * __namei(const char *, unsigned int);
-
-#define namei(pathname)		__namei(pathname, LOOKUP_FOLLOW)
-#define lnamei(pathname)	__namei(pathname, 0)
+extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+#define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1064,13 +1065,13 @@
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
-extern inline void brelse(struct buffer_head *buf)
+static inline void brelse(struct buffer_head *buf)
 {
 	if (buf)
 		__brelse(buf);
 }
 extern void __bforget(struct buffer_head *);
-extern inline void bforget(struct buffer_head *buf)
+static inline void bforget(struct buffer_head *buf)
 {
 	if (buf)
 		__bforget(buf);
@@ -1083,7 +1084,6 @@
 
 extern int brw_page(int, struct page *, kdev_t, int [], int);
 
-typedef int (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);
 typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int);
 
 /* Generic buffer handling for block filesystems.. */
@@ -1119,7 +1119,6 @@
 
 extern struct super_block *get_super(kdev_t);
 struct super_block *get_empty_super(void);
-void remove_vfsmnt(kdev_t dev);
 extern void put_super(kdev_t);
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/fs_struct.h linux/include/linux/fs_struct.h
--- v2.3.99-pre6/linux/include/linux/fs_struct.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/fs_struct.h	Fri Apr 28 22:46:37 2000
@@ -31,8 +31,10 @@
 	struct vfsmount *old_rootmnt = fs->rootmnt;
 	fs->rootmnt = mntget(mnt);
 	fs->root = dget(dentry);
-	dput(old_root);
-	mntput(old_rootmnt);
+	if (old_root) {
+		dput(old_root);
+		mntput(old_rootmnt);
+	}
 }
 
 /*
@@ -48,8 +50,10 @@
 	struct vfsmount *old_pwdmnt = fs->pwdmnt;
 	fs->pwdmnt = mntget(mnt);
 	fs->pwd = dget(dentry);
-	dput(old_pwd);
-	mntput(old_pwdmnt);
+	if (old_pwd) {
+		dput(old_pwd);
+		mntput(old_pwdmnt);
+	}
 }
 
 struct fs_struct *copy_fs_struct(struct fs_struct *old);
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/hdlcdrv.h linux/include/linux/hdlcdrv.h
--- v2.3.99-pre6/linux/include/linux/hdlcdrv.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/hdlcdrv.h	Thu May  4 11:31:21 2000
@@ -109,7 +109,6 @@
 #include <linux/spinlock.h>
 
 #define HDLCDRV_MAGIC      0x5ac6e778
-#define HDLCDRV_IFNAMELEN    6
 #define HDLCDRV_HDLCBUFFER  32 /* should be a power of 2 for speed reasons */
 #define HDLCDRV_BITBUFFER  256 /* should be a power of 2 for speed reasons */
 #undef HDLCDRV_LOOPBACK  /* define for HDLC debugging purposes */
@@ -181,8 +180,6 @@
 
 struct hdlcdrv_state {
 	int magic;
-
-	char ifname[HDLCDRV_IFNAMELEN];
 
 	const struct hdlcdrv_ops *ops;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.99-pre6/linux/include/linux/i2o.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/i2o.h	Wed May 10 16:56:43 2000
@@ -142,7 +142,6 @@
 	void (*bus_disable)(struct i2o_controller *c);
 
 	void *page_frame;		/* Message buffers */
-	int inbound_size;		/* Inbound queue size */
 };
 
 /*
@@ -304,8 +303,6 @@
 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); 
 
@@ -401,13 +398,12 @@
 
 #define I2O_PRIVATE_MSG			0xFF
 
-/*
- *	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
+/* Command status values  */
+
+#define I2O_CMD_IN_PROGRESS	0x01
+#define I2O_CMD_REJECTED	0x02
+#define I2O_CMD_FAILED		0x03
+#define I2O_CMD_COMPLETED	0x04
 
 /* I2O API function return values */
 
@@ -490,6 +486,25 @@
 #define I2O_DSC_DEVICE_BUSY                    0x001B
 #define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
 
+/* FailureStatusCodes, Table 3-3 Message Failure Codes */
+
+#define I2O_FSC_TRANSPORT_SERVICE_SUSPENDED             0x81
+#define I2O_FSC_TRANSPORT_SERVICE_TERMINATED            0x82
+#define I2O_FSC_TRANSPORT_CONGESTION                    0x83
+#define I2O_FSC_TRANSPORT_FAILURE                       0x84
+#define I2O_FSC_TRANSPORT_STATE_ERROR                   0x85
+#define I2O_FSC_TRANSPORT_TIME_OUT                      0x86
+#define I2O_FSC_TRANSPORT_ROUTING_FAILURE               0x87
+#define I2O_FSC_TRANSPORT_INVALID_VERSION               0x88
+#define I2O_FSC_TRANSPORT_INVALID_OFFSET                0x89
+#define I2O_FSC_TRANSPORT_INVALID_MSG_FLAGS             0x8A
+#define I2O_FSC_TRANSPORT_FRAME_TOO_SMALL               0x8B
+#define I2O_FSC_TRANSPORT_FRAME_TOO_LARGE               0x8C
+#define I2O_FSC_TRANSPORT_INVALID_TARGET_ID             0x8D
+#define I2O_FSC_TRANSPORT_INVALID_INITIATOR_ID          0x8E
+#define I2O_FSC_TRANSPORT_INVALID_INITIATOR_CONTEXT     0x8F
+#define I2O_FSC_TRANSPORT_UNKNOWN_FAILURE               0xFF
+
 /* Device Claim Types */
 #define	I2O_CLAIM_PRIMARY					0x01000000
 #define	I2O_CLAIM_MANAGEMENT					0x02000000
@@ -526,7 +541,7 @@
 #define MSG_64BIT_CNTXT	0x0200
 #define MSG_MULTI_TRANS	0x1000
 #define MSG_FAIL	0x2000
-#define MSG_LAST	0x4000
+#define MSG_FINAL	0x4000
 #define MSG_REPLY	0x8000
 
  /* minimum size msg */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.3.99-pre6/linux/include/linux/if_ether.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/if_ether.h	Mon May  8 22:21:58 2000
@@ -56,6 +56,8 @@
 #define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
 #define ETH_P_IPX	0x8137		/* IPX over DIX			*/
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
+#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
 
 /*
  *	Non DIX types. Won't clash for 1500 types.
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/if_pppox.h linux/include/linux/if_pppox.h
--- v2.3.99-pre6/linux/include/linux/if_pppox.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_pppox.h	Thu May 11 11:27:15 2000
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * Linux PPP over X - Generic PPP transport layer sockets
+ * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) 
+ *
+ * This file supplies definitions required by the PPP over Ethernet driver
+ * (pppox.c).  All version information wrt this file is located in pppox.c
+ *
+ * License:
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef __LINUX_IF_PPPOX_H
+#define __LINUX_IF_PPPOX_H
+
+#include <linux/if_ether.h>
+#include <linux/if.h>
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#ifdef  __KERNEL__
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <asm/semaphore.h>
+#include <linux/ppp_channel.h>
+#endif /* __KERNEL__ */
+
+/* For user-space programs to pick up these definitions
+ * which they wouldn't get otherwise without defining __KERNEL__
+ */
+#ifndef AF_PPPOX
+#define AF_PPPOX	24
+#define PF_PPPOX	AF_PPPOX
+#endif /* !(AF_PPPOX) */
+
+/************************************************************************ 
+ * PPPoE addressing definition 
+ */ 
+typedef __u16 sid_t; 
+struct pppoe_addr{ 
+       sid_t           sid;                    /* Session identifier */ 
+       unsigned char   remote[ETH_ALEN];       /* Remote address */ 
+       char            dev[IFNAMSIZ];          /* Local device to use */ 
+}; 
+ 
+/************************************************************************ 
+ * Protocols supported by AF_PPPOX 
+ */ 
+#define PX_PROTO_OE    0 /* Currently just PPPoE */
+#define PX_MAX_PROTO   1	
+ 
+struct sockaddr_pppox { 
+       sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
+       unsigned int    sa_protocol;          /* protocol identifier */ 
+       union{ 
+               struct pppoe_addr       pppoe; 
+       }sa_addr; 
+}__attribute__ ((packed)); 
+
+
+/*********************************************************************
+ *
+ * ioctl interface for defining forwarding of connections
+ *
+ ********************************************************************/
+
+#define PPPOEIOCSFWD	_IOW(0xB1 ,0, sizeof(struct sockaddr_pppox))
+#define PPPOEIOCDFWD	_IO(0xB1 ,1)
+/*#define PPPOEIOCGFWD	_IOWR(0xB1,2, sizeof(struct sockaddr_pppox))*/
+
+/* Codes to identify message types */
+#define PADI_CODE	0x09
+#define PADO_CODE	0x07
+#define PADR_CODE	0x19
+#define PADS_CODE	0x65
+#define PADT_CODE	0xa7
+struct pppoe_tag {
+	__u16 tag_type;
+	__u16 tag_len;
+	char tag_data[0];
+} __attribute ((packed));
+
+/* Tag identifiers */
+#define PTT_EOL		__constant_htons(0x0000)
+#define PTT_SRV_NAME	__constant_htons(0x0101)
+#define PTT_AC_NAME	__constant_htons(0x0102)
+#define PTT_HOST_UNIQ	__constant_htons(0x0103)
+#define PTT_AC_COOKIE	__constant_htons(0x0104)
+#define PTT_VENDOR 	__constant_htons(0x0105)
+#define PTT_RELAY_SID	__constant_htons(0x0110)
+#define PTT_SRV_ERR     __constant_htons(0x0201)
+#define PTT_SYS_ERR  	__constant_htons(0x0202)
+#define PTT_GEN_ERR  	__constant_htons(0x0203)
+
+struct pppoe_hdr {
+	__u8 ver : 4;
+	__u8 type : 4;
+	__u8 code;
+	__u16 sid;
+	__u16 length;
+	struct pppoe_tag tag[0];
+} __attribute__ ((packed));
+
+#ifdef __KERNEL__
+
+struct pppox_proto {
+	int (*create)(struct socket *sock);
+	int (*ioctl)(struct socket *sock, unsigned int cmd,
+		     unsigned long arg);
+};
+
+extern int register_pppox_proto(int proto_num, struct pppox_proto *pp);
+extern void unregister_pppox_proto(int proto_num);
+extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
+extern int pppox_channel_ioctl(struct ppp_channel *pc, unsigned int cmd,
+			       unsigned long arg);
+
+/* PPPoE socket states */
+enum {
+    PPPOX_NONE		= 0,  /* initial state */
+    PPPOX_CONNECTED	= 1,  /* connection established ==TCP_ESTABLISHED */
+    PPPOX_BOUND		= 2,  /* bound to ppp device */
+    PPPOX_RELAY		= 4,  /* forwarding is enabled */
+    PPPOX_DEAD		= 8
+};
+
+extern struct ppp_channel_ops pppoe_chan_ops;
+
+extern void  pppox_proto_init(struct net_proto *np);
+
+#endif /* __KERNEL__ */
+
+#endif /* !(__LINUX_IF_PPPOX_H) */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/input.h linux/include/linux/input.h
--- v2.3.99-pre6/linux/include/linux/input.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/input.h	Thu Apr 27 17:35:05 2000
@@ -416,7 +416,7 @@
 #include <linux/devfs_fs_kernel.h>
 
 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
-#define BIT(x)	(1<<((x)%BITS_PER_LONG))
+#define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
 struct input_dev {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.99-pre6/linux/include/linux/mm.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/mm.h	Thu May 11 11:26:54 2000
@@ -173,7 +173,7 @@
 #define PG_slab			 8
 #define PG_swap_cache		 9
 #define PG_skip			10
-#define PG_swap_entry		11
+#define PG_unused_03		11
 #define PG_highmem		12
 				/* bits 21-30 unused */
 #define PG_reserved		31
@@ -196,7 +196,11 @@
 #define SetPageError(page)	set_bit(PG_error, &(page)->flags)
 #define ClearPageError(page)	clear_bit(PG_error, &(page)->flags)
 #define PageReferenced(page)	test_bit(PG_referenced, &(page)->flags)
+#define SetPageReferenced(page)	set_bit(PG_referenced, &(page)->flags)
+#define PageTestandClearReferenced(page)	test_and_clear_bit(PG_referenced, &(page)->flags)
 #define PageDecrAfter(page)	test_bit(PG_decr_after, &(page)->flags)
+#define SetPageDecrAfter(page)	set_bit(PG_decr_after, &(page)->flags)
+#define PageTestandClearDecrAfter(page)	test_and_clear_bit(PG_decr_after, &(page)->flags)
 #define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
 #define PageSwapCache(page)	test_bit(PG_swap_cache, &(page)->flags)
 #define PageReserved(page)	test_bit(PG_reserved, &(page)->flags)
@@ -210,9 +214,6 @@
 #define PageClearSwapCache(page)	clear_bit(PG_swap_cache, &(page)->flags)
 
 #define PageTestandClearSwapCache(page)	test_and_clear_bit(PG_swap_cache, &(page)->flags)
-#define PageSwapEntry(page)		test_bit(PG_swap_entry, &(page)->flags)
-#define SetPageSwapEntry(page)		set_bit(PG_swap_entry, &(page)->flags)
-#define ClearPageSwapEntry(page)	clear_bit(PG_swap_entry, &(page)->flags)
 
 #ifdef CONFIG_HIGHMEM
 #define PageHighMem(page)		test_bit(PG_highmem, &(page)->flags)
@@ -312,7 +313,7 @@
 extern struct page * alloc_pages_node(int nid, int gfp_mask, unsigned long order);
 
 #ifndef CONFIG_DISCONTIGMEM
-extern inline struct page * alloc_pages(int gfp_mask, unsigned long order)
+static inline struct page * alloc_pages(int gfp_mask, unsigned long order)
 {
 	/*  temporary check. */
 	if (contig_page_data.node_zonelists[gfp_mask].gfp_mask != (gfp_mask))
@@ -331,7 +332,7 @@
 #define alloc_page(gfp_mask) \
 		alloc_pages(gfp_mask, 0)
 
-extern inline unsigned long __get_free_pages (int gfp_mask, unsigned long order)
+static inline unsigned long __get_free_pages (int gfp_mask, unsigned long order)
 {
 	struct page * page;
 
@@ -347,7 +348,7 @@
 #define __get_dma_pages(gfp_mask, order) \
 		__get_free_pages((gfp_mask) | GFP_DMA,(order))
 
-extern inline unsigned long get_zeroed_page(int gfp_mask)
+static inline unsigned long get_zeroed_page(int gfp_mask)
 {
 	unsigned long page;
 
@@ -367,7 +368,7 @@
  */
 extern void FASTCALL(__free_pages_ok(struct page * page, unsigned long order));
 
-extern inline void __free_pages(struct page *page, unsigned long order)
+static inline void __free_pages(struct page *page, unsigned long order)
 {
 	if (!put_page_testzero(page))
 		return;
@@ -376,7 +377,7 @@
 
 #define __free_page(page) __free_pages(page, 0)
 
-extern inline void free_pages(unsigned long addr, unsigned long order)
+static inline void free_pages(unsigned long addr, unsigned long order)
 {
 	unsigned long map_nr;
 
@@ -433,7 +434,7 @@
 	unsigned long len, unsigned long prot,
 	unsigned long flag, unsigned long pgoff);
 
-extern inline unsigned long do_mmap(struct file *file, unsigned long addr,
+static inline unsigned long do_mmap(struct file *file, unsigned long addr,
 	unsigned long len, unsigned long prot,
 	unsigned long flag, unsigned long offset)
 {
@@ -454,7 +455,7 @@
 /* filemap.c */
 extern void remove_inode_page(struct page *);
 extern unsigned long page_unuse(struct page *);
-extern int shrink_mmap(int, int, zone_t *);
+extern int shrink_mmap(int, int);
 extern void truncate_inode_pages(struct address_space *, loff_t);
 
 /* generic vm_area_ops exported for stackable file systems */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/module.h linux/include/linux/module.h
--- v2.3.99-pre6/linux/include/linux/module.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/module.h	Thu May 11 11:26:54 2000
@@ -190,6 +190,17 @@
 __attribute__((section(".modinfo"))) =		\
 "parm_desc_" __MODULE_STRING(var) "=" desc
 
+/*
+ * MODULE_DEVICE_TABLE exports information about devices
+ * currently supported by this module.  A device type, such as PCI,
+ * is a C-like identifier passed as the first arg to this macro.
+ * The second macro arg is the variable containing the device
+ * information being made public.
+ *
+ * The following is a list of known device types (arg 1),
+ * and the C types which are to be passed as arg 2.
+ * pci - struct pci_device_id - List of PCI ids supported by this module
+ */
 #define MODULE_DEVICE_TABLE(type,name)	\
 const struct type##_device_id * __module_##type##_device_table = name
 /* not put to .modinfo section to avoid section type conflicts */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.3.99-pre6/linux/include/linux/mount.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/mount.h	Mon May  8 11:17:47 2000
@@ -10,24 +10,40 @@
  */
 #ifndef _LINUX_MOUNT_H
 #define _LINUX_MOUNT_H
+#ifdef __KERNEL__
 
 struct vfsmount
 {
-  kdev_t mnt_dev;			/* Device this applies to */
+	struct dentry *mnt_mountpoint;	/* dentry of mountpoint */
+	struct dentry *mnt_root;	/* root of the mounted tree */
+	struct vfsmount *mnt_parent;	/* fs we are mounted on */
+	struct list_head mnt_instances;	/* other vfsmounts of the same fs */
+	struct list_head mnt_clash;	/* those who are mounted on (other */
+					/* instances) of the same dentry */
+	struct super_block *mnt_sb;	/* pointer to superblock */
+	struct list_head mnt_mounts;	/* list of children, anchored here */
+	struct list_head mnt_child;	/* and going through their mnt_child */
+	atomic_t mnt_count;
+
   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 list_head mnt_list;
 };
 
-/* MOUNT_REWRITE: fill these */
 static inline struct vfsmount *mntget(struct vfsmount *mnt)
 {
+	if (mnt)
+		atomic_inc(&mnt->mnt_count);
 	return mnt;
 }
 
 static inline void mntput(struct vfsmount *mnt)
 {
+	if (mnt) {
+		if (atomic_dec_and_test(&mnt->mnt_count))
+			BUG();
+	}
 }
 
+#endif
 #endif /* _LINUX_MOUNT_H */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/net.h linux/include/linux/net.h
--- v2.3.99-pre6/linux/include/linux/net.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/net.h	Thu May 11 11:26:54 2000
@@ -18,6 +18,7 @@
 #ifndef _LINUX_NET_H
 #define _LINUX_NET_H
 
+#include <linux/config.h>
 #include <linux/socket.h>
 #include <linux/wait.h>
 
@@ -141,7 +142,7 @@
 extern unsigned long net_random(void);
 extern void net_srandom(unsigned long);
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 #define SOCKOPS_WRAPPED(name) name
 #define SOCKOPS_WRAP(name, fam)
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.3.99-pre6/linux/include/linux/netdevice.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/netdevice.h	Thu May 11 11:27:15 2000
@@ -210,7 +210,7 @@
 	 * (i.e. as seen by users in the "Space.c" file).  It is the name
 	 * the interface.
 	 */
-	char			*name;
+	char			name[IFNAMSIZ];
 
 	/*
 	 *	I/O specific fields
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
--- v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_conntrack.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h	Thu May 11 11:32:36 2000
@@ -51,7 +51,10 @@
 	IPS_EXPECTED = 0x01,
 
 	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
-	IPS_SEEN_REPLY = 0x02
+	IPS_SEEN_REPLY = 0x02,
+
+	/* Packet seen leaving box: bit 2 set.  Can be set, not unset. */
+	IPS_CONFIRMED = 0x04
 };
 
 struct ip_conntrack_expect
@@ -88,7 +91,7 @@
 	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
 
 	/* Have we seen traffic both ways yet? (bitset) */
-	unsigned int status;
+	volatile unsigned int status;
 
 	/* Timer function; drops refcnt when it goes off. */
 	struct timer_list timeout;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_conntrack_core.h linux/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_conntrack_core.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_core.h	Thu May 11 11:32:36 2000
@@ -20,8 +20,9 @@
 extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
 
-/* Returns TRUE if it dealt with ICMP, and filled in skb->nfct */
-int icmp_error_track(struct sk_buff *skb);
+/* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
+extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
+					     enum ip_conntrack_info *ctinfo);
 extern int get_tuple(const struct iphdr *iph, size_t len,
 		     struct ip_conntrack_tuple *tuple,
 		     struct ip_conntrack_protocol *protocol);
@@ -30,6 +31,9 @@
 struct ip_conntrack_tuple_hash *
 ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
 		      const struct ip_conntrack *ignored_conntrack);
+
+/* Confirm a connection */
+void ip_conntrack_confirm(struct ip_conntrack *ct);
 
 extern unsigned int ip_conntrack_htable_size;
 extern struct list_head *ip_conntrack_hash;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- v2.3.99-pre6/linux/include/linux/netfilter_ipv4/ip_tables.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Thu May 11 11:32:36 2000
@@ -346,6 +346,9 @@
 			  unsigned int matchinfosize,
 			  unsigned int hook_mask);
 
+	/* Called when entry of this type deleted. */
+	void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
 };
@@ -374,6 +377,9 @@
 			  void *targinfo,
 			  unsigned int targinfosize,
 			  unsigned int hook_mask);
+
+	/* Called when entry of this type deleted. */
+	void (*destroy)(void *targinfo, unsigned int targinfosize);
 
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.3.99-pre6/linux/include/linux/nfs_fs.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/nfs_fs.h	Thu May 11 11:27:10 2000
@@ -175,7 +175,7 @@
 /*
  * linux/fs/nfs/write.c
  */
-extern int  nfs_writepage(struct file *file, struct dentry *, struct page *);
+extern int  nfs_writepage(struct file *file, struct page *);
 extern int  nfs_flush_incompatible(struct file *file, struct page *page);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
 /*
@@ -232,7 +232,7 @@
 /*
  * linux/fs/nfs/read.c
  */
-extern int  nfs_readpage(struct dentry *, struct page *);
+extern int  nfs_readpage(struct file *, struct page *);
 extern int  nfs_pagein_inode(struct inode *, unsigned long, unsigned int);
 extern int  nfs_pagein_timeout(struct inode *);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/nfsd/export.h linux/include/linux/nfsd/export.h
--- v2.3.99-pre6/linux/include/linux/nfsd/export.h	Fri Mar 10 16:40:50 2000
+++ linux/include/linux/nfsd/export.h	Thu May 11 11:30:18 2000
@@ -62,6 +62,7 @@
 	struct svc_export *	ex_parent;
 	struct svc_client *	ex_client;
 	int			ex_flags;
+	struct vfsmount *	ex_mnt;
 	struct dentry *		ex_dentry;
 	kdev_t			ex_dev;
 	ino_t			ex_ino;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/ntfs_fs_sb.h linux/include/linux/ntfs_fs_sb.h
--- v2.3.99-pre6/linux/include/linux/ntfs_fs_sb.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/ntfs_fs_sb.h	Tue May  2 13:46:53 2000
@@ -15,7 +15,10 @@
 	ntfs_u32 at_standard_information;
 	ntfs_u32 at_attribute_list;
 	ntfs_u32 at_file_name;
+	ntfs_u32 at_volume_version;
 	ntfs_u32 at_security_descriptor;
+	ntfs_u32 at_volume_name;
+	ntfs_u32 at_volume_information;
 	ntfs_u32 at_data;
 	ntfs_u32 at_index_root;
 	ntfs_u32 at_index_allocation;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.3.99-pre6/linux/include/linux/pagemap.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/pagemap.h	Thu May 11 11:26:55 2000
@@ -80,6 +80,7 @@
 extern void __add_page_to_hash_queue(struct page * page, struct page **p);
 
 extern void add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long index);
+extern void add_to_page_cache_locked(struct page * page, struct address_space *mapping, unsigned long index);
 
 extern inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long index)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.99-pre6/linux/include/linux/pci_ids.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/pci_ids.h	Sat Apr 29 10:19:57 2000
@@ -332,6 +332,7 @@
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5591		0x5591
 #define PCI_DEVICE_ID_SI_5597		0x5597
+#define PCI_DEVICE_ID_SI_5598		0x5598
 #define PCI_DEVICE_ID_SI_5600		0x5600
 #define PCI_DEVICE_ID_SI_6306		0x6306
 #define PCI_DEVICE_ID_SI_6326		0x6326
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/pipe_fs_i.h linux/include/linux/pipe_fs_i.h
--- v2.3.99-pre6/linux/include/linux/pipe_fs_i.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/pipe_fs_i.h	Mon May  8 11:17:47 2000
@@ -1,6 +1,7 @@
 #ifndef _LINUX_PIPE_FS_I_H
 #define _LINUX_PIPE_FS_I_H
 
+#define PIPEFS_MAGIC 0x50495045
 struct pipe_inode_info {
 	wait_queue_head_t wait;
 	char *base;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/ppp_channel.h linux/include/linux/ppp_channel.h
--- v2.3.99-pre6/linux/include/linux/ppp_channel.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/ppp_channel.h	Thu May 11 11:27:15 2000
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/poll.h>
+#include <asm/atomic.h>
 
 struct ppp_channel;
 
@@ -31,6 +32,7 @@
 	int	(*start_xmit)(struct ppp_channel *, struct sk_buff *);
 	/* Handle an ioctl call that has come in via /dev/ppp. */
 	int	(*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
+	
 };
 
 struct ppp_channel {
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.99-pre6/linux/include/linux/proc_fs.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/proc_fs.h	Thu May 11 11:26:55 2000
@@ -96,7 +96,7 @@
 						struct proc_dir_entry *parent);
 extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
 
-extern struct super_block *proc_super_blocks;
+extern struct vfsmount *proc_mnt;
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
 extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/quotaops.h linux/include/linux/quotaops.h
--- v2.3.99-pre6/linux/include/linux/quotaops.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/quotaops.h	Thu May 11 11:29:44 2000
@@ -14,6 +14,8 @@
 
 #if defined(CONFIG_QUOTA)
 
+#include <linux/smp_lock.h>
+
 /*
  * declaration of quota_function calls in kernel.
  */
@@ -94,8 +96,10 @@
 	int error = -EDQUOT;
 
 	if (dentry->d_inode->i_sb->dq_op) {
+		lock_kernel();
 		dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
 		error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr);
+		unlock_kernel();
 	} else {
 		error = notify_change(dentry, iattr);
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.99-pre6/linux/include/linux/sched.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/sched.h	Thu May 11 11:26:54 2000
@@ -203,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 min_flt, maj_flt, rss, total_vm, locked_vm;
+	unsigned long 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 */
@@ -225,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 {
@@ -310,7 +310,6 @@
 /* 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;
@@ -346,8 +345,8 @@
 /* Thread group tracking */
    	u32 parent_exec_id;
    	u32 self_exec_id;
-/* Protection of fields allocatio/deallocation */
-	struct semaphore exit_sem;
+/* Protection of (de-)allocation: mm, files, fs, tty */
+	spinlock_t alloc_lock;
 };
 
 /*
@@ -418,7 +417,7 @@
     blocked:		{{0}},						\
     sigqueue:		NULL,						\
     sigqueue_tail:	&tsk.sigqueue,					\
-    exit_sem:		__MUTEX_INITIALIZER(tsk.exit_sem)		\
+    alloc_lock:		SPIN_LOCK_UNLOCKED				\
 }
 
 
@@ -442,7 +441,7 @@
 
 #define pid_hashfn(x)	((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-extern __inline__ void hash_pid(struct task_struct *p)
+static inline void hash_pid(struct task_struct *p)
 {
 	struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
 
@@ -452,14 +451,14 @@
 	p->pidhash_pprev = htable;
 }
 
-extern __inline__ void unhash_pid(struct task_struct *p)
+static inline void unhash_pid(struct task_struct *p)
 {
 	if(p->pidhash_next)
 		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
 	*p->pidhash_pprev = p->pidhash_next;
 }
 
-extern __inline__ struct task_struct *find_task_by_pid(int pid)
+static inline struct task_struct *find_task_by_pid(int pid)
 {
 	struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
 
@@ -525,7 +524,7 @@
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
-extern inline int signal_pending(struct task_struct *p)
+static inline int signal_pending(struct task_struct *p)
 {
 	return (p->sigpending != 0);
 }
@@ -593,7 +592,7 @@
  * These will be removed, but in the mean time, when the SECURE_NOROOT 
  * flag is set, uids don't grant privilege.
  */
-extern inline int suser(void)
+static inline int suser(void)
 {
 	if (!issecure(SECURE_NOROOT) && current->euid == 0) { 
 		current->flags |= PF_SUPERPRIV;
@@ -602,7 +601,7 @@
 	return 0;
 }
 
-extern inline int fsuser(void)
+static inline int fsuser(void)
 {
 	if (!issecure(SECURE_NOROOT) && current->fsuid == 0) {
 		current->flags |= PF_SUPERPRIV;
@@ -617,7 +616,7 @@
  * fsuser(). See include/linux/capability.h for defined capabilities.
  */
 
-extern inline int capable(int cap)
+static inline int capable(int cap)
 {
 #if 1 /* ok now */
 	if (cap_raised(current->cap_effective, cap))
@@ -707,7 +706,7 @@
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
 
-extern inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+static inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -716,7 +715,7 @@
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-extern inline void add_wait_queue_exclusive(wait_queue_head_t *q,
+static inline void add_wait_queue_exclusive(wait_queue_head_t *q,
 							wait_queue_t * wait)
 {
 	unsigned long flags;
@@ -726,7 +725,7 @@
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-extern inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+static inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -820,12 +819,12 @@
 	p->run_list.next = NULL;
 }
 
-extern inline int task_on_runqueue(struct task_struct *p)
+static inline int task_on_runqueue(struct task_struct *p)
 {
 	return (p->run_list.next != NULL);
 }
 
-extern inline void unhash_process(struct task_struct *p)
+static inline void unhash_process(struct task_struct *p)
 {
 	if (task_on_runqueue(p)) BUG();
 	write_lock_irq(&tasklist_lock);
@@ -835,19 +834,14 @@
 	write_unlock_irq(&tasklist_lock);
 }
 
-static inline int task_lock(struct task_struct *p)
+static inline void task_lock(struct task_struct *p)
 {
-	down(&p->exit_sem);
-	if (p->p_pptr)
-		return 1;
-	/* He's dead, Jim. You take his wallet, I'll take the tricorder... */
-	up(&p->exit_sem);
-	return 0;
+	spin_lock(&p->alloc_lock);
 }
 
 static inline void task_unlock(struct task_struct *p)
 {
-	up(&p->exit_sem);
+	spin_unlock(&p->alloc_lock);
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.3.99-pre6/linux/include/linux/socket.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/socket.h	Thu May 11 11:26:54 2000
@@ -167,6 +167,7 @@
 #define AF_ATMSVC	20	/* ATM SVCs			*/
 #define AF_SNA		22	/* Linux SNA Project (nutters!) */
 #define AF_IRDA		23	/* IRDA sockets			*/
+#define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_MAX		32	/* For now.. */
 
 /* Protocol families, same as address families. */
@@ -195,7 +196,7 @@
 #define PF_ATMSVC	AF_ATMSVC
 #define PF_SNA		AF_SNA
 #define PF_IRDA		AF_IRDA
-
+#define PF_PPPOX	AF_PPPOX
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/string.h linux/include/linux/string.h
--- v2.3.99-pre6/linux/include/linux/string.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/string.h	Thu May 11 11:26:54 2000
@@ -9,34 +9,72 @@
 #endif
 
 extern char * ___strtok;
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern char * strsep(char **,const char *);
+extern __kernel_size_t strspn(const char *,const char *);
+
+
+/*
+ * Include machine specific inline routines
+ */
+#include <asm/string.h>
+
+#ifndef __HAVE_ARCH_STRCPY
 extern char * strcpy(char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCPY
 extern char * strncpy(char *,const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCAT
 extern char * strncat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCMP
+extern int strcmp(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCMP
+extern int strncmp(const char *,const char *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRNICMP
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCHR
 extern char * strchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
-extern char * strpbrk(const char *,const char *);
-extern char * strtok(char *,const char *);
-extern char * strsep(char **,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRLEN
 extern __kernel_size_t strlen(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNLEN
 extern __kernel_size_t strnlen(const char *,__kernel_size_t);
-extern __kernel_size_t strspn(const char *,const char *);
-extern int strcmp(const char *,const char *);
-extern int strncmp(const char *,const char *,__kernel_size_t);
-extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
 
+#ifndef __HAVE_ARCH_MEMSET
 extern void * memset(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCPY
 extern void * memcpy(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMMOVE
 extern void * memmove(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMSCAN
 extern void * memscan(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCMP
 extern int memcmp(const void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *,int,__kernel_size_t);
-
-/*
- * Include machine specific inline routines
- */
-#include <asm/string.h>
+#endif
 
 #ifdef __cplusplus
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.99-pre6/linux/include/linux/swap.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/swap.h	Thu May 11 14:50:08 2000
@@ -80,14 +80,13 @@
 
 struct zone_t;
 /* linux/ipc/shm.c */
-extern int shm_swap (int, int, zone_t *);
+extern int shm_swap(int, int);
 
 /* linux/mm/swap.c */
-extern void swap_setup (void);
+extern void swap_setup(void);
 
 /* 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);
+extern int try_to_free_pages(unsigned int gfp_mask);
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *, int);
@@ -121,7 +120,6 @@
 					struct inode **);
 extern int swap_duplicate(swp_entry_t);
 extern int swap_count(struct page *);
-extern swp_entry_t acquire_swap_entry(struct page *page);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
 #define get_swap_page() __get_swap_page(1)
 extern void __swap_free(swp_entry_t, unsigned short);
@@ -173,13 +171,18 @@
 	spin_unlock(&pagemap_lru_lock);		\
 } while (0)
 
+#define	__lru_cache_del(page)			\
+do {						\
+	list_del(&(page)->lru);			\
+	nr_lru_pages--;				\
+} while (0)
+
 #define	lru_cache_del(page)			\
 do {						\
 	if (!PageLocked(page))			\
 		BUG();				\
 	spin_lock(&pagemap_lru_lock);		\
-	list_del(&(page)->lru);			\
-	nr_lru_pages--;				\
+	__lru_cache_del(page);			\
 	spin_unlock(&pagemap_lru_lock);		\
 } while (0)
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.3.99-pre6/linux/include/linux/timer.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/timer.h	Thu May 11 11:26:54 2000
@@ -2,6 +2,7 @@
 #define _LINUX_TIMER_H
 
 #include <linux/config.h>
+#include <linux/list.h>
 
 /*
  * Old-style timers. Please don't use for any new code.
@@ -47,8 +48,7 @@
  * to distinguish between the different invocations.
  */
 struct timer_list {
-	struct timer_list *next; /* MUST be first element */
-	struct timer_list *prev;
+	struct list_head list;
 	unsigned long expires;
 	unsigned long data;
 	void (*function)(unsigned long);
@@ -56,7 +56,7 @@
 };
 
 extern void add_timer(struct timer_list * timer);
-extern int  del_timer(struct timer_list * timer);
+extern int del_timer(struct timer_list * timer);
 
 /*
  * mod_timer is a more efficient way to update the expire field of an
@@ -67,18 +67,17 @@
 
 extern void it_real_fn(unsigned long);
 
-extern inline void init_timer(struct timer_list * timer)
+static inline void init_timer(struct timer_list * timer)
 {
-	timer->next = NULL;
-	timer->prev = NULL;
+	timer->list.next = timer->list.prev = NULL;
 #ifdef CONFIG_SMP
 	timer->running = 0;
 #endif
 }
 
-extern inline int timer_pending(const struct timer_list * timer)
+static inline int timer_pending (const struct timer_list * timer)
 {
-	return timer->prev != NULL;
+	return timer->list.next != NULL;
 }
 
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.3.99-pre6/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.3.99-pre6/linux/include/linux/usb.h	Wed Apr 26 16:34:09 2000
+++ linux/include/linux/usb.h	Mon May  8 17:37:44 2000
@@ -82,18 +82,19 @@
 #define USB_PID_OUT                            0xe1
 #define USB_PID_ACK                            0xd2
 #define USB_PID_DATA0                          0xc3
-#define USB_PID_UNDEF_4                        0xb4
+#define USB_PID_PING                           0xb4	/* USB 2.0 */
 #define USB_PID_SOF                            0xa5
-#define USB_PID_UNDEF_6                        0x96
-#define USB_PID_UNDEF_7                        0x87
-#define USB_PID_UNDEF_8                        0x78
+#define USB_PID_NYET                           0x96	/* USB 2.0 */
+#define USB_PID_DATA2                          0x87	/* USB 2.0 */
+#define USB_PID_SPLIT                          0x78	/* USB 2.0 */
 #define USB_PID_IN                             0x69
 #define USB_PID_NAK                            0x5a
 #define USB_PID_DATA1                          0x4b
-#define USB_PID_PREAMBLE                       0x3c
+#define USB_PID_PREAMBLE                       0x3c	/* Token mode */
+#define USB_PID_ERR                            0x3c	/* USB 2.0: handshake mode */
 #define USB_PID_SETUP                          0x2d
 #define USB_PID_STALL                          0x1e
-#define USB_PID_UNDEF_F                        0x0f
+#define USB_PID_MDATA                          0x0f	/* USB 2.0 */
 
 /*
  * Standard requests
@@ -134,43 +135,6 @@
 
 #define USB_MAJOR 180
 
-/* for 2.2-kernels */
- 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-
-static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
-{
-	__list_add(new, head->prev, head);
-}
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-typedef struct wait_queue wait_queue_t;
-
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
-	struct wait_queue wait = { current, NULL }
-#define DECLARE_WAIT_QUEUE_HEAD(wait)\
-	wait_queue_head_t wait
-
-#define init_waitqueue_head(x) *x=NULL
-#define init_MUTEX(x) *(x)=MUTEX
-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED
-
-
-#define __set_current_state(state_value)                        \
-	do { current->state = state_value; } while (0)
-#ifdef CONFIG_SMP
-#define set_current_state(state_value)          \
-	set_mb(current->state, state_value)
-#else
-#define set_current_state(state_value)          \
-	__set_current_state(state_value)
-#endif
-
-#endif // 2.2.x
-
-
 static __inline__ void wait_ms(unsigned int ms)
 {
 	if(!in_interrupt()) {
@@ -593,12 +557,6 @@
 extern void usb_release_bandwidth(struct usb_device *, int);
 
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
-
-extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
-extern int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe);
-
-extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
-extern int usb_terminate_bulk(struct usb_device *, void *);
 
 extern void usb_init_root_hub(struct usb_device *dev);
 extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len);
diff -u --recursive --new-file v2.3.99-pre6/linux/include/net/atmclip.h linux/include/net/atmclip.h
--- v2.3.99-pre6/linux/include/net/atmclip.h	Sat Feb 26 22:32:07 2000
+++ linux/include/net/atmclip.h	Thu May 11 11:32:04 2000
@@ -48,7 +48,6 @@
 
 
 struct clip_priv {
-	char name[8];			/* interface name */
 	int number;			/* for convenience ... */
 	spinlock_t xoff_lock;		/* ensures that pop is atomic (SMP) */
 	struct net_device_stats stats;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/net/irda/irlan_common.h linux/include/net/irda/irlan_common.h
--- v2.3.99-pre6/linux/include/net/irda/irlan_common.h	Sun Nov  7 16:37:34 1999
+++ linux/include/net/irda/irlan_common.h	Thu May  4 11:31:21 2000
@@ -164,7 +164,6 @@
 	queue_t q; /* Must be first */
 
 	int    magic;
-	char   ifname[9];
 	struct net_device dev;        /* Ethernet device structure*/
 	struct enet_statistics stats;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.99-pre6/linux/include/net/sock.h	Wed Apr 26 16:34:09 2000
+++ linux/include/net/sock.h	Thu May 11 11:27:15 2000
@@ -66,6 +66,11 @@
 #endif
 #endif
 
+#if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE)
+#include <linux/if_pppox.h>
+#include <linux/ppp_channel.h>   /* struct ppp_channel */
+#endif
+
 #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
 #if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
 #include <net/spx.h>
@@ -102,6 +107,7 @@
 struct unix_opt {
 	struct unix_address	*addr;
 	struct dentry *		dentry;
+	struct vfsmount *	mnt;
 	struct semaphore	readsem;
 	struct sock *		other;
 	struct sock **		list;
@@ -204,6 +210,28 @@
 };
 #endif
 
+#if defined(CONFIG_PPPOE) || defined (CONFIG_PPPOE_MODULE)
+struct pppoe_opt
+{
+	struct net_device      *dev;	  /* device associated with socket*/
+	struct pppoe_addr	pa;	  /* what this socket is bound to*/
+	struct sockaddr_pppox	relay;	  /* what socket data will be
+					     relayed to (PPPoE relaying) */
+};
+
+struct pppox_opt
+{
+	struct ppp_channel	chan;
+	struct sock		*sk;
+	struct pppox_opt	*next;	  /* for hash table */
+	union {
+		struct pppoe_opt pppoe;
+	} proto;
+};
+#define pppoe_dev	proto.pppoe.dev
+#define pppoe_pa	proto.pppoe.pa
+#define pppoe_relay	proto.pppoe.relay
+#endif
 
 /* This defines a selective acknowledgement block. */
 struct tcp_sack_block {
@@ -583,6 +611,9 @@
 #endif
 #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
 		rose_cb			*rose;
+#endif
+#if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE)
+		struct pppox_opt	*pppox;
 #endif
 #ifdef CONFIG_NETLINK
 		struct netlink_opt	*af_netlink;
diff -u --recursive --new-file v2.3.99-pre6/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.99-pre6/linux/include/net/tcp.h	Wed Apr 26 16:34:09 2000
+++ linux/include/net/tcp.h	Thu May 11 11:31:16 2000
@@ -1079,7 +1079,7 @@
 
 static __inline__ void tcp_check_probe_timer(struct sock *sk, struct tcp_opt *tp)
 {
-	if (!tp->packets_out && !tp->probe_timer.prev)
+	if (!tp->packets_out && !timer_pending(&tp->probe_timer))
 		tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, tp->rto);
 }
 
@@ -1505,13 +1505,13 @@
 
 	switch (what) {
 	case TCP_TIME_RETRANS:
-		ret = tp->retransmit_timer.prev != NULL;
+		ret = timer_pending(&tp->retransmit_timer);
 		break;
 	case TCP_TIME_DACK:
-		ret = tp->delack_timer.prev != NULL;
+		ret = timer_pending(&tp->delack_timer);
 		break;
 	case TCP_TIME_PROBE0:
-		ret = tp->probe_timer.prev != NULL;
+		ret = timer_pending(&tp->probe_timer);
 		break;	
 	default:
 		ret = 0;
diff -u --recursive --new-file v2.3.99-pre6/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.99-pre6/linux/ipc/shm.c	Wed Apr 26 16:34:09 2000
+++ linux/ipc/shm.c	Wed May 10 09:45:45 2000
@@ -132,7 +132,7 @@
 static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 #endif
 
-static void zshm_swap (int prio, int gfp_mask, zone_t *zone);
+static void zshm_swap (int prio, int gfp_mask);
 static void zmap_unuse(swp_entry_t entry, struct page *page);
 static void shmzero_open(struct vm_area_struct *shmd);
 static void shmzero_close(struct vm_area_struct *shmd);
@@ -145,7 +145,7 @@
 
 static struct super_block * shm_sb;
 
-static DECLARE_FSTYPE(shm_fs_type, "shm", shm_read_super, 0);
+static DECLARE_FSTYPE(shm_fs_type, "shm", shm_read_super, FS_SINGLE);
 
 static struct super_operations shm_sops = {
 	read_inode:	shm_read_inode,
@@ -214,9 +214,15 @@
 
 void __init shm_init (void)
 {
+	struct vfsmount *res;
 	ipc_init_ids(&shm_ids, 1);
 
 	register_filesystem (&shm_fs_type);
+	res = kern_mount(&shm_fs_type);
+	if (IS_ERR(res)) {
+		unregister_filesystem(&shm_fs_type);
+		return;
+	}
 #ifdef CONFIG_PROC_FS
 	create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
 #endif
@@ -276,11 +282,6 @@
 {
 	struct inode * root_inode;
 
-	if (shm_sb) {
-		printk(KERN_ERR "shm fs already mounted\n");
-		return NULL;
-	}
-
 	shm_ctlall = SHMALL;
 	shm_ctlmni = SHMMNI;
 	shm_mode   = S_IRWXUGO | S_ISVTX;
@@ -303,7 +304,6 @@
 	s->s_root = d_alloc_root(root_inode);
 	if (!s->s_root)
 		goto out_no_root;
-	s->u.generic_sbp = (void*) shm_sb;
 	shm_sb = s;
 	return s;
 
@@ -342,16 +342,9 @@
 
 static void shm_put_super(struct super_block *sb)
 {
-	struct super_block **p = &shm_sb;
 	int i;
 	struct shmid_kernel *shp;
 
-	while (*p != sb) {
-		if (!*p)	/* should never happen */
-			return;
-		p = (struct super_block **)&(*p)->u.generic_sbp;
-	}
-	*p = (struct super_block *)(*p)->u.generic_sbp;
 	down(&shm_ids.sem);
 	for(i = 0; i <= shm_ids.max_id; i++) {
 		if (i == zero_id)
@@ -747,8 +740,9 @@
 	if (shm_tot + numpages >= shm_ctlall)
 		return -ENOSPC;
 
-	if (!(shp = seg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
-		return -ENOMEM;
+	shp = seg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1);
+	if (IS_ERR(shp))
+		return PTR_ERR(shp);
 	id = shm_addid(shp);
 	if(id == -1) {
 		seg_free(shp, 1);
@@ -778,13 +772,6 @@
 {
 	struct shmid_kernel *shp;
 	int err, id = 0;
-	static int count=0;
-
-	if (!shm_sb) {
-		if(count++<5)
-			printk(KERN_WARNING "shmget: shm filesystem not mounted\n");
-		return -EINVAL;
-	}
 
 	if (size < SHMMIN)
 		return -EINVAL;
@@ -928,13 +915,6 @@
 	struct shm_setbuf setbuf;
 	struct shmid_kernel *shp;
 	int err, version;
-	static int count;
-
-	if (!shm_sb) {
-		if(count++<5)
-			printk (KERN_WARNING "shmctl: shm filesystem not mounted\n");
-		return -EINVAL;
-	}
 
 	if (cmd < 0 || shmid < 0)
 		return -EINVAL;
@@ -1162,7 +1142,6 @@
 /*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
  */
-/* MOUNT_REWRITE: kernel vfsmnt of shmfs should be passed to __filp_open() */
 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
 	unsigned long addr;
@@ -1202,6 +1181,7 @@
 	sprintf (name, SHM_FMT, shmid);
 
 	lock_kernel();
+	mntget(shm_fs_type.kern_mnt);
 	dentry = lookup_one(name, lock_parent(shm_sb->s_root));
 	unlock_dir(shm_sb->s_root);
 	err = PTR_ERR(dentry);
@@ -1212,11 +1192,11 @@
 		goto bad_file;
 	err = permission(dentry->d_inode, acc_mode);
 	if (err)
-		goto bad_file;
-	file = dentry_open(dentry, NULL, o_flags);
+		goto bad_file1;
+	file = dentry_open(dentry, shm_fs_type.kern_mnt, o_flags);
 	err = PTR_ERR(file);
 	if (IS_ERR (file))
-		goto bad_file;
+		goto bad_file1;
 	down(&current->mm->mmap_sem);
 	*raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
 			  prot, flags, 0);
@@ -1229,7 +1209,10 @@
 	fput (file);
 	return err;
 
+bad_file1:
+	dput(dentry);
 bad_file:
+	mntput(shm_fs_type.kern_mnt);
 	unlock_kernel();
 	if (err == -ENOENT)
 		return -EINVAL;
@@ -1394,12 +1377,10 @@
 		(*rss)++;
 		pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
 		SHM_ENTRY(shp, idx) = pte;
-	} else
-		--current->maj_flt;  /* was incremented in do_no_page */
+	}
 
 	/* pte_val(pte) == SHM_ENTRY (shp, idx) */
 	get_page(pte_page(pte));
-	current->min_flt++;
 	return pte_page(pte);
 
 oom:
@@ -1430,7 +1411,7 @@
 #define RETRY	1
 #define FAILED	2
 
-static int shm_swap_core(struct shmid_kernel *shp, unsigned long idx, swp_entry_t swap_entry, zone_t *zone, int *counter, struct page **outpage)
+static int shm_swap_core(struct shmid_kernel *shp, unsigned long idx, swp_entry_t swap_entry, int *counter, struct page **outpage)
 {
 	pte_t page;
 	struct page *page_map;
@@ -1439,7 +1420,7 @@
 	if (!pte_present(page))
 		return RETRY;
 	page_map = pte_page(page);
-	if (zone && (!memclass(page_map->zone, zone)))
+	if (page_map->zone->free_pages > page_map->zone->pages_high)
 		return RETRY;
 	if (shp->id != zero_id) swap_attempts++;
 
@@ -1448,6 +1429,7 @@
 	if (page_count(page_map) != 1)
 		return RETRY;
 
+	lock_page(page_map);
 	if (!(page_map = prepare_highmem_swapout(page_map)))
 		return FAILED;
 	SHM_ENTRY (shp, idx) = swp_entry_to_pte(swap_entry);
@@ -1491,7 +1473,7 @@
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
 
-int shm_swap (int prio, int gfp_mask, zone_t *zone)
+int shm_swap (int prio, int gfp_mask)
 {
 	struct shmid_kernel *shp;
 	swp_entry_t swap_entry;
@@ -1500,7 +1482,7 @@
 	int counter;
 	struct page * page_map;
 
-	zshm_swap(prio, gfp_mask, zone);
+	zshm_swap(prio, gfp_mask);
 	counter = shm_rss >> prio;
 	if (!counter)
 		return 0;
@@ -1532,7 +1514,7 @@
 	if (idx >= shp->shm_npages)
 		goto next_id;
 
-	switch (shm_swap_core(shp, idx, swap_entry, zone, &counter, &page_map)) {
+	switch (shm_swap_core(shp, idx, swap_entry, &counter, &page_map)) {
 		case RETRY: goto check_table;
 		case FAILED: goto failed;
 	}
@@ -1694,7 +1676,6 @@
  * on the pseudo-file. This is possible because the open/close calls
  * are bracketed by the file count update calls.
  */
-/* MOUNT_REWRITE: set ->f_vfsmnt to shmfs one */
 static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
 {
 	struct file *filp;
@@ -1712,14 +1693,14 @@
 		put_filp(filp);
 		return(0);
 	}
-	filp->f_vfsmnt = NULL;
+	filp->f_vfsmnt = mntget(shm_fs_type.kern_mnt);
 	d_instantiate(filp->f_dentry, inp);
 
 	/*
 	 * Copy over dev/ino for benefit of procfs. Use
 	 * ino to indicate seperate mappings.
 	 */
-	filp->f_dentry->d_inode->i_dev = shm_sb->s_dev;
+	filp->f_dentry->d_inode->i_dev = shm_fs_type.kern_mnt->mnt_sb->s_dev;
 	filp->f_dentry->d_inode->i_ino = (unsigned long)shp;
 	if (fzero)
 		fput(fzero);	/* release /dev/zero file */
@@ -1819,7 +1800,7 @@
 	spin_unlock(&zmap_list_lock);
 }
 
-static void zshm_swap (int prio, int gfp_mask, zone_t *zone)
+static void zshm_swap (int prio, int gfp_mask)
 {
 	struct shmid_kernel *shp;
 	swp_entry_t swap_entry;
@@ -1864,7 +1845,7 @@
 		goto next_id;
 	}
 
-	switch (shm_swap_core(shp, idx, swap_entry, zone, &counter, &page_map)) {
+	switch (shm_swap_core(shp, idx, swap_entry, &counter, &page_map)) {
 		case RETRY: goto check_table;
 		case FAILED: goto failed;
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/ipc/util.c linux/ipc/util.c
--- v2.3.99-pre6/linux/ipc/util.c	Fri Mar 10 16:40:50 2000
+++ linux/ipc/util.c	Mon May  8 16:29:38 2000
@@ -249,7 +249,7 @@
     return;
 }
 
-int shm_swap (int prio, int gfp_mask, zone_t *zone)
+int shm_swap (int prio, int gfp_mask)
 {
     return 0;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
--- v2.3.99-pre6/linux/kernel/exec_domain.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/exec_domain.c	Tue May  9 16:18:27 2000
@@ -110,9 +110,16 @@
 	if (it) {
 		if (atomic_read(&current->fs->count) != 1) {
 			struct fs_struct *new = copy_fs_struct(current->fs);
-			if (!new)
+			struct fs_struct *old;
+			if (!new) {
+				put_exec_domain(it);
 				return;
-			put_fs_struct(xchg(&current->fs,new));
+			}
+			task_lock(current);
+			old = current->fs;
+			current->fs = new;
+			task_unlock(current);
+			put_fs_struct(old);
 		}
 		/*
 		 * At that point we are guaranteed to be the sole owner of
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.99-pre6/linux/kernel/exit.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/exit.c	Tue May  9 16:18:27 2000
@@ -182,24 +182,32 @@
 
 extern kmem_cache_t *files_cachep;  
 
+void put_files_struct(struct files_struct *files)
+{
+	if (atomic_dec_and_test(&files->count)) {
+		close_files(files);
+		/*
+		 * Free the fd and fdset arrays if we expanded them.
+		 */
+		if (files->fd != &files->fd_array[0])
+			free_fd_array(files->fd, files->max_fds);
+		if (files->max_fdset > __FD_SETSIZE) {
+			free_fdset(files->open_fds, files->max_fdset);
+			free_fdset(files->close_on_exec, files->max_fdset);
+		}
+		kmem_cache_free(files_cachep, files);
+	}
+}
+
 static inline void __exit_files(struct task_struct *tsk)
 {
-	struct files_struct * files = xchg(&tsk->files, NULL);
+	struct files_struct * files = tsk->files;
 
 	if (files) {
-		if (atomic_dec_and_test(&files->count)) {
-			close_files(files);
-			/*
-			 * Free the fd and fdset arrays if we expanded them.
-			 */
-			if (files->fd != &files->fd_array[0])
-				free_fd_array(files->fd, files->max_fds);
-			if (files->max_fdset > __FD_SETSIZE) {
-				free_fdset(files->open_fds, files->max_fdset);
-				free_fdset(files->close_on_exec, files->max_fdset);
-			}
-			kmem_cache_free(files_cachep, files);
-		}
+		task_lock(tsk);
+		tsk->files = NULL;
+		task_unlock(tsk);
+		put_files_struct(files);
 	}
 }
 
@@ -232,7 +240,9 @@
 	struct fs_struct * fs = tsk->fs;
 
 	if (fs) {
+		task_lock(tsk);
 		tsk->fs = NULL;
+		task_unlock(tsk);
 		__put_fs_struct(fs);
 	}
 }
@@ -247,11 +257,9 @@
 	struct signal_struct * sig = tsk->sig;
 
 	if (sig) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&tsk->sigmask_lock, flags);
+		spin_lock_irq(&tsk->sigmask_lock);
 		tsk->sig = NULL;
-		spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
+		spin_unlock_irq(&tsk->sigmask_lock);
 		if (atomic_dec_and_test(&sig->count))
 			kfree(sig);
 	}
@@ -302,7 +310,10 @@
 		atomic_inc(&mm->mm_count);
 		mm_release();
 		if (mm != tsk->active_mm) BUG();
+		/* more a memory barrier than a real lock */
+		task_lock(tsk);
 		tsk->mm = NULL;
+		task_unlock(tsk);
 		enter_lazy_tlb(mm, current, smp_processor_id());
 		mmput(mm);
 	}
@@ -434,12 +445,10 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	__exit_sighand(tsk);
-	task_lock(tsk);
 	exit_thread();
 	tsk->state = TASK_ZOMBIE;
 	tsk->exit_code = code;
 	exit_notify();
-	task_unlock(tsk);
 	put_exec_domain(tsk->exec_domain);
 	if (tsk->binfmt && tsk->binfmt->module)
 		__MOD_DEC_USE_COUNT(tsk->binfmt->module);
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.99-pre6/linux/kernel/fork.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/fork.c	Fri May  5 12:22:54 2000
@@ -6,9 +6,9 @@
 
 /*
  *  'fork.c' contains the help-routines for the 'fork' system call
- * (see also system_call.s).
+ * (see also entry.S and others).
  * Fork is rather simple, once you get the hang of it, but the memory
- * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
+ * management can be a bitch. See 'mm/memory.c': 'copy_page_tables()'
  */
 
 #include <linux/config.h>
@@ -680,7 +680,7 @@
 	p->p_cptr = NULL;
 	init_waitqueue_head(&p->wait_chldexit);
 	p->vfork_sem = NULL;
-	sema_init(&p->exit_sem, 1);
+	spin_lock_init(&p->alloc_lock);
 
 	p->sigpending = 0;
 	sigemptyset(&p->signal);
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.99-pre6/linux/kernel/ksyms.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/ksyms.c	Mon May  8 22:21:57 2000
@@ -85,6 +85,7 @@
 
 #ifdef CONFIG_MODULES
 EXPORT_SYMBOL(get_module_symbol);
+EXPORT_SYMBOL(try_inc_mod_count);
 #endif
 EXPORT_SYMBOL(get_option);
 EXPORT_SYMBOL(get_options);
@@ -137,18 +138,20 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_empty_super);
-EXPORT_SYMBOL(remove_vfsmnt);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(_fput);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
-EXPORT_SYMBOL(__namei);
-EXPORT_SYMBOL(lookup_dentry);
-EXPORT_SYMBOL(walk_init);
-EXPORT_SYMBOL(walk_name);
+EXPORT_SYMBOL(follow_up);
+EXPORT_SYMBOL(follow_down);
+EXPORT_SYMBOL(path_init);
+EXPORT_SYMBOL(path_walk);
+EXPORT_SYMBOL(path_release);
+EXPORT_SYMBOL(__user_walk);
 EXPORT_SYMBOL(lookup_one);
+EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(d_alloc_root);
 EXPORT_SYMBOL(d_delete);
@@ -214,7 +217,6 @@
 EXPORT_SYMBOL(posix_unblock_lock);
 EXPORT_SYMBOL(locks_mandatory_area);
 EXPORT_SYMBOL(dput);
-EXPORT_SYMBOL(is_root_busy);
 EXPORT_SYMBOL(have_submounts);
 EXPORT_SYMBOL(prune_dcache);
 EXPORT_SYMBOL(shrink_dcache_sb);
@@ -230,6 +232,7 @@
 EXPORT_SYMBOL(vfs_rmdir);
 EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(vfs_rename);
+EXPORT_SYMBOL(vfs_statfs);
 EXPORT_SYMBOL(generic_read_dir);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(ROOT_DEV);
@@ -309,6 +312,9 @@
 /* filesystem registration */
 EXPORT_SYMBOL(register_filesystem);
 EXPORT_SYMBOL(unregister_filesystem);
+EXPORT_SYMBOL(kern_mount);
+EXPORT_SYMBOL(kern_umount);
+EXPORT_SYMBOL(may_umount);
 
 /* executable format registration */
 EXPORT_SYMBOL(register_binfmt);
@@ -351,7 +357,7 @@
 EXPORT_SYMBOL(autoirq_report);
 #endif
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(del_timer_sync);
 #endif
 EXPORT_SYMBOL(mod_timer);
@@ -361,7 +367,7 @@
 EXPORT_SYMBOL(timer_active);
 EXPORT_SYMBOL(timer_table);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /* Various random spinlocks we want to export */
 EXPORT_SYMBOL(tqueue_lock);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.99-pre6/linux/kernel/ptrace.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/ptrace.c	Fri May  5 12:22:54 2000
@@ -121,10 +121,13 @@
 	struct vm_area_struct * vma;
 
 	/* Worry about races with exit() */
-	lock_kernel();
+	task_lock(tsk);
 	mm = tsk->mm;
-	atomic_inc(&mm->mm_users);
-	unlock_kernel();
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(tsk);
+	if (!mm)
+		return 0;
 
 	down(&mm->mmap_sem);
 	vma = find_extend_vma(mm, addr);
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.99-pre6/linux/kernel/sched.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/sched.c	Tue May  2 16:49:58 2000
@@ -1157,6 +1157,8 @@
 	sched_data->last_schedule = get_cycles();
 }
 
+extern void init_timervecs (void);
+
 void __init sched_init(void)
 {
 	/*
@@ -1170,6 +1172,8 @@
 
 	for(nr = 0; nr < PIDHASH_SZ; nr++)
 		pidhash[nr] = NULL;
+
+	init_timervecs();
 
 	init_bh(TIMER_BH, timer_bh);
 	init_bh(TQUEUE_BH, tqueue_bh);
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/signal.c linux/kernel/signal.c
--- v2.3.99-pre6/linux/kernel/signal.c	Mon Mar 27 08:08:32 2000
+++ linux/kernel/signal.c	Mon May  8 22:00:01 2000
@@ -6,6 +6,7 @@
  *  1997-11-02  Modified for POSIX.1b signals by Richard Henderson
  */
 
+#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/unistd.h>
@@ -386,7 +387,7 @@
 	sigaddset(&t->signal, sig);
 	if (!sigismember(&t->blocked, sig)) {
 		t->sigpending = 1;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		/*
 		 * If the task is running on a different CPU 
 		 * force a reschedule on the other CPU - note that
@@ -403,7 +404,7 @@
 		if (t->has_cpu && t->processor != smp_processor_id())
 			smp_send_reschedule(t->processor);
 		spin_unlock(&runqueue_lock);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	}
 
 out:
diff -u --recursive --new-file v2.3.99-pre6/linux/kernel/timer.c linux/kernel/timer.c
--- v2.3.99-pre6/linux/kernel/timer.c	Wed Apr 26 16:34:09 2000
+++ linux/kernel/timer.c	Tue May  2 16:49:58 2000
@@ -83,13 +83,13 @@
 #define TVR_MASK (TVR_SIZE - 1)
 
 struct timer_vec {
-        int index;
-        struct timer_list *vec[TVN_SIZE];
+	int index;
+	struct list_head vec[TVN_SIZE];
 };
 
 struct timer_vec_root {
-        int index;
-        struct timer_list *vec[TVR_SIZE];
+	int index;
+	struct list_head vec[TVR_SIZE];
 };
 
 static struct timer_vec tv5 = { 0 };
@@ -104,19 +104,22 @@
 
 #define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
 
-static unsigned long timer_jiffies = 0;
-
-static inline void insert_timer(struct timer_list *timer, struct timer_list **vec)
+void init_timervecs (void)
 {
-	struct timer_list *next = *vec;
+	int i;
 
-	timer->next = next;
-	if (next)
-		next->prev = timer;
-	*vec = timer;
-	timer->prev = (struct timer_list *)vec;
+	for (i = 0; i < TVN_SIZE; i++) {
+		INIT_LIST_HEAD(tv5.vec + i);
+		INIT_LIST_HEAD(tv4.vec + i);
+		INIT_LIST_HEAD(tv3.vec + i);
+		INIT_LIST_HEAD(tv2.vec + i);
+	}
+	for (i = 0; i < TVR_SIZE; i++)
+		INIT_LIST_HEAD(tv1.vec + i);
 }
 
+static unsigned long timer_jiffies = 0;
+
 static inline void internal_add_timer(struct timer_list *timer)
 {
 	/*
@@ -124,7 +127,7 @@
 	 */
 	unsigned long expires = timer->expires;
 	unsigned long idx = expires - timer_jiffies;
-	struct timer_list ** vec;
+	struct list_head * vec;
 
 	if (idx < TVR_SIZE) {
 		int i = expires & TVR_MASK;
@@ -148,10 +151,13 @@
 		vec = tv5.vec + i;
 	} else {
 		/* Can only get here on architectures with 64-bit jiffies */
-		timer->next = timer->prev = timer;
+		INIT_LIST_HEAD(&timer->list);
 		return;
 	}
-	insert_timer(timer, vec);
+	/*
+	 * Timers are FIFO!
+	 */
+	list_add(&timer->list, vec->prev);
 }
 
 spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
@@ -161,7 +167,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&timerlist_lock, flags);
-	if (timer->prev)
+	if (timer->list.next)
 		goto bug;
 	internal_add_timer(timer);
 out:
@@ -174,17 +180,12 @@
 	goto out;
 }
 
-static inline int detach_timer(struct timer_list *timer)
+static inline int detach_timer (struct timer_list *timer)
 {
-	struct timer_list *prev = timer->prev;
-	if (prev) {
-		struct timer_list *next = timer->next;
-		prev->next = next;
-		if (next)
-			next->prev = prev;
-		return 1;
-	}
-	return 0;
+	if (!timer_pending(timer))
+		return 0;
+	list_del(&timer->list);
+	return 1;
 }
 
 int mod_timer(struct timer_list *timer, unsigned long expires)
@@ -207,7 +208,7 @@
 
 	spin_lock_irqsave(&timerlist_lock, flags);
 	ret = detach_timer(timer);
-	timer->next = timer->prev = 0;
+	timer->list.next = timer->list.prev = NULL;
 	spin_unlock_irqrestore(&timerlist_lock, flags);
 	return ret;
 }
@@ -231,7 +232,7 @@
 
 		spin_lock_irqsave(&timerlist_lock, flags);
 		ret += detach_timer(timer);
-		timer->next = timer->prev = 0;
+		timer->list.next = timer->list.prev = 0;
 		running = timer->running;
 		spin_unlock_irqrestore(&timerlist_lock, flags);
 
@@ -247,42 +248,58 @@
 
 static inline void cascade_timers(struct timer_vec *tv)
 {
-        /* cascade all the timers from tv up one level */
-        struct timer_list *timer;
-        timer = tv->vec[tv->index];
-        /*
-         * We are removing _all_ timers from the list, so we don't  have to
-         * detach them individually, just clear the list afterwards.
-         */
-        while (timer) {
-                struct timer_list *tmp = timer;
-                timer = timer->next;
-                internal_add_timer(tmp);
-        }
-        tv->vec[tv->index] = NULL;
-        tv->index = (tv->index + 1) & TVN_MASK;
+	/* cascade all the timers from tv up one level */
+	struct list_head *head, *curr, *next;
+
+	head = tv->vec + tv->index;
+	curr = head->next;
+	/*
+	 * We are removing _all_ timers from the list, so we don't  have to
+	 * detach them individually, just clear the list afterwards.
+	 */
+	while (curr != head) {
+		struct timer_list *tmp;
+
+		tmp = list_entry(curr, struct timer_list, list);
+		next = curr->next;
+		list_del(curr); // not needed
+		internal_add_timer(tmp);
+		curr = next;
+	}
+	INIT_LIST_HEAD(head);
+	tv->index = (tv->index + 1) & TVN_MASK;
 }
 
 static inline void run_timer_list(void)
 {
 	spin_lock_irq(&timerlist_lock);
 	while ((long)(jiffies - timer_jiffies) >= 0) {
-		struct timer_list *timer;
+		struct list_head *head, *curr;
 		if (!tv1.index) {
 			int n = 1;
 			do {
 				cascade_timers(tvecs[n]);
 			} while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);
 		}
-		while ((timer = tv1.vec[tv1.index])) {
-			void (*fn)(unsigned long) = timer->function;
-			unsigned long data = timer->data;
+repeat:
+		head = tv1.vec + tv1.index;
+		curr = head->next;
+		if (curr != head) {
+			struct timer_list *timer;
+			void (*fn)(unsigned long);
+			unsigned long data;
+
+			timer = list_entry(curr, struct timer_list, list);
+ 			fn = timer->function;
+ 			data= timer->data;
+
 			detach_timer(timer);
-			timer->next = timer->prev = NULL;
+			timer->list.next = timer->list.prev = NULL;
 			timer_set_running(timer);
 			spin_unlock_irq(&timerlist_lock);
 			fn(data);
 			spin_lock_irq(&timerlist_lock);
+			goto repeat;
 		}
 		++timer_jiffies; 
 		tv1.index = (tv1.index + 1) & TVR_MASK;
@@ -340,7 +357,7 @@
     /* Bump the maxerror field */
     time_maxerror += time_tolerance >> SHIFT_USEC;
     if ( time_maxerror > NTP_PHASE_LIMIT ) {
-        time_maxerror = NTP_PHASE_LIMIT;
+	time_maxerror = NTP_PHASE_LIMIT;
 	time_status |= STA_UNSYNC;
     }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.99-pre6/linux/mm/filemap.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/filemap.c	Thu May 11 14:50:08 2000
@@ -46,7 +46,7 @@
 struct page **page_hash_table;
 struct list_head lru_cache;
 
-spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
 /*
  * NOTE: to avoid deadlocking you must never acquire the pagecache_lock with
  *       the pagemap_lru_lock held.
@@ -67,7 +67,7 @@
 		PAGE_BUG(page);
 }
 
-static void remove_page_from_hash_queue(struct page * page)
+static inline void remove_page_from_hash_queue(struct page * page)
 {
 	if(page->pprev_hash) {
 		if(page->next_hash)
@@ -92,47 +92,71 @@
  * sure the page is locked and that nobody else uses it - or that usage
  * is safe.
  */
+static inline void __remove_inode_page(struct page *page)
+{
+	remove_page_from_inode_queue(page);
+	remove_page_from_hash_queue(page);
+	page->mapping = NULL;
+}
+
 void remove_inode_page(struct page *page)
 {
 	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);
-	page->mapping = NULL;
+	__remove_inode_page(page);
 	spin_unlock(&pagecache_lock);
 }
 
+#define ITERATIONS 100
+
 void invalidate_inode_pages(struct inode * inode)
 {
 	struct list_head *head, *curr;
 	struct page * page;
+	int count;
 
- repeat:
 	head = &inode->i_mapping->pages;
-	spin_lock(&pagecache_lock);
-	curr = head->next;
 
-	while (curr != head) {
-		page = list_entry(curr, struct page, list);
-		curr = curr->next;
+	while (head != head->next) {
+		spin_lock(&pagecache_lock);
+		spin_lock(&pagemap_lru_lock);
+		head = &inode->i_mapping->pages;
+		curr = head->next;
+		count = 0;
+
+		while ((curr != head) && (count++ < ITERATIONS)) {
+			page = list_entry(curr, struct page, list);
+			curr = curr->next;
+
+			/* We cannot invalidate a locked page */
+			if (TryLockPage(page))
+				continue;
 
-		/* We cannot invalidate a locked page */
-		if (TryLockPage(page))
-			continue;
-		spin_unlock(&pagecache_lock);
+			__lru_cache_del(page);
+			__remove_inode_page(page);
+			UnlockPage(page);
+			page_cache_release(page);
+		}
 
-		lru_cache_del(page);
-		remove_inode_page(page);
-		UnlockPage(page);
-		page_cache_release(page);
-		goto repeat;
+		/* At this stage we have passed through the list
+		 * once, and there may still be locked pages. */
+
+		if (head->next!=head) {
+			page = list_entry(head->next, struct page, list);
+			get_page(page);
+			spin_unlock(&pagemap_lru_lock);
+			spin_unlock(&pagecache_lock);
+			/* We need to block */
+			lock_page(page);
+			UnlockPage(page);
+			page_cache_release(page);
+		} else {                                         
+			spin_unlock(&pagemap_lru_lock);
+			spin_unlock(&pagecache_lock);
+		}
 	}
-	spin_unlock(&pagecache_lock);
 }
 
 /*
@@ -163,10 +187,10 @@
 		/* page wholly truncated - free it */
 		if (offset >= start) {
 			if (TryLockPage(page)) {
-				spin_unlock(&pagecache_lock);
 				get_page(page);
+				spin_unlock(&pagecache_lock);
 				wait_on_page(page);
-				put_page(page);
+				page_cache_release(page);
 				goto repeat;
 			}
 			get_page(page);
@@ -236,57 +260,47 @@
 	spin_unlock(&pagecache_lock);
 }
 
-int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
+int shrink_mmap(int priority, int gfp_mask)
 {
-	int ret = 0, loop = 0, count;
-	LIST_HEAD(young);
+	int ret = 0, count;
 	LIST_HEAD(old);
-	LIST_HEAD(forget);
 	struct list_head * page_lru, * dispose;
 	struct page * page = NULL;
-	struct zone_struct * p_zone;
-	int maxloop = 256 >> priority;
 	
-	if (!zone)
-		BUG();
-
-	count = nr_lru_pages >> priority;
-	if (!count)
-		return ret;
+	count = nr_lru_pages / (priority + 1);
 
-	spin_lock(&pagemap_lru_lock);
-again:
 	/* we need pagemap_lru_lock for list_del() ... subtle code below */
+	spin_lock(&pagemap_lru_lock);
 	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;
 
-		/*
-		 * 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;
-		if (p_zone != zone && (loop > (maxloop / 4) ||
-				p_zone->free_pages > p_zone->pages_high))
+		dispose = &lru_cache;
+		if (PageTestandClearReferenced(page))
 			goto dispose_continue;
 
-		/* 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;
+		count--;
 
-		if (test_and_clear_bit(PG_referenced, &page->flags))
-			goto dispose_continue;
+		/*
+		 * I'm ambivalent on this one.. Should we try to
+		 * maintain LRU on the LRU list, and put pages that
+		 * are old at the end of the queue, even if that
+		 * means that we'll re-scan then again soon and
+		 * often waste CPU time? Or should be just let any
+		 * pages we do not want to touch now for one reason
+		 * or another percolate to be "young"?
+		 *
+		dispose = &old;
+		 *
+		 */
 
-		count--;
+		/*
+		 * Avoid unscalable SMP locking for pages we can
+		 * immediate tell are untouchable..
+		 */
 		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;
 
@@ -300,7 +314,10 @@
 		/* avoid freeing the page while it's locked */
 		get_page(page);
 
-		/* Is it a buffer page? */
+		/*
+		 * Is it a buffer page? Try to clean it up regardless
+		 * of zone - it's old.
+		 */
 		if (page->buffers) {
 			if (!try_to_free_buffers(page))
 				goto unlock_continue;
@@ -335,19 +352,23 @@
 			goto made_inode_progress;
 		}	
 
+		/*
+		 * Page is from a zone we don't care about.
+		 * Don't drop page cache entries in vain.
+		 */
+		if (page->zone->free_pages > page->zone->pages_high)
+			goto cache_unlock_continue;
+
 		/* is it a page-cache page? */
 		if (page->mapping) {
 			if (!PageDirty(page) && !pgcache_under_min()) {
-				remove_page_from_inode_queue(page);
-				remove_page_from_hash_queue(page);
-				page->mapping = NULL;
+				__remove_inode_page(page);
 				spin_unlock(&pagecache_lock);
 				goto made_inode_progress;
 			}
 			goto cache_unlock_continue;
 		}
 
-		dispose = &forget;
 		printk(KERN_ERR "shrink_mmap: unknown LRU page!\n");
 
 cache_unlock_continue:
@@ -356,10 +377,6 @@
 		spin_lock(&pagemap_lru_lock);
 		UnlockPage(page);
 		put_page(page);
-		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);
 	}
@@ -375,13 +392,7 @@
 	/* 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, &lru_cache);
 	list_splice(&old, lru_cache.prev);
 
 	spin_unlock(&pagemap_lru_lock);
@@ -403,7 +414,7 @@
 		if (page->index == offset)
 			break;
 	}
-	set_bit(PG_referenced, &page->flags);
+	SetPageReferenced(page);
 not_found:
 	return page;
 }
@@ -495,6 +506,26 @@
 }
 
 /*
+ * Add a page to the inode page cache.
+ *
+ * The caller must have locked the page and 
+ * set all the page flags correctly..
+ */
+void add_to_page_cache_locked(struct page * page, struct address_space *mapping, unsigned long index)
+{
+	if (!PageLocked(page))
+		BUG();
+
+	get_page(page);
+	spin_lock(&pagecache_lock);
+	page->index = index;
+	add_page_to_inode_queue(mapping, page);
+	__add_page_to_hash_queue(page, page_hash(mapping, index));
+	lru_cache_add(page);
+	spin_unlock(&pagecache_lock);
+}
+
+/*
  * This adds a page to the page cache, starting out as locked,
  * owned by us, referenced, but not uptodate and with no errors.
  */
@@ -569,7 +600,7 @@
 		return -ENOMEM;
 
 	if (!add_to_page_cache_unique(page, mapping, offset, hash)) {
-		int error = mapping->a_ops->readpage(file->f_dentry, page);
+		int error = mapping->a_ops->readpage(file, page);
 		page_cache_release(page);
 		return error;
 	}
@@ -1104,7 +1135,7 @@
 
 readpage:
 		/* ... and start the actual read. The read will unlock the page. */
-		error = mapping->a_ops->readpage(filp->f_dentry, page);
+		error = mapping->a_ops->readpage(filp, page);
 
 		if (!error) {
 			if (Page_Uptodate(page))
@@ -1486,7 +1517,7 @@
 		goto success;
 	}
 
-	if (!mapping->a_ops->readpage(file->f_dentry, page)) {
+	if (!mapping->a_ops->readpage(file, page)) {
 		wait_on_page(page);
 		if (Page_Uptodate(page))
 			goto success;
@@ -1504,7 +1535,7 @@
 		goto success;
 	}
 	ClearPageError(page);
-	if (!mapping->a_ops->readpage(file->f_dentry, page)) {
+	if (!mapping->a_ops->readpage(file, page)) {
 		wait_on_page(page);
 		if (Page_Uptodate(page))
 			goto success;
@@ -1519,27 +1550,16 @@
 }
 
 static int filemap_write_page(struct file *file,
-			      unsigned long index,
 			      struct page * page,
 			      int wait)
 {
-	int result;
-	struct dentry * dentry;
-	struct inode * inode;
-
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
-
 	/*
 	 * If a task terminates while we're swapping the page, the vma and
 	 * and file could be released: try_to_swap_out has done a get_file.
 	 * vma/file is guaranteed to exist in the unmap/sync cases because
 	 * mmap_sem is held.
 	 */
-	lock_page(page);
-	result = inode->i_mapping->a_ops->writepage(file, dentry, page);
-	UnlockPage(page);
-	return result;
+	return page->mapping->a_ops->writepage(file, page);
 }
 
 
@@ -1551,7 +1571,7 @@
 extern void wakeup_bdflush(int);
 int filemap_swapout(struct page * page, struct file * file)
 {
-	int retval = filemap_write_page(file, page->index, page, 0);
+	int retval = filemap_write_page(file, page, 0);
 	wakeup_bdflush(0);
 	return retval;
 }
@@ -1597,7 +1617,9 @@
 		printk("weirdness: pgoff=%lu index=%lu address=%lu vm_start=%lu vm_pgoff=%lu\n",
 			pgoff, page->index, address, vma->vm_start, vma->vm_pgoff);
 	}
-	error = filemap_write_page(vma->vm_file, pgoff, page, 1);
+	lock_page(page);
+	error = filemap_write_page(vma->vm_file, page, 1);
+	UnlockPage(page);
 	page_cache_free(page);
 	return error;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/highmem.c linux/mm/highmem.c
--- v2.3.99-pre6/linux/mm/highmem.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/highmem.c	Wed May  3 14:45:32 2000
@@ -24,8 +24,12 @@
 
 unsigned long highmem_mapnr;
 
+/*
+ * Take one locked page, return another low-memory locked page.
+ */
 struct page * prepare_highmem_swapout(struct page * page)
 {
+	struct page *new_page;
 	unsigned long regular_page;
 	unsigned long vaddr;
 	/*
@@ -36,6 +40,14 @@
 	if (!PageHighMem(page))
 		return page;
 
+	/*
+	 * Here we break the page lock, and we split the
+	 * dirty page into two. We can unlock the old page,
+	 * and we'll now have two of them. Too bad, it would
+	 * have been nice to continue to potentially share
+	 * across a fork().
+	 */
+	UnlockPage(page);
 	regular_page = __get_free_page(GFP_ATOMIC);
 	if (!regular_page)
 		return NULL;
@@ -49,8 +61,9 @@
 	 * we stored its data into the new regular_page.
 	 */
 	__free_page(page);
-
-	return mem_map + MAP_NR(regular_page);
+	new_page = mem_map + MAP_NR(regular_page);
+	LockPage(new_page);
+	return new_page;
 }
 
 struct page * replace_with_highmem(struct page * page)
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/memory.c linux/mm/memory.c
--- v2.3.99-pre6/linux/mm/memory.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/memory.c	Tue May  2 17:03:58 2000
@@ -824,7 +824,6 @@
 	map_nr = pte_pagenr(pte);
 	if (map_nr >= max_mapnr)
 		goto bad_wp_page;
-	mm->min_flt++;
 	old_page = mem_map + map_nr;
 	
 	/*
@@ -855,7 +854,7 @@
 		flush_cache_page(vma, address);
 		establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
 		spin_unlock(&mm->page_table_lock);
-		return 1;
+		return 1;	/* Minor fault */
 	}
 
 	/*
@@ -880,7 +879,7 @@
 	}
 	spin_unlock(&mm->page_table_lock);
 	__free_page(new_page);
-	return 1;
+	return 1;	/* Minor fault */
 
 bad_wp_page:
 	spin_unlock(&mm->page_table_lock);
@@ -1049,12 +1048,9 @@
 	}
 
 	mm->rss++;
-	mm->min_flt++;
 
 	pte = mk_pte(page, vma->vm_page_prot);
 
-	SetPageSwapEntry(page);
-
 	/*
 	 * Freeze the "shared"ness of the page, ie page_count + swap_count.
 	 * Must lock page before transferring our swap count to already
@@ -1074,7 +1070,7 @@
 	set_pte(page_table, pte);
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, address, pte);
-	return 1;
+	return 1;	/* Minor fault */
 }
 
 /*
@@ -1094,13 +1090,12 @@
 		clear_user_highpage(page, addr);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		mm->rss++;
-		mm->min_flt++;
 		flush_page_to_ram(page);
 	}
 	set_pte(page_table, entry);
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
-	return 1;
+	return 1;	/* Minor fault */
 }
 
 /*
@@ -1133,7 +1128,6 @@
 		return 0;
 	if (new_page == NOPAGE_OOM)
 		return -1;
-	++mm->maj_flt;
 	++mm->rss;
 	/*
 	 * This silly early PAGE_DIRTY setting removes a race
@@ -1156,7 +1150,7 @@
 	set_pte(page_table, entry);
 	/* no need to invalidate: a not-present page shouldn't be cached */
 	update_mmu_cache(vma, address, entry);
-	return 1;
+	return 2;	/* Major fault */
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.99-pre6/linux/mm/page_alloc.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/page_alloc.c	Wed May 10 16:47:43 2000
@@ -58,23 +58,6 @@
  */
 #define BAD_RANGE(zone,x) (((zone) != (x)->zone) || (((x)-mem_map) < (zone)->offset) || (((x)-mem_map) >= (zone)->offset+(zone)->size))
 
-#if 0
-
-static inline unsigned long classfree(zone_t *zone)
-{
-	unsigned long free = 0;
-	zone_t *z = zone->zone_pgdat->node_zones;
-
-	while (z != zone) {
-		free += z->free_pages;
-		z++;
-	}
-	free += zone->free_pages;
-	return(free);
-}
-
-#endif
-
 /*
  * Buddy system. Hairy. You really aren't expected to understand this
  *
@@ -227,67 +210,13 @@
 	return NULL;
 }
 
-static int zone_balance_memory(zonelist_t *zonelist)
-{
-	int tried = 0, freed = 0;
-	zone_t **zone;
-	int gfp_mask = zonelist->gfp_mask;
-	extern wait_queue_head_t kswapd_wait;
-
-	zone = zonelist->zones;
-	for (;;) {
-		zone_t *z = *(zone++);
-		if (!z)
-			break;
-		if (z->free_pages > z->pages_low)
-			continue;
-
-		z->zone_wake_kswapd = 1;
-		wake_up_interruptible(&kswapd_wait);
-
-		/* Are we reaching the critical stage? */
-		if (!z->low_on_memory) {
-			/* Not yet critical, so let kswapd handle it.. */
-			if (z->free_pages > z->pages_min)
-				continue;
-			z->low_on_memory = 1;
-		}
-		/*
-		 * In the atomic allocation case we only 'kick' the
-		 * state machine, but do not try to free pages
-		 * ourselves.
-		 */
-		tried = 1;
-		freed |= try_to_free_pages(gfp_mask, z);
-	}
-	if (tried && !freed) {
-		if (!(gfp_mask & __GFP_HIGH))
-			return 0;
-	}
-	return 1;
-}
-
 /*
  * This is the 'heart' of the zoned buddy allocator:
  */
 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
-	 * do our best to just allocate things without
-	 * further thought.
-	 */
-	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);
+	extern wait_queue_head_t kswapd_wait;
 
 	/*
 	 * (If anyone calls gfp from interrupts nonatomically then it
@@ -304,38 +233,67 @@
 			BUG();
 
 		/* Are we supposed to free memory? Don't make it worse.. */
-		if (!z->zone_wake_kswapd && z->free_pages > z->pages_low) {
+		if (!z->zone_wake_kswapd) {
 			struct page *page = rmqueue(z, order);
-			low_on_memory = 0;
+			if (z->free_pages < z->pages_low) {
+				z->zone_wake_kswapd = 1;
+				if (waitqueue_active(&kswapd_wait))
+					wake_up_interruptible(&kswapd_wait);
+			}
 			if (page)
 				return page;
 		}
 	}
 
-	low_on_memory = 1;
 	/*
-	 * Ok, no obvious zones were available, start
-	 * balancing things a bit..
+	 * Ok, we don't have any zones that don't need some
+	 * balancing.. See if we have any that aren't critical..
 	 */
-	if (zone_balance_memory(zonelist)) {
-		zone = zonelist->zones;
-allocate_ok:
-		for (;;) {
-			zone_t *z = *(zone++);
-			if (!z)
-				break;
-			if (z->free_pages) {
-				struct page *page = rmqueue(z, order);
-				if (page)
-					return page;
-			}
+	zone = zonelist->zones;
+	for (;;) {
+		zone_t *z = *(zone++);
+		if (!z)
+			break;
+		if (!z->low_on_memory) {
+			struct page *page = rmqueue(z, order);
+			if (z->free_pages < z->pages_min)
+				z->low_on_memory = 1;
+			if (page)
+				return page;
 		}
 	}
-	return NULL;
 
-/*
- * The main chunk of the balancing code is in this offline branch:
- */
+	/*
+	 * Uhhuh. All the zones have been critical, which means that
+	 * we'd better do some synchronous swap-out. kswapd has not
+	 * been able to cope..
+	 */
+	if (!(current->flags & PF_MEMALLOC)) {
+		int gfp_mask = zonelist->gfp_mask;
+		if (!try_to_free_pages(gfp_mask)) {
+			if (!(gfp_mask & __GFP_HIGH))
+				goto fail;
+		}
+	}
+
+	/*
+	 * Final phase: allocate anything we can!
+	 */
+	zone = zonelist->zones;
+	for (;;) {
+		struct page *page;
+
+		zone_t *z = *(zone++);
+		if (!z)
+			break;
+		page = rmqueue(z, order);
+		if (page)
+			return page;
+	}
+
+fail:
+	/* No luck.. */
+	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/page_io.c linux/mm/page_io.c
--- v2.3.99-pre6/linux/mm/page_io.c	Tue Dec  7 09:32:52 1999
+++ linux/mm/page_io.c	Fri May  5 12:47:48 2000
@@ -74,7 +74,7 @@
 		return 0;
 	}
  	if (!wait) {
- 		set_bit(PG_decr_after, &page->flags);
+ 		SetPageDecrAfter(page);
  		atomic_inc(&nr_async_pages);
  	}
 
@@ -132,6 +132,11 @@
 		PAGE_BUG(page);
 	if (PageSwapCache(page))
 		PAGE_BUG(page);
+	if (page->mapping)
+		PAGE_BUG(page);
+	/* needs sync_page to wait I/O completation */
+	page->mapping = &swapper_space;
 	if (!rw_swap_page_base(rw, entry, page, wait))
 		UnlockPage(page);
+	page->mapping = NULL;
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/slab.c linux/mm/slab.c
--- v2.3.99-pre6/linux/mm/slab.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/slab.c	Wed May 10 16:56:44 2000
@@ -682,6 +682,9 @@
 	size_t		left_over;
 	size_t		align;
 
+#if SLAB_DEBUG_SUPPORT
+	flags |= SLAB_POISON;
+#endif
 	/* Sanity checks... */
 #if	SLAB_MGMT_CHECKS
 	if (!name) {
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.99-pre6/linux/mm/swap_state.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/swap_state.c	Wed May  3 17:04:12 2000
@@ -47,14 +47,20 @@
 
 void add_to_swap_cache(struct page *page, swp_entry_t entry)
 {
+	unsigned long flags;
+
 #ifdef SWAP_CACHE_INFO
 	swap_cache_add_total++;
 #endif
+	if (!PageLocked(page))
+		BUG();
 	if (PageTestandSetSwapCache(page))
 		BUG();
 	if (page->mapping)
 		BUG();
-	add_to_page_cache(page, &swapper_space, entry.val);
+	flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty));
+	page->flags = flags | (1 << PG_referenced) | (1 << PG_uptodate);
+	add_to_page_cache_locked(page, &swapper_space, entry.val);
 }
 
 static inline void remove_from_swap_cache(struct page *page)
@@ -130,9 +136,6 @@
 		}
 		UnlockPage(page);
 	}
-
-	ClearPageSwapEntry(page);
-
 	__free_page(page);
 }
 
@@ -228,6 +231,7 @@
 	/* 
 	 * Add it to the swap cache and read its contents.
 	 */
+	lock_page(new_page);
 	add_to_swap_cache(new_page, entry);
 	rw_swap_page(READ, new_page, wait);
 	return new_page;
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.99-pre6/linux/mm/swapfile.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/swapfile.c	Mon May  8 11:17:47 2000
@@ -200,49 +200,6 @@
 	goto out;
 }
 
-/* needs the big kernel lock */
-swp_entry_t acquire_swap_entry(struct page *page)
-{
-	struct swap_info_struct * p;
-	unsigned long offset, type;
-	swp_entry_t entry;
-
-	if (!PageSwapEntry(page))
-		goto new_swap_entry;
-
-	/* We have the old entry in the page offset still */
-	if (!page->index)
-		goto new_swap_entry;
-	entry.val = page->index;
-	type = SWP_TYPE(entry);
-	if (type >= nr_swapfiles)
-		goto new_swap_entry;
-	p = type + swap_info;
-	if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
-		goto new_swap_entry;
-	offset = SWP_OFFSET(entry);
-	if (offset >= p->max)
-		goto new_swap_entry;
-	/* Has it been re-used for something else? */
-	swap_list_lock();
-	swap_device_lock(p);
-	if (p->swap_map[offset])
-		goto unlock_new_swap_entry;
-
-	/* We're cool, we can just use the old one */
-	p->swap_map[offset] = 1;
-	swap_device_unlock(p);
-	nr_swap_pages--;
-	swap_list_unlock();
-	return entry;
-
-unlock_new_swap_entry:
-	swap_device_unlock(p);
-	swap_list_unlock();
-new_swap_entry:
-	return get_swap_page();
-}
-
 /*
  * The swap entry has been read in advance, and we return 1 to indicate
  * that the page has been used or is no longer needed.
@@ -443,8 +400,7 @@
 asmlinkage long sys_swapoff(const char * specialfile)
 {
 	struct swap_info_struct * p = NULL;
-	struct dentry * dentry;
-	struct vfsmount *mnt;
+	struct nameidata nd;
 	int i, type, prev;
 	int err;
 	
@@ -452,9 +408,8 @@
 		return -EPERM;
 
 	lock_kernel();
-	dentry = namei(specialfile);
-	err = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	err = user_path_walk(specialfile, &nd);
+	if (err)
 		goto out;
 
 	prev = -1;
@@ -463,11 +418,11 @@
 		p = swap_info + type;
 		if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
 			if (p->swap_file) {
-				if (p->swap_file == dentry)
+				if (p->swap_file == nd.dentry)
 				  break;
 			} else {
-				if (S_ISBLK(dentry->d_inode->i_mode)
-				    && (p->swap_device == dentry->d_inode->i_rdev))
+				if (S_ISBLK(nd.dentry->d_inode->i_mode)
+				    && (p->swap_device == nd.dentry->d_inode->i_rdev))
 				  break;
 			}
 		}
@@ -509,22 +464,21 @@
 		goto out_dput;
 	}
 	if (p->swap_device)
-		blkdev_put(dentry->d_inode->i_bdev, BDEV_SWAP);
-	dput(dentry);
+		blkdev_put(nd.dentry->d_inode->i_bdev, BDEV_SWAP);
+	path_release(&nd);
 
-	dentry = p->swap_file;
+	nd.dentry = p->swap_file;
 	p->swap_file = NULL;
-	mnt = p->swap_vfsmnt;
+	nd.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);
+	path_release(&nd);
 out:
 	unlock_kernel();
 	return err;
@@ -637,8 +591,8 @@
 	if (IS_ERR(name))
 		goto bad_swap_2;
 	error = 0;
-	if (walk_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		error = walk_name(name, &nd);
+	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		error = path_walk(name, &nd);
 	putname(name);
 	if (error)
 		goto bad_swap_2;
@@ -835,8 +789,7 @@
 	p->flags = 0;
 	if (!(swap_flags & SWAP_FLAG_PREFER))
 		++least_priority;
-	dput(nd.dentry);
-	mntput(nd.mnt);
+	path_release(&nd);
 out:
 	if (swap_header)
 		free_page((long) swap_header);
diff -u --recursive --new-file v2.3.99-pre6/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.99-pre6/linux/mm/vmscan.c	Wed Apr 26 16:34:09 2000
+++ linux/mm/vmscan.c	Thu May 11 14:01:17 2000
@@ -48,7 +48,6 @@
 	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)) {
 		/*
@@ -56,11 +55,11 @@
 		 * tables to the global page map.
 		 */
 		set_pte(page_table, pte_mkold(pte));
-		set_bit(PG_referenced, &page->flags);
+                SetPageReferenced(page);
 		goto out_failed;
 	}
 
-	if (PageLocked(page))
+	if (TryLockPage(page))
 		goto out_failed;
 
 	/*
@@ -76,6 +75,8 @@
 		swap_duplicate(entry);
 		set_pte(page_table, swp_entry_to_pte(entry));
 drop_pte:
+		UnlockPage(page);
+		mm->swap_cnt--;
 		vma->vm_mm->rss--;
 		flush_tlb_page(vma, address);
 		__free_page(page);
@@ -107,7 +108,14 @@
 	 * locks etc.
 	 */
 	if (!(gfp_mask & __GFP_IO))
-		goto out_failed;
+		goto out_unlock;
+
+	/*
+	 * Don't do any of the expensive stuff if
+	 * we're not really interested in this zone.
+	 */
+	if (page->zone->free_pages > page->zone->pages_high)
+		goto out_unlock;
 
 	/*
 	 * Ok, it's really dirty. That means that
@@ -134,10 +142,12 @@
 		struct file *file = vma->vm_file;
 		if (file) get_file(file);
 		pte_clear(page_table);
+		mm->swap_cnt--;
 		vma->vm_mm->rss--;
 		flush_tlb_page(vma, address);
 		vmlist_access_unlock(vma->vm_mm);
 		error = swapout(page, file);
+		UnlockPage(page);
 		if (file) fput(file);
 		if (!error)
 			goto out_free_success;
@@ -151,18 +161,20 @@
 	 * we have the swap cache set up to associate the
 	 * page with that swap entry.
 	 */
-	entry = acquire_swap_entry(page);
+	entry = get_swap_page();
 	if (!entry.val)
-		goto out_failed; /* No swap space left */
-		
+		goto out_unlock; /* No swap space left */
+
 	if (!(page = prepare_highmem_swapout(page)))
 		goto out_swap_free;
 
 	swap_duplicate(entry);	/* One for the process, one for the swap cache */
 
-	/* This will also lock the page */
+	/* Add it to the swap cache */
 	add_to_swap_cache(page, entry);
+
 	/* Put the swap entry into the pte after the page is in swapcache */
+	mm->swap_cnt--;
 	vma->vm_mm->rss--;
 	set_pte(page_table, swp_entry_to_pte(entry));
 	flush_tlb_page(vma, address);
@@ -178,7 +190,9 @@
 	swap_free(entry);
 out_failed:
 	return 0;
-
+out_unlock:
+	UnlockPage(page);
+	return 0;
 }
 
 /*
@@ -328,12 +342,11 @@
  * N.B. This function returns only 0 or 1.  Return values != 1 from
  * the lower level routines result in continued processing.
  */
-int swap_out(unsigned int priority, int gfp_mask)
+static int swap_out(unsigned int priority, int gfp_mask)
 {
 	struct task_struct * p;
 	int counter;
 	int __ret = 0;
-	int assign = 0;
 
 	lock_kernel();
 	/* 
@@ -350,7 +363,7 @@
 	 * Think of swap_cnt as a "shadow rss" - it tells us which process
 	 * we want to page out (always try largest first).
 	 */
-	counter = nr_threads / (priority+1);
+	counter = (nr_threads << 1) >> (priority >> 1);
 	if (counter < 1)
 		counter = 1;
 
@@ -358,12 +371,12 @@
 		unsigned long max_cnt = 0;
 		struct mm_struct *best = NULL;
 		int pid = 0;
+		int assign = 0;
 	select:
 		read_lock(&tasklist_lock);
 		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)
@@ -377,25 +390,6 @@
 				pid = p->pid;
 			}
 		}
-		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) {
@@ -429,22 +423,25 @@
  * now we need this so that we can do page allocations
  * without holding the kernel lock etc.
  *
- * We want to try to free "count" pages, and we need to 
- * cluster them so that we get good swap-out behaviour. See
- * the "free_memory()" macro for details.
+ * We want to try to free "count" pages, and we want to 
+ * cluster them so that we get good swap-out behaviour.
+ *
+ * Don't try _too_ hard, though. We don't want to have bad
+ * latency.
  */
-static int do_try_to_free_pages(unsigned int gfp_mask, zone_t *zone)
+#define FREE_COUNT	8
+#define SWAP_COUNT	8
+static int do_try_to_free_pages(unsigned int gfp_mask)
 {
 	int priority;
-	int count = SWAP_CLUSTER_MAX;
-	int ret;
+	int count = FREE_COUNT;
 
 	/* Always trim SLAB caches when memory gets low. */
 	kmem_cache_reap(gfp_mask);
 
 	priority = 6;
 	do {
-		while ((ret = shrink_mmap(priority, gfp_mask, zone))) {
+		while (shrink_mmap(priority, gfp_mask)) {
 			if (!--count)
 				goto done;
 		}
@@ -457,27 +454,41 @@
 		   	 * shrink_mmap() almost never fail when there's
 		   	 * really plenty of memory free. 
 			 */
-			count -= shrink_dcache_memory(priority, gfp_mask, zone);
-			count -= shrink_icache_memory(priority, gfp_mask, zone);
+			count -= shrink_dcache_memory(priority, gfp_mask);
+			count -= shrink_icache_memory(priority, gfp_mask);
 			if (count <= 0)
 				goto done;
-			while (shm_swap(priority, gfp_mask, zone)) {
+			while (shm_swap(priority, gfp_mask)) {
 				if (!--count)
 					goto done;
 			}
 		}
 
-		/* 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;
+		/*
+		 * Then, try to page stuff out..
+		 *
+		 * This will not actually free any pages (they get
+		 * put in the swap cache), so we must not count this
+		 * as a "count" success.
+		 */
+		{
+			int swap_count = SWAP_COUNT;
+			while (swap_out(priority, gfp_mask))
+				if (--swap_count < 0)
+					break;
 		}
 	} while (--priority >= 0);
-done:
 
-	return priority >= 0;
+	/* Always end on a shrink_mmap.. */
+	while (shrink_mmap(0, gfp_mask)) {
+		if (!--count)
+			goto done;
+	}
+
+	return 0;
+
+done:
+	return 1;
 }
 
 DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
@@ -497,10 +508,7 @@
  */
 int kswapd(void *unused)
 {
-	int i;
 	struct task_struct *tsk = current;
-	pg_data_t *pgdat;
-	zone_t *zone;
 
 	tsk->session = 1;
 	tsk->pgrp = 1;
@@ -521,27 +529,30 @@
 	 */
 	tsk->flags |= PF_MEMALLOC;
 
-	while (1) {
-		/*
-		 * If we actually get into a low-memory situation,
-		 * the processes needing more memory will wake us
-		 * up on a more timely basis.
-		 */
+	for (;;) {
+		pg_data_t *pgdat;
+		int something_to_do = 0;
+
 		pgdat = pgdat_list;
-		while (pgdat) {
-			for (i = 0; i < MAX_NR_ZONES; i++) {
-				zone = pgdat->node_zones + i;
+		do {
+			int i;
+			for(i = 0; i < MAX_NR_ZONES; i++) {
+				zone_t *zone = pgdat->node_zones+ i;
+				if (!zone->size || !zone->zone_wake_kswapd)
+					continue;
+				something_to_do = 1;
+				do_try_to_free_pages(GFP_KSWAPD);
 				if (tsk->need_resched)
 					schedule();
-				if ((!zone->size) || (!zone->zone_wake_kswapd))
-					continue;
-				do_try_to_free_pages(GFP_KSWAPD, zone);
 			}
+			run_task_queue(&tq_disk);
 			pgdat = pgdat->node_next;
+		} while (pgdat);
+
+		if (!something_to_do) {
+			tsk->state = TASK_INTERRUPTIBLE;
+			interruptible_sleep_on(&kswapd_wait);
 		}
-		run_task_queue(&tq_disk);
-		tsk->state = TASK_INTERRUPTIBLE;
-		interruptible_sleep_on(&kswapd_wait);
 	}
 }
 
@@ -560,13 +571,13 @@
  * can be done by just dropping cached pages without having
  * any deadlock issues.
  */
-int try_to_free_pages(unsigned int gfp_mask, zone_t *zone)
+int try_to_free_pages(unsigned int gfp_mask)
 {
 	int retval = 1;
 
 	if (gfp_mask & __GFP_WAIT) {
 		current->flags |= PF_MEMALLOC;
-		retval = do_try_to_free_pages(gfp_mask, zone);
+		retval = do_try_to_free_pages(gfp_mask);
 		current->flags &= ~PF_MEMALLOC;
 	}
 	return retval;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/atm/clip.c linux/net/atm/clip.c
--- v2.3.99-pre6/linux/net/atm/clip.c	Wed Apr 26 16:34:09 2000
+++ linux/net/atm/clip.c	Tue May  2 12:41:00 2000
@@ -594,7 +594,6 @@
 	if (!dev) return -ENOMEM;
 	memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv));
 	clip_priv = PRIV(dev);
-	dev->name = clip_priv->name;
 	sprintf(dev->name,"atm%d",number);
 	dev->init = clip_init;
 	spin_lock_init(&clip_priv->xoff_lock);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/atm/lec.c linux/net/atm/lec.c
--- v2.3.99-pre6/linux/net/atm/lec.c	Wed Apr 26 16:34:09 2000
+++ linux/net/atm/lec.c	Wed May  3 01:48:03 2000
@@ -34,7 +34,7 @@
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #include <linux/if_bridge.h>
 #include "../bridge/br_private.h"
-static unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
+static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 #endif
 
 /* Modular too */
@@ -92,7 +92,7 @@
 }
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-static void handle_bridge(struct sk_buff *skb, struct net_device *dev)
+static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
 {
         struct ethhdr *eth;
         char *buff;
@@ -220,8 +220,8 @@
                 (long)skb->head, (long)skb->data, (long)skb->tail,
                 (long)skb->end);
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-        if (memcmp(skb->data, bridge_ula, sizeof(bridge_ula)) == 0)
-                handle_bridge(skb, dev);
+        if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
+                lec_handle_bridge(skb, dev);
 #endif
 
         /* Make sure we have room for lec_id */
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v2.3.99-pre6/linux/net/ax25/ax25_timer.c	Fri Jan 21 18:19:17 2000
+++ linux/net/ax25/ax25_timer.c	Thu May  4 11:25:34 2000
@@ -140,12 +140,12 @@
 
 int ax25_t1timer_running(ax25_cb *ax25)
 {
-	return (ax25->t1timer.prev != NULL || ax25->t1timer.next != NULL);
+	return timer_pending(&ax25->t1timer);
 }
 
 unsigned long ax25_display_timer(struct timer_list *timer)
 {
-	if (timer->prev == NULL && timer->next == NULL)
+	if (!timer_pending(timer))
 		return 0;
 
 	return timer->expires - jiffies;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/bridge/br_if.c linux/net/bridge/br_if.c
--- v2.3.99-pre6/linux/net/bridge/br_if.c	Sat Feb 26 22:32:08 2000
+++ linux/net/bridge/br_if.c	Mon May  8 22:21:58 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_if.c,v 1.2 2000/02/21 15:51:34 davem Exp $
+ *	$Id: br_if.c,v 1.3 2000/05/05 02:17:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -74,7 +74,7 @@
 
 	b = &bridge_list;
 	while ((br = *b) != NULL) {
-		if (!strncmp(br->name, name, IFNAMSIZ))
+		if (!strncmp(br->dev.name, name, IFNAMSIZ))
 			return b;
 
 		b = &(br->next);
@@ -102,9 +102,8 @@
 	memset(br, 0, sizeof(*br));
 	dev = &br->dev;
 
-	strncpy(br->name, name, IFNAMSIZ);
+	strncpy(dev->name, name, IFNAMSIZ);
 	dev->priv = br;
-	dev->name = br->name;
 	ether_setup(dev);
 	br_dev_setup(dev);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v2.3.99-pre6/linux/net/bridge/br_private.h	Mon Mar 27 08:08:33 2000
+++ linux/net/bridge/br_private.h	Mon May  8 22:21:58 2000
@@ -4,7 +4,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_private.h,v 1.2 2000/03/21 21:08:47 davem Exp $
+ *	$Id: br_private.h,v 1.3 2000/05/05 02:17:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -82,7 +82,6 @@
 	struct net_bridge		*next;
 	rwlock_t			lock;
 	struct net_bridge_port		*port_list;
-	char				name[IFNAMSIZ];
 	struct net_device		dev;
 	struct net_device_stats		statistics;
 	rwlock_t			hash_lock;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/bridge/br_stp.c linux/net/bridge/br_stp.c
--- v2.3.99-pre6/linux/net/bridge/br_stp.c	Sat Feb 26 22:32:08 2000
+++ linux/net/bridge/br_stp.c	Mon May  8 22:21:58 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_stp.c,v 1.2 2000/02/21 15:51:34 davem Exp $
+ *	$Id: br_stp.c,v 1.3 2000/05/05 02:17:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -292,7 +292,7 @@
 /* called under bridge lock */
 void br_topology_change_detection(struct net_bridge *br)
 {
-	printk(KERN_INFO "%s: topology change detected, ", br->name);
+	printk(KERN_INFO "%s: topology change detected, ", br->dev.name);
 
 	if (br_is_root_bridge(br)) {
 		printk("propagating\n");
@@ -357,7 +357,7 @@
 			br_topology_change_detection(p->br);
 
 		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->name, p->port_no, p->dev->name, "blocking");
+		       p->br->dev.name, p->port_no, p->dev->name, "blocking");
 
 		p->state = BR_STATE_BLOCKING;
 		br_timer_clear(&p->forward_delay_timer);
@@ -369,7 +369,7 @@
 {
 	if (p->state == BR_STATE_BLOCKING) {
 		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->name, p->port_no, p->dev->name, "listening");
+		       p->br->dev.name, p->port_no, p->dev->name, "listening");
 
 		p->state = BR_STATE_LISTENING;
 		br_timer_set(&p->forward_delay_timer, jiffies);
@@ -456,7 +456,7 @@
 	if (p->state != BR_STATE_DISABLED &&
 	    br_is_designated_port(p)) {
 		printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n",
-		       p->br->name, p->port_no, p->dev->name);
+		       p->br->dev.name, p->port_no, p->dev->name);
 
 		br_topology_change_detection(p->br);
 		br_topology_change_acknowledge(p);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/bridge/br_stp_if.c linux/net/bridge/br_stp_if.c
--- v2.3.99-pre6/linux/net/bridge/br_stp_if.c	Sat Feb 26 22:32:08 2000
+++ linux/net/bridge/br_stp_if.c	Mon May  8 22:21:58 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_stp_if.c,v 1.2 2000/02/21 15:51:34 davem Exp $
+ *	$Id: br_stp_if.c,v 1.3 2000/05/05 02:17:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -103,7 +103,7 @@
 
 	br = p->br;
 	printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-	       br->name, p->port_no, p->dev->name, "disabled");
+	       br->dev.name, p->port_no, p->dev->name, "disabled");
 
 	wasroot = br_is_root_bridge(br);
 	br_become_designated_port(p);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/bridge/br_stp_timer.c linux/net/bridge/br_stp_timer.c
--- v2.3.99-pre6/linux/net/bridge/br_stp_timer.c	Sat Feb 26 22:32:08 2000
+++ linux/net/bridge/br_stp_timer.c	Mon May  8 22:21:58 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_stp_timer.c,v 1.2 2000/02/21 15:51:35 davem Exp $
+ *	$Id: br_stp_timer.c,v 1.3 2000/05/05 02:17:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -58,7 +58,7 @@
 	int was_root;
 
 	br = p->br;
-	printk(KERN_INFO "%s: ", br->name);
+	printk(KERN_INFO "%s: ", br->dev.name);
 	printk("neighbour ");
 	dump_bridge_id(&p->designated_bridge);
 	printk(" lost on port %i(%s)\n", p->port_no, p->dev->name);
@@ -82,13 +82,13 @@
 {
 	if (p->state == BR_STATE_LISTENING) {
 		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->name, p->port_no, p->dev->name, "learning");
+		       p->br->dev.name, p->port_no, p->dev->name, "learning");
 
 		p->state = BR_STATE_LEARNING;
 		br_timer_set(&p->forward_delay_timer, jiffies);
 	} else if (p->state == BR_STATE_LEARNING) {
 		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->name, p->port_no, p->dev->name, "forwarding");
+		       p->br->dev.name, p->port_no, p->dev->name, "forwarding");
 
 		p->state = BR_STATE_FORWARDING;
 		if (br_is_designated_for_some_port(p->br))
@@ -99,7 +99,7 @@
 /* called under bridge lock */
 static void br_tcn_timer_expired(struct net_bridge *br)
 {
-	printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->name);
+	printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->dev.name);
 	br_transmit_tcn(br);
 	br_timer_set(&br->tcn_timer, jiffies);
 }
diff -u --recursive --new-file v2.3.99-pre6/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.99-pre6/linux/net/core/dev.c	Wed Apr 26 16:34:09 2000
+++ linux/net/core/dev.c	Mon May  8 22:21:58 2000
@@ -453,13 +453,12 @@
 
 struct net_device *dev_alloc(const char *name, int *err)
 {
-	struct net_device *dev=kmalloc(sizeof(struct net_device)+16, GFP_KERNEL);
+	struct net_device *dev=kmalloc(sizeof(struct net_device), GFP_KERNEL);
 	if (dev == NULL) {
 		*err = -ENOBUFS;
 		return NULL;
 	}
 	memset(dev, 0, sizeof(struct net_device));
-	dev->name = (char *)(dev + 1);	/* Name string space */
 	*err = dev_alloc_name(dev, name);
 	if (*err < 0) {
 		kfree(dev);
@@ -851,7 +850,7 @@
 
 
 /*=======================================================================
-			Receiver rotutines
+			Receiver routines
   =======================================================================*/
 
 int netdev_max_backlog = 300;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/core/dst.c linux/net/core/dst.c
--- v2.3.99-pre6/linux/net/core/dst.c	Fri Oct 22 13:21:55 1999
+++ linux/net/core/dst.c	Tue May  2 16:48:16 2000
@@ -37,7 +37,7 @@
 static void dst_run_gc(unsigned long);
 
 static struct timer_list dst_gc_timer =
-	{ NULL, NULL, DST_GC_MIN, 0L, dst_run_gc };
+	{ data: DST_GC_MIN, function: dst_run_gc };
 
 
 static void dst_run_gc(unsigned long dummy)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- v2.3.99-pre6/linux/net/decnet/dn_route.c	Sun Mar 19 18:35:31 2000
+++ linux/net/decnet/dn_route.c	Wed May  3 01:48:03 2000
@@ -104,8 +104,8 @@
 static struct dn_rt_hash_bucket *dn_rt_hash_table;
 static unsigned dn_rt_hash_mask;
 
-static struct timer_list dn_route_timer = { NULL, NULL, 0, 0L, NULL };
-static struct timer_list dn_rt_flush_timer = { NULL, NULL, 0, 0L, dn_run_flush };
+static struct timer_list dn_route_timer = { function: NULL };
+static struct timer_list dn_rt_flush_timer = { function: dn_run_flush };
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/decnet/dn_timer.c linux/net/decnet/dn_timer.c
--- v2.3.99-pre6/linux/net/decnet/dn_timer.c	Fri Sep 10 23:57:38 1999
+++ linux/net/decnet/dn_timer.c	Wed May  3 01:48:03 2000
@@ -135,8 +135,7 @@
 
 	if (!scp->delack_pending) {
 		scp->delack_pending = 1;
-		scp->delack_timer.next =
-		scp->delack_timer.prev = NULL;
+		init_timer(&scp->delack_timer);
 		scp->delack_timer.expires = jiffies + FAST_INTERVAL;
 		scp->delack_timer.data = (unsigned long)sk;
 		scp->delack_timer.function = dn_fast_timer;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/inetpeer.c linux/net/ipv4/inetpeer.c
--- v2.3.99-pre6/linux/net/ipv4/inetpeer.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/inetpeer.c	Wed May  3 01:48:03 2000
@@ -3,7 +3,7 @@
  *
  *  This source is covered by the GNU GPL, the same as all kernel sources.
  *
- *  Version:	$Id: inetpeer.c,v 1.1 2000/01/06 00:41:55 davem Exp $
+ *  Version:	$Id: inetpeer.c,v 1.2 2000/05/03 06:37:06 davem Exp $
  *
  *  Authors:	Andrey V. Savochkin <saw@msu.ru>
  */
@@ -94,7 +94,7 @@
 
 static void peer_check_expire(unsigned long dummy);
 static struct timer_list peer_periodic_timer =
-	{ NULL, NULL, 0, 0, &peer_check_expire };
+	{ { NULL, NULL }, 0, 0, &peer_check_expire };
 int inet_peer_gc_mintime = 10 * HZ,
     inet_peer_gc_maxtime = 120 * HZ;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c
--- v2.3.99-pre6/linux/net/ipv4/ip_gre.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/ip_gre.c	Thu May  4 11:31:22 2000
@@ -118,11 +118,11 @@
 static int ipgre_fb_tunnel_init(struct net_device *dev);
 
 static struct net_device ipgre_fb_tunnel_dev = {
-	NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipgre_fb_tunnel_init,
+	"gre%d", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipgre_fb_tunnel_init,
 };
 
 static struct ip_tunnel ipgre_fb_tunnel = {
-	NULL, &ipgre_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"gre0", }
+	NULL, &ipgre_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"gre%d", }
 };
 
 /* Tunnel hash table */
@@ -268,7 +268,7 @@
 	dev->priv = (void*)(dev+1);
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
-	dev->name = nt->parms.name;
+	strcpy(dev->name, nt->parms.name);
 	dev->init = ipgre_tunnel_init;
 	dev->new_style = 1;
 	memcpy(&nt->parms, parms, sizeof(*parms));
@@ -1226,7 +1226,6 @@
 	printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
 
 	ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
-	ipgre_fb_tunnel_dev.name = ipgre_fb_tunnel.parms.name;
 #ifdef MODULE
 	register_netdev(&ipgre_fb_tunnel_dev);
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.99-pre6/linux/net/ipv4/ipconfig.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/ipconfig.c	Wed May  3 01:48:03 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.30 2000/04/15 01:48:10 davem Exp $
+ *  $Id: ipconfig.c,v 1.31 2000/05/03 06:37:06 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -227,20 +227,17 @@
 	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 (%u.%u.%u.%u).\n",
-			NIPQUAD(err));
+		printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", 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 (%u.%u.%u.%u).\n",
-			NIPQUAD(err));
+		printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", 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 (%u.%u.%u.%u).\n",
-			NIPQUAD(err));
+		printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
 		return -1;
 	}
 	return 0;
@@ -264,8 +261,7 @@
 		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 (%u.%u.%u.%u).\n",
-				NIPQUAD(err));
+			printk(KERN_ERR "IP-Config: Cannot add default route (%d).\n", err);
 			return -1;
 		}
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v2.3.99-pre6/linux/net/ipv4/ipip.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/ipip.c	Mon May  8 22:21:58 2000
@@ -1,7 +1,7 @@
 /*
  *	Linux NET3:	IP/IP protocol decoder. 
  *
- *	Version: $Id: ipip.c,v 1.32 2000/03/21 06:13:54 davem Exp $
+ *	Version: $Id: ipip.c,v 1.33 2000/05/05 02:17:17 davem Exp $
  *
  *	Authors:
  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -121,11 +121,11 @@
 static int ipip_tunnel_init(struct net_device *dev);
 
 static struct net_device ipip_fb_tunnel_dev = {
-	NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init,
+	"tunl%d", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init,
 };
 
 static struct ip_tunnel ipip_fb_tunnel = {
-	NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl0", }
+	NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl%d", }
 };
 
 static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
@@ -237,7 +237,7 @@
 	dev->priv = (void*)(dev+1);
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
-	dev->name = nt->parms.name;
+	strcpy(dev->name, nt->parms.name);
 	dev->init = ipip_tunnel_init;
 	dev->new_style = 1;
 	memcpy(&nt->parms, parms, sizeof(*parms));
@@ -875,7 +875,6 @@
 	printk(KERN_INFO "IPv4 over IPv4 tunneling driver\n");
 
 	ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
-	ipip_fb_tunnel_dev.name = ipip_fb_tunnel.parms.name;
 #ifdef MODULE
 	register_netdev(&ipip_fb_tunnel_dev);
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.3.99-pre6/linux/net/ipv4/ipmr.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/ipmr.c	Mon May  8 22:21:58 2000
@@ -9,7 +9,7 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	Version: $Id: ipmr.c,v 1.51 2000/03/17 14:41:52 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.53 2000/05/05 02:17:17 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -189,7 +189,7 @@
 	struct in_device *in_dev;
 	int size;
 
-	size = sizeof(*dev) + IFNAMSIZ + sizeof(struct net_device_stats);
+	size = sizeof(*dev) + sizeof(struct net_device_stats);
 	dev = kmalloc(size, GFP_KERNEL);
 	if (!dev)
 		return NULL;
@@ -197,7 +197,6 @@
 	memset(dev, 0, size);
 
 	dev->priv = dev + 1;
-	dev->name = dev->priv + sizeof(struct net_device_stats);
 
 	strcpy(dev->name, "pimreg");
 
@@ -321,7 +320,7 @@
 	struct mfc_cache *c, **cp;
 
 	if (!spin_trylock(&mfc_unres_lock)) {
-		mod_timer(&ipmr_expire_timer, jiffies + HZ/10);
+		mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
 		return;
 	}
 
@@ -661,9 +660,7 @@
 		c->next = mfc_unres_queue;
 		mfc_unres_queue = c;
 
-		if (!del_timer(&ipmr_expire_timer))
-			ipmr_expire_timer.expires = c->mfc_un.unres.expires;
-		add_timer(&ipmr_expire_timer);
+		mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
 	}
 
 	/*
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_core.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_core.c	Thu Apr 27 15:43:16 2000
@@ -157,10 +157,47 @@
 }
 
 static void
+clean_from_lists(struct ip_conntrack *ct)
+{
+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+	/* Remove from both hash lists */
+	LIST_DELETE(&ip_conntrack_hash
+		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
+		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+	LIST_DELETE(&ip_conntrack_hash
+		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
+		    &ct->tuplehash[IP_CT_DIR_REPLY]);
+	/* If our expected is in the list, take it out. */
+	if (ct->expected.expectant) {
+		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
+		IP_NF_ASSERT(ct->expected.expectant == ct);
+		LIST_DELETE(&expect_list, &ct->expected);
+	}
+}
+
+static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
 
+	/* Unconfirmed connections haven't been cleaned up by the
+	   timer: hence they cannot be simply deleted here. */
+	if (!(ct->status & IPS_CONFIRMED)) {
+		WRITE_LOCK(&ip_conntrack_lock);
+		/* Race check: they can't get a reference if noone has
+                   one and we have the write lock. */
+		if (atomic_read(&ct->ct_general.use) == 0) {
+			clean_from_lists(ct);
+			WRITE_UNLOCK(&ip_conntrack_lock);
+		} else {
+			/* Either a last-minute confirmation (ie. ct
+			   now has timer attached), or a last-minute
+			   new skb has reference (still unconfirmed). */
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return;
+		}
+	}
+
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
@@ -178,19 +215,7 @@
 	struct ip_conntrack *ct = (void *)ul_conntrack;
 
 	WRITE_LOCK(&ip_conntrack_lock);
-	/* Remove from both hash lists */
-	LIST_DELETE(&ip_conntrack_hash
-		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
-		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-	LIST_DELETE(&ip_conntrack_hash
-		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
-		    &ct->tuplehash[IP_CT_DIR_REPLY]);
-	/* If our expected is in the list, take it out. */
-	if (ct->expected.expectant) {
-		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
-		IP_NF_ASSERT(ct->expected.expectant == ct);
-		LIST_DELETE(&expect_list, &ct->expected);
-	}
+	clean_from_lists(ct);
 	WRITE_UNLOCK(&ip_conntrack_lock);
 	ip_conntrack_put(ct);
 }
@@ -235,6 +260,26 @@
 	return h;
 }
 
+/* Confirm a connection */
+void
+ip_conntrack_confirm(struct ip_conntrack *ct)
+{
+	DEBUGP("Confirming conntrack %p\n", ct);
+	WRITE_LOCK(&ip_conntrack_lock);
+	/* Race check */
+	if (!(ct->status & IPS_CONFIRMED)) {
+		IP_NF_ASSERT(!timer_pending(&ct->timeout));
+		ct->status |= IPS_CONFIRMED;
+		/* Timer relative to confirmation time, not original
+		   setting time, otherwise we'd get timer wrap in
+		   wierd delay cases. */
+		ct->timeout.expires += jiffies;
+		add_timer(&ct->timeout);
+		atomic_inc(&ct->ct_general.use);
+	}
+	WRITE_UNLOCK(&ip_conntrack_lock);
+}
+
 /* Returns true if a connection correspondings to the tuple (required
    for NAT). */
 int
@@ -250,24 +295,28 @@
 	return h != NULL;
 }
 
-/* Returns TRUE if it dealt with ICMP, and filled in skb fields */
-int icmp_error_track(struct sk_buff *skb)
+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+struct ip_conntrack *
+icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
 {
-	const struct iphdr *iph = skb->nh.iph;
-	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+	const struct iphdr *iph;
+	struct icmphdr *hdr;
 	struct ip_conntrack_tuple innertuple, origtuple;
-	struct iphdr *inner = (struct iphdr *)(hdr + 1);
-	size_t datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
+	struct iphdr *inner;
+	size_t datalen;
 	struct ip_conntrack_protocol *innerproto;
 	struct ip_conntrack_tuple_hash *h;
-	enum ip_conntrack_info ctinfo;
 
-	if (iph->protocol != IPPROTO_ICMP)
-		return 0;
+	IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
+
+	iph = skb->nh.iph;
+	hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+	inner = (struct iphdr *)(hdr + 1);
+	datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
 
 	if (skb->len < iph->ihl * 4 + sizeof(struct icmphdr)) {
 		DEBUGP("icmp_error_track: too short\n");
-		return 1;
+		return NULL;
 	}
 
 	if (hdr->type != ICMP_DEST_UNREACH
@@ -275,12 +324,12 @@
 	    && hdr->type != ICMP_TIME_EXCEEDED
 	    && hdr->type != ICMP_PARAMETERPROB
 	    && hdr->type != ICMP_REDIRECT)
-		return 0;
+		return NULL;
 
 	/* Ignore it if the checksum's bogus. */
 	if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
 		DEBUGP("icmp_error_track: bad csum\n");
-		return 1;
+		return NULL;
 	}
 
 	innerproto = find_proto(inner->protocol);
@@ -290,28 +339,68 @@
 		DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
 		       inner->protocol, inner->ihl, 8,
 		       datalen);
-		return 1;
+		return NULL;
 	}
 
 	/* Ordinarily, we'd expect the inverted tupleproto, but it's
 	   been preserved inside the ICMP. */
 	if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
 		DEBUGP("icmp_error_track: Can't invert tuple\n");
-		return 1;
+		return NULL;
 	}
 	h = ip_conntrack_find_get(&innertuple, NULL);
 	if (!h) {
 		DEBUGP("icmp_error_track: no match\n");
-		return 1;
+		return NULL;
+	}
+	if (!(h->ctrack->status & IPS_CONFIRMED)) {
+		DEBUGP("icmp_error_track: unconfirmed\n");
+		ip_conntrack_put(h->ctrack);
+		return NULL;
 	}
 
-	ctinfo = IP_CT_RELATED;
+	*ctinfo = IP_CT_RELATED;
 	if (DIRECTION(h) == IP_CT_DIR_REPLY)
-		ctinfo += IP_CT_IS_REPLY;
+		*ctinfo += IP_CT_IS_REPLY;
 
 	/* Update skb to refer to this connection */
-	skb->nfct = &h->ctrack->infos[ctinfo];
-	return 1;
+	skb->nfct = &h->ctrack->infos[*ctinfo];
+	return h->ctrack;
+}
+
+/* There's a small race here where we may free a just-replied to
+   connection.  Too bad: we're in trouble anyway. */
+static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
+{
+	/* Unconfirmed connections either really fresh or transitory
+           anyway */
+	if (!(i->ctrack->status & IPS_SEEN_REPLY)
+	    && (i->ctrack->status & IPS_CONFIRMED))
+		return 1;
+	return 0;
+}
+
+static int early_drop(struct list_head *chain)
+{
+	/* Traverse backwards: gives us oldest, which is roughly LRU */
+	struct ip_conntrack_tuple_hash *h;
+	int dropped = 0;
+
+	READ_LOCK(&ip_conntrack_lock);
+	h = LIST_FIND(chain, unreplied, struct ip_conntrack_tuple_hash *);
+	if (h)
+		atomic_inc(&h->ctrack->ct_general.use);
+	READ_UNLOCK(&ip_conntrack_lock);
+
+	if (!h)
+		return dropped;
+
+	if (del_timer(&h->ctrack->timeout)) {
+		death_by_timeout((unsigned long)h->ctrack);
+		dropped = 1;
+	}
+	ip_conntrack_put(h->ctrack);
+	return dropped;
 }
 
 static inline int helper_cmp(const struct ip_conntrack_helper *i,
@@ -345,29 +434,38 @@
 	enum ip_conntrack_info ctinfo;
 	unsigned long extra_jiffies;
 	int i;
+	static unsigned int drop_next = 0;
 
-	if (!invert_tuple(&repl_tuple, tuple, protocol)) {
-		DEBUGP("Can't invert tuple.\n");
-		return 1;
-	}
+	hash = hash_conntrack(tuple);
 
-	if(ip_conntrack_max &&
-	    (atomic_read(&ip_conntrack_count) >= ip_conntrack_max)) {
+	if (ip_conntrack_max &&
+	    atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
 		if (net_ratelimit())
-			printk(KERN_WARNING "ip_conntrack: maximum limit of %d entries exceeded\n", ip_conntrack_max);
+			printk(KERN_WARNING "ip_conntrack: maximum limit of"
+			       " %d entries exceeded\n", ip_conntrack_max);
+
+		/* Try dropping from random chain, or else from the
+                   chain about to put into (in case they're trying to
+                   bomb one hash chain). */
+		if (!early_drop(&ip_conntrack_hash[drop_next++])
+		    && !early_drop(&ip_conntrack_hash[hash]))
+			return 1;
+	}
+
+	if (!invert_tuple(&repl_tuple, tuple, protocol)) {
+		DEBUGP("Can't invert tuple.\n");
 		return 1;
 	}
+	repl_hash = hash_conntrack(&repl_tuple);
 
 	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
 	if (!conntrack) {
 		DEBUGP("Can't allocate conntrack.\n");
 		return 1;
 	}
-	hash = hash_conntrack(tuple);
-	repl_hash = hash_conntrack(&repl_tuple);
 
 	memset(conntrack, 0, sizeof(struct ip_conntrack));
-	atomic_set(&conntrack->ct_general.use, 2);
+	atomic_set(&conntrack->ct_general.use, 1);
 	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
@@ -381,17 +479,17 @@
 		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return 1;
 	}
+	/* Don't set timer yet: wait for confirmation */
+	init_timer(&conntrack->timeout);
 	conntrack->timeout.data = (unsigned long)conntrack;
 	conntrack->timeout.function = death_by_timeout;
-	conntrack->timeout.expires = jiffies + extra_jiffies;
-	add_timer(&conntrack->timeout);
+	conntrack->timeout.expires = extra_jiffies;
 
 	/* Sew in at head of hash list. */
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Check noone else beat us in the race... */
 	if (__ip_conntrack_find(tuple, NULL)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
-		printk("ip_conntrack: Wow someone raced us!\n");
 		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return 0;
 	}
@@ -417,70 +515,70 @@
 		     &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]);
 	list_prepend(&ip_conntrack_hash[repl_hash],
 		     &conntrack->tuplehash[IP_CT_DIR_REPLY]);
+	atomic_inc(&ip_conntrack_count);
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
 	/* Update skb to refer to this connection */
 	skb->nfct = &conntrack->infos[ctinfo];
 
-	atomic_inc(&ip_conntrack_count);
 	return 1;
 }
 
-static void
-resolve_normal_ct(struct sk_buff *skb, int create)
+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+static inline struct ip_conntrack *
+resolve_normal_ct(struct sk_buff *skb,
+		  struct ip_conntrack_protocol *proto,
+		  enum ip_conntrack_info *ctinfo)
 {
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_protocol *proto;
-	enum ip_conntrack_info ctinfo;
 
-	proto = find_proto(skb->nh.iph->protocol);
 	if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
-		return;
+		return NULL;
 
 	/* Loop around search/insert race */
 	do {
 		/* look for tuple match */
 		h = ip_conntrack_find_get(&tuple, NULL);
-		if (!h && (!create || init_conntrack(&tuple, proto, skb)))
-			return;
+		if (!h && init_conntrack(&tuple, proto, skb))
+			return NULL;
 	} while (!h);
 
 	/* It exists; we have (non-exclusive) reference. */
 	if (DIRECTION(h) == IP_CT_DIR_REPLY) {
-		ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
+		/* Reply on unconfirmed connection => unclassifiable */
+		if (!(h->ctrack->status & IPS_CONFIRMED)) {
+			DEBUGP("Reply on unconfirmed connection\n");
+			ip_conntrack_put(h->ctrack);
+			return NULL;
+		}
+
+		*ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
 		h->ctrack->status |= IPS_SEEN_REPLY;
 	} else {
 		/* Once we've had two way comms, always ESTABLISHED. */
 		if (h->ctrack->status & IPS_SEEN_REPLY) {
 			DEBUGP("ip_conntrack_in: normal packet for %p\n",
 			       h->ctrack);
-		        ctinfo = IP_CT_ESTABLISHED;
+		        *ctinfo = IP_CT_ESTABLISHED;
 		} else if (h->ctrack->status & IPS_EXPECTED) {
 			DEBUGP("ip_conntrack_in: related packet for %p\n",
 			       h->ctrack);
-			ctinfo = IP_CT_RELATED;
+			*ctinfo = IP_CT_RELATED;
 		} else {
 			DEBUGP("ip_conntrack_in: new packet for %p\n",
 			       h->ctrack);
-			ctinfo = IP_CT_NEW;
+			*ctinfo = IP_CT_NEW;
 		}
 	}
-	skb->nfct = &h->ctrack->infos[ctinfo];
+	skb->nfct = &h->ctrack->infos[*ctinfo];
+	return h->ctrack;
 }
 
 /* Return conntrack and conntrack_info a given skb */
-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, create);
-	}
-
+inline struct ip_conntrack *
+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+{
 	if (skb->nfct) {
 		struct ip_conntrack *ct
 			= (struct ip_conntrack *)skb->nfct->master;
@@ -493,11 +591,6 @@
 	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,
@@ -526,15 +619,19 @@
 			return NF_STOLEN;
 	}
 
-	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);
+
+	/* It may be an icmp error... */
+	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP 
+	    || !(ct = icmp_error_track(*pskb, &ctinfo))) {
+		if (!(ct = resolve_normal_ct(*pskb, proto, &ctinfo))) {
+			/* Not valid part of a connection */
+			return NF_ACCEPT;
+		}
 	}
+	IP_NF_ASSERT((*pskb)->nfct);
 
-	proto = find_proto((*pskb)->nh.iph->protocol);
 	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
-
 	if (ret == -1) {
 		/* Invalid */
 		nf_conntrack_put((*pskb)->nfct);
@@ -665,10 +762,15 @@
 	IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
 
 	WRITE_LOCK(&ip_conntrack_lock);
-	/* 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);
+	/* Timer may not be active yet */
+	if (!(ct->status & IPS_CONFIRMED))
+		ct->timeout.expires = extra_jiffies;
+	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);
 }
@@ -740,6 +842,17 @@
 		/* Time to push up daises... */
 		if (del_timer(&h->ctrack->timeout))
 			death_by_timeout((unsigned long)h->ctrack);
+		else if (!(h->ctrack->status & IPS_CONFIRMED)) {
+			/* Unconfirmed connection.  Clean from lists,
+			   mark confirmed so it gets cleaned as soon
+			   as packet comes back. */
+			WRITE_LOCK(&ip_conntrack_lock);
+			if (!(h->ctrack->status & IPS_CONFIRMED)) {
+				clean_from_lists(h->ctrack);
+				h->ctrack->status |= IPS_CONFIRMED;
+			}
+			WRITE_UNLOCK(&ip_conntrack_lock);
+		}
 		/* ... else the timer will get him soon. */
 
 		ip_conntrack_put(h->ctrack);
@@ -836,7 +949,14 @@
 #ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(ip_conntrack_sysctl_header);
 #endif
+ 
+ i_see_dead_people:
 	ip_ct_selective_cleanup(kill_all, NULL);
+	if (atomic_read(&ip_conntrack_count) != 0) {
+		schedule();
+		goto i_see_dead_people;
+	}
+
 	kmem_cache_destroy(ip_conntrack_cachep);
 	vfree(ip_conntrack_hash);
 	nf_unregister_sockopt(&so_getorigdst);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Thu Apr 27 15:43:15 2000
@@ -23,6 +23,10 @@
 /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
    closely.  They're more complex. --RR */
 
+/* We steal a bit to indicate no reply yet (can't use status, because
+   it's set before we get into packet handling). */
+#define TCP_REPLY_BIT 0x1000
+
 /* Actually, I believe that neither ipmasq (where this code is stolen
    from) nor ipfilter do it exactly right.  A new conntrack machine taking
    into account packet loss (which creates uncertainty as to exactly
@@ -141,7 +145,7 @@
 	enum tcp_conntrack state;
 
 	READ_LOCK(&tcp_lock);
-	state = conntrack->proto.tcp_state;
+	state = (conntrack->proto.tcp_state & ~TCP_REPLY_BIT);
 	READ_UNLOCK(&tcp_lock);
 
 	return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
@@ -161,7 +165,7 @@
 		      struct iphdr *iph, size_t len,
 		      enum ip_conntrack_info ctinfo)
 {
-	enum tcp_conntrack newconntrack;
+	enum tcp_conntrack newconntrack, oldtcpstate;
 	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
 
 	/* We're guaranteed to have the base header, but maybe not the
@@ -172,10 +176,11 @@
 	}
 
 	WRITE_LOCK(&tcp_lock);
+	oldtcpstate = conntrack->proto.tcp_state;
 	newconntrack
 		= tcp_conntracks
 		[CTINFO2DIR(ctinfo)]
-		[get_conntrack_index(tcph)][conntrack->proto.tcp_state];
+		[get_conntrack_index(tcph)][oldtcpstate & ~TCP_REPLY_BIT];
 
 	/* Invalid */
 	if (newconntrack == TCP_CONNTRACK_MAX) {
@@ -187,9 +192,22 @@
 	}
 
 	conntrack->proto.tcp_state = newconntrack;
+	if ((oldtcpstate & TCP_REPLY_BIT)
+	    || ctinfo >= IP_CT_IS_REPLY)
+		conntrack->proto.tcp_state |= TCP_REPLY_BIT;
+
 	WRITE_UNLOCK(&tcp_lock);
 
-	ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
+	/* If only reply is a RST, we can consider ourselves not to
+	   have an established connection: this is a fairly common
+	   problem case, so we can delete the conntrack
+	   immediately.  --RR */
+	if (!(oldtcpstate & TCP_REPLY_BIT) && tcph->rst) {
+		if (del_timer(&conntrack->timeout))
+			conntrack->timeout.function((unsigned long)conntrack);
+	} else 
+		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
+
 	return NF_ACCEPT;
 }
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Thu Apr 27 15:43:15 2000
@@ -86,6 +86,12 @@
 	len += print_tuple(buffer + len,
 			   &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
 			   proto);
+#if 0
+	if (!(conntrack->status & IPS_CONFIRMED))
+		len += sprintf(buffer + len, "[UNCONFIRMED] ");
+	len += sprintf(buffer + len, "use=%u ",
+		       atomic_read(&conntrack->ct_general.use));
+#endif
 	len += sprintf(buffer + len, "\n");
 
 	return len;
@@ -157,6 +163,22 @@
 	return len;
 }
 
+static unsigned int ip_confirm(unsigned int hooknum,
+			       struct sk_buff **pskb,
+			       const struct net_device *in,
+			       const struct net_device *out,
+			       int (*okfn)(struct sk_buff *))
+{
+	/* We've seen it coming out the other side: confirm */
+	if ((*pskb)->nfct) {
+		struct ip_conntrack *ct
+			= (struct ip_conntrack *)(*pskb)->nfct->master;
+		if (!(ct->status & IPS_CONFIRMED))
+			ip_conntrack_confirm(ct);
+	}
+	return NF_ACCEPT;
+}
+
 static unsigned int ip_refrag(unsigned int hooknum,
 			      struct sk_buff **pskb,
 			      const struct net_device *in,
@@ -165,6 +187,14 @@
 {
 	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 
+	/* We've seen it coming out the other side: confirm */
+	if ((*pskb)->nfct) {
+		struct ip_conntrack *ct
+			= (struct ip_conntrack *)(*pskb)->nfct->master;
+		if (!(ct->status & IPS_CONFIRMED))
+			ip_conntrack_confirm(ct);
+	}
+
 	/* Local packets are never produced too large for their
 	   interface.  We degfragment them at LOCAL_OUT, however,
 	   so we have to refragment them here. */
@@ -203,6 +233,8 @@
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops
 = { { NULL, NULL }, ip_refrag, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_LAST };
+static struct nf_hook_ops ip_conntrack_local_in_ops
+= { { NULL, NULL }, ip_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST-1 };
 
 static int init_or_cleanup(int init)
 {
@@ -230,10 +262,17 @@
 		printk("ip_conntrack: can't register post-routing hook.\n");
 		goto cleanup_inandlocalops;
 	}
+	ret = nf_register_hook(&ip_conntrack_local_in_ops);
+	if (ret < 0) {
+		printk("ip_conntrack: can't register local in hook.\n");
+		goto cleanup_inoutandlocalops;
+	}
 
 	return ret;
 
  cleanup:
+	nf_unregister_hook(&ip_conntrack_local_in_ops);
+ cleanup_inoutandlocalops:
 	nf_unregister_hook(&ip_conntrack_out_ops);
  cleanup_inandlocalops:
 	nf_unregister_hook(&ip_conntrack_local_out_ops);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_fw_compat.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_fw_compat.c	Thu Apr 27 15:43:16 2000
@@ -13,6 +13,7 @@
 #include <net/route.h>
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
 
 static struct firewall_ops *fwops;
 
@@ -60,6 +61,18 @@
 	return 0;
 }
 
+static inline void
+confirm_connection(struct sk_buff *skb)
+{
+	if (skb->nfct) {
+		struct ip_conntrack *ct
+			= (struct ip_conntrack *)skb->nfct->master;
+
+		if (!(ct->status & IPS_CONFIRMED))
+			ip_conntrack_confirm(ct);
+	}
+}
+
 static unsigned int
 fw_in(unsigned int hooknum,
       struct sk_buff **pskb,
@@ -105,10 +118,14 @@
 		ret = fwops->fw_output(fwops, PF_INET,
 				       (struct net_device *)out,
 				       (*pskb)->nh.raw, &redirpt, pskb);
-		if (fwops->fw_acct_out && (ret == FW_ACCEPT || ret == FW_SKIP))
-			fwops->fw_acct_out(fwops, PF_INET,
-					   (struct net_device *)in,
-					   (*pskb)->nh.raw, &redirpt, pskb);
+		if (ret == FW_ACCEPT || ret == FW_SKIP) {
+			if (fwops->fw_acct_out)
+				fwops->fw_acct_out(fwops, PF_INET,
+						   (struct net_device *)in,
+						   (*pskb)->nh.raw, &redirpt,
+						   pskb);
+			confirm_connection(*pskb);
+		}
 		break;
 	}
 
@@ -155,6 +172,16 @@
 	}
 }
 
+static unsigned int fw_confirm(unsigned int hooknum,
+			       struct sk_buff **pskb,
+			       const struct net_device *in,
+			       const struct net_device *out,
+			       int (*okfn)(struct sk_buff *))
+{
+	confirm_connection(*pskb);
+	return NF_ACCEPT;
+}
+
 extern int ip_fw_ctl(int optval, void *user, unsigned int len);
 
 static int sock_fn(struct sock *sk, int optval, void *user, unsigned int len)
@@ -174,6 +201,9 @@
 static struct nf_hook_ops forward_ops
 = { { NULL, NULL }, fw_in, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER };
 
+static struct nf_hook_ops local_in_ops
+= { { NULL, NULL }, fw_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST - 1 };
+
 static struct nf_sockopt_ops sock_ops
 = { { NULL, NULL }, PF_INET, 64, 64 + 1024 + 1, &sock_fn, 0, 0, NULL,
     0, NULL };
@@ -202,6 +232,7 @@
 	nf_register_hook(&preroute_ops);
 	nf_register_hook(&postroute_ops);
 	nf_register_hook(&forward_ops);
+	nf_register_hook(&local_in_ops);
 
 	return ret;
 
@@ -209,6 +240,7 @@
 	nf_unregister_hook(&preroute_ops);
 	nf_unregister_hook(&postroute_ops);
 	nf_unregister_hook(&forward_ops);
+	nf_unregister_hook(&local_in_ops);
 
 	masq_cleanup();
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Thu Apr 27 15:43:16 2000
@@ -103,6 +103,7 @@
 	struct ip_conntrack_protocol *protocol;
 	struct ip_conntrack_tuple_hash *h;
 	enum ip_conntrack_info ctinfo;
+	struct ip_conntrack *ct;
 	int ret;
 
 	protocol = find_proto(iph->protocol);
@@ -113,31 +114,18 @@
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
 		/* ICMP errors. */
-		if (icmp_error_track(*pskb)) {
-			/* If it is valid, tranlsate it */
-			if ((*pskb)->nfct) {
-				struct ip_conntrack *ct
-					= (struct ip_conntrack *)
-					(*pskb)->nfct->master;
-				enum ip_conntrack_dir dir;
-
-				if ((*pskb)->nfct-ct->infos >= IP_CT_IS_REPLY)
-					dir = IP_CT_DIR_REPLY;
-				else
-					dir = IP_CT_DIR_ORIGINAL;
-
-				icmp_reply_translation(*pskb,
-						       ct,
-						       NF_IP_PRE_ROUTING,
-						       dir);
-			}
+		if ((ct = icmp_error_track(*pskb, &ctinfo))) {
+			icmp_reply_translation(*pskb, ct,
+					       NF_IP_PRE_ROUTING,
+					       CTINFO2DIR(ctinfo));
 			return NF_ACCEPT;
 		}
 		/* Fall thru... */
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
 		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
-			printk("ip_fw_compat_masq: Couldn't get tuple\n");
+			if (net_ratelimit())
+				printk("ip_fw_compat_masq: Can't get tuple\n");
 			return NF_ACCEPT;
 		}
 		break;
@@ -166,8 +154,9 @@
 					    NF_IP_PRE_ROUTING,
 					    pskb);
 			} else
-				printk("ip_fw_compat_masq: conntrack"
-				       " didn't like\n");
+				if (net_ratelimit()) 
+					printk("ip_fw_compat_masq: conntrack"
+					       " didn't like\n");
 		}
 	} else {
 		if (h)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ip_tables.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/netfilter/ip_tables.c	Thu Apr 27 15:43:15 2000
@@ -589,6 +589,9 @@
 	if (i && (*i)-- == 0)
 		return 1;
 
+	if (m->u.match->destroy)
+		m->u.match->destroy(m->data, m->match_size - sizeof(*m));
+
 	if (m->u.match->me)
 		__MOD_DEC_USE_COUNT(m->u.match->me);
 
@@ -769,6 +772,8 @@
 	/* Cleanup all matches */
 	IPT_MATCH_ITERATE(e, cleanup_match, NULL);
 	t = ipt_get_target(e);
+	if (t->u.target->destroy)
+		t->u.target->destroy(t->data, t->target_size - sizeof(*t));
 	if (t->u.target->me)
 		__MOD_DEC_USE_COUNT(t->u.target->me);
 
@@ -1094,7 +1099,7 @@
 	/* Silent error: too late now. */
 	copy_to_user(tmp.counters, counters,
 		     sizeof(struct ipt_counters) * tmp.num_counters);
-
+	vfree(counters);
 	up(&ipt_mutex);
 	return 0;
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_LOG.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Thu Apr 27 15:43:15 2000
@@ -334,7 +334,8 @@
 }
 
 static struct ipt_target ipt_log_reg
-= { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, THIS_MODULE };
+= { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, NULL, 
+    THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MARK.c linux/net/ipv4/netfilter/ipt_MARK.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MARK.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_MARK.c	Thu Apr 27 15:43:15 2000
@@ -47,7 +47,7 @@
 }
 
 static struct ipt_target ipt_mark_reg
-= { { NULL, NULL }, "MARK", target, checkentry, THIS_MODULE };
+= { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MASQUERADE.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c	Thu Apr 27 15:43:15 2000
@@ -60,7 +60,7 @@
 {
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
-	const struct ip_nat_range *r;
+	const struct ip_nat_multi_range *mr;
 	struct ip_nat_multi_range newrange;
 	u_int32_t newsrc;
 	struct rtable *rt;
@@ -76,7 +76,7 @@
 	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW
 				  || ctinfo == IP_CT_RELATED));
 
-	r = targinfo;
+	mr = targinfo;
 
 	if (ip_route_output(&rt, (*pskb)->nh.iph->daddr,
 			    0,
@@ -97,9 +97,9 @@
 
 	/* Transfer from original range. */
 	newrange = ((struct ip_nat_multi_range)
-		{ 1, { { r->flags | IP_NAT_RANGE_MAP_IPS,
+		{ 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 			 newsrc, newsrc,
-			 r->min, r->max } } });
+			 mr->range[0].min, mr->range[0].max } } });
 
 	/* Hand modified range to generic setup. */
 	return ip_nat_setup_info(ct, &newrange, hooknum);
@@ -142,7 +142,7 @@
 };
 
 static struct ipt_target masquerade
-= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check,
+= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check, NULL,
     THIS_MODULE };
 
 static int __init init(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MIRROR.c linux/net/ipv4/netfilter/ipt_MIRROR.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_MIRROR.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_MIRROR.c	Thu Apr 27 15:43:15 2000
@@ -113,7 +113,7 @@
 }
 
 static struct ipt_target ipt_mirror_reg
-= { { NULL, NULL }, "MIRROR", ipt_mirror_target, ipt_mirror_checkentry,
+= { { NULL, NULL }, "MIRROR", ipt_mirror_target, ipt_mirror_checkentry, NULL,
     THIS_MODULE };
 
 static int __init init(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_REDIRECT.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_REDIRECT.c	Thu Apr 27 15:43:15 2000
@@ -58,7 +58,7 @@
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 	u_int32_t newdst;
-	const struct ip_nat_range *r = targinfo;
+	const struct ip_nat_multi_range *mr = targinfo;
 	struct ip_nat_multi_range newrange;
 
 	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
@@ -77,16 +77,17 @@
 
 	/* Transfer from original range. */
 	newrange = ((struct ip_nat_multi_range)
-		{ 1, { { r->flags | IP_NAT_RANGE_MAP_IPS,
+		{ 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 			 newdst, newdst,
-			 r->min, r->max } } });
+			 mr->range[0].min, mr->range[0].max } } });
 
 	/* Hand modified range to generic setup. */
 	return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static struct ipt_target redirect_reg
-= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, THIS_MODULE };
+= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, NULL,
+    THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_REJECT.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_REJECT.c	Thu Apr 27 15:43:15 2000
@@ -120,7 +120,7 @@
 }
 
 static struct ipt_target ipt_reject_reg
-= { { NULL, NULL }, "REJECT", reject, check, THIS_MODULE };
+= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_TOS.c linux/net/ipv4/netfilter/ipt_TOS.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_TOS.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_TOS.c	Thu Apr 27 15:43:15 2000
@@ -66,7 +66,7 @@
 }
 
 static struct ipt_target ipt_tos_reg
-= { { NULL, NULL }, "TOS", target, checkentry, THIS_MODULE };
+= { { NULL, NULL }, "TOS", target, checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_limit.c linux/net/ipv4/netfilter/ipt_limit.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_limit.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_limit.c	Thu Apr 27 15:43:15 2000
@@ -124,7 +124,7 @@
 }
 
 static struct ipt_match ipt_limit_reg
-= { { NULL, NULL }, "limit", ipt_limit_match, ipt_limit_checkentry,
+= { { NULL, NULL }, "limit", ipt_limit_match, ipt_limit_checkentry, NULL,
     THIS_MODULE };
 
 static int __init init(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_mac.c linux/net/ipv4/netfilter/ipt_mac.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_mac.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_mac.c	Thu Apr 27 15:43:15 2000
@@ -46,7 +46,7 @@
 }
 
 static struct ipt_match mac_match
-= { { NULL, NULL }, "mac", &match, &ipt_mac_checkentry, THIS_MODULE };
+= { { NULL, NULL }, "mac", &match, &ipt_mac_checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_mark.c linux/net/ipv4/netfilter/ipt_mark.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_mark.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_mark.c	Thu Apr 27 15:43:15 2000
@@ -34,7 +34,7 @@
 }
 
 static struct ipt_match mark_match
-= { { NULL, NULL }, "mark", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "mark", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_multiport.c linux/net/ipv4/netfilter/ipt_multiport.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_multiport.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_multiport.c	Thu Apr 27 15:43:15 2000
@@ -84,7 +84,7 @@
 }
 
 static struct ipt_match multiport_match
-= { { NULL, NULL }, "multiport", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_owner.c linux/net/ipv4/netfilter/ipt_owner.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_owner.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_owner.c	Thu Apr 27 15:43:15 2000
@@ -118,7 +118,7 @@
 }
 
 static struct ipt_match owner_match
-= { { NULL, NULL }, "owner", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_state.c linux/net/ipv4/netfilter/ipt_state.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_state.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_state.c	Thu Apr 27 15:43:15 2000
@@ -42,7 +42,7 @@
 }
 
 static struct ipt_match state_match
-= { { NULL, NULL }, "state", &match, &check, THIS_MODULE };
+= { { NULL, NULL }, "state", &match, &check, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_tos.c linux/net/ipv4/netfilter/ipt_tos.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_tos.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_tos.c	Thu Apr 27 15:43:15 2000
@@ -35,7 +35,7 @@
 }
 
 static struct ipt_match tos_match
-= { { NULL, NULL }, "tos", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "tos", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/ipt_unclean.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Thu Apr 27 15:43:15 2000
@@ -558,7 +558,7 @@
 }
 
 static struct ipt_match unclean_match
-= { { NULL, NULL }, "unclean", &match, &checkentry, THIS_MODULE };
+= { { NULL, NULL }, "unclean", &match, &checkentry, NULL, THIS_MODULE };
 
 static int __init init(void)
 {
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/iptable_filter.c linux/net/ipv4/netfilter/iptable_filter.c
--- v2.3.99-pre6/linux/net/ipv4/netfilter/iptable_filter.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/iptable_filter.c	Thu Apr 27 15:43:16 2000
@@ -121,8 +121,8 @@
 		NF_IP_PRI_FILTER }
 };
 
-/* Default to no forward for security reasons. */
-static int forward = NF_DROP;
+/* Default to forward because I got too much mail already. */
+static int forward = NF_ACCEPT;
 MODULE_PARM(forward, "i");
 
 static int __init init(void)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.3.99-pre6/linux/net/ipv4/raw.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/raw.c	Wed May  3 01:48:03 2000
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.49 2000/04/25 04:13:34 davem Exp $
+ * Version:	$Id: raw.c,v 1.50 2000/05/03 06:37:06 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -591,7 +591,7 @@
 	src   = sp->rcv_saddr;
 	destp = 0;
 	srcp  = sp->num;
-	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_active = (timer_pending(&sp->timer)) ? 2 : 0;
 	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.99-pre6/linux/net/ipv4/tcp_ipv4.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/tcp_ipv4.c	Wed May  3 01:48:03 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.207 2000/04/25 04:13:34 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.208 2000/05/03 06:37:06 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -2002,14 +2002,14 @@
 	srcp  = ntohs(sp->sport);
 	timer_active	= 0;
 	timer_expires	= (unsigned) -1;
-	if (tp->retransmit_timer.prev != NULL && tp->retransmit_timer.expires < timer_expires) {
+	if (timer_pending(&tp->retransmit_timer) && tp->retransmit_timer.expires < timer_expires) {
 		timer_active	= 1;
 		timer_expires	= tp->retransmit_timer.expires;
-	} else if (tp->probe_timer.prev != NULL && tp->probe_timer.expires < timer_expires) {
+	} else if (timer_pending(&tp->probe_timer) && tp->probe_timer.expires < timer_expires) {
 		timer_active	= 4;
 		timer_expires	= tp->probe_timer.expires;
 	}
-	if (sp->timer.prev != NULL && sp->timer.expires < timer_expires) {
+	if (timer_pending(&sp->timer) && sp->timer.expires < timer_expires) {
 		timer_active	= 2;
 		timer_expires	= sp->timer.expires;
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.3.99-pre6/linux/net/ipv4/tcp_timer.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/tcp_timer.c	Wed May  3 01:48:03 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.75 2000/04/08 07:21:25 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.76 2000/05/03 06:37:07 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -378,7 +378,7 @@
 static int tcp_twcal_hand = -1;
 static int tcp_twcal_jiffie;
 static void tcp_twcal_tick(unsigned long);
-static struct timer_list tcp_twcal_timer = {NULL, NULL, 0, 0, tcp_twcal_tick,};
+static struct timer_list tcp_twcal_timer = {function: tcp_twcal_tick};
 static struct tcp_tw_bucket *tcp_twcal_row[TCP_TW_RECYCLE_SLOTS];
 
 void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.99-pre6/linux/net/ipv4/udp.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv4/udp.c	Wed May  3 01:48:03 2000
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.81 2000/04/25 04:13:34 davem Exp $
+ * Version:	$Id: udp.c,v 1.82 2000/05/03 06:37:07 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -988,7 +988,7 @@
 	src   = sp->rcv_saddr;
 	destp = ntohs(sp->dport);
 	srcp  = ntohs(sp->sport);
-	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_active = timer_pending(&sp->timer) ? 2 : 0;
 	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.3.99-pre6/linux/net/ipv6/addrconf.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv6/addrconf.c	Wed May  3 01:48:03 2000
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: addrconf.c,v 1.57 2000/01/18 08:24:21 davem Exp $
+ *	$Id: addrconf.c,v 1.58 2000/05/03 06:37:07 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -84,10 +84,7 @@
 
 void addrconf_verify(unsigned long);
 
-static struct timer_list addr_chk_timer = {
-	NULL, NULL,
-	0, 0, addrconf_verify
-};
+static struct timer_list addr_chk_timer = { function: addrconf_verify };
 
 static int addrconf_ifdown(struct net_device *dev, int how);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- v2.3.99-pre6/linux/net/ipv6/ip6_fib.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv6/ip6_fib.c	Wed May  3 01:48:04 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.20 2000/01/16 05:11:37 davem Exp $
+ *	$Id: ip6_fib.c,v 1.21 2000/05/03 06:37:07 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -87,12 +87,7 @@
 
 static __u32	rt_sernum	= 0;
 
-static struct timer_list ip6_fib_timer = {
-	NULL, NULL,
-	0,
-	~0UL,
-	fib6_run_gc
-};
+static struct timer_list ip6_fib_timer = { function: fib6_run_gc };
 
 static struct fib6_walker_t fib6_walker_list = {
 	&fib6_walker_list, &fib6_walker_list, 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.3.99-pre6/linux/net/ipv6/raw.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv6/raw.c	Wed May  3 01:48:04 2000
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.35 2000/04/25 04:13:34 davem Exp $
+ *	$Id: raw.c,v 1.36 2000/05/03 06:37:07 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -715,15 +715,15 @@
 {
 	struct in6_addr *dest, *src;
 	__u16 destp, srcp;
-	int timer_active;
+	int sock_timer_active;
 	unsigned long timer_expires;
 
 	dest  = &sp->net_pinfo.af_inet6.daddr;
 	src   = &sp->net_pinfo.af_inet6.rcv_saddr;
 	destp = 0;
 	srcp  = sp->num;
-	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
-	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sock_timer_active = timer_pending(&sp->timer) ? 2 : 0;
+	timer_expires = (sock_timer_active == 2 ? sp->timer.expires : jiffies);
 	sprintf(tmpbuf,
 		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
 		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
@@ -734,7 +734,7 @@
 		dest->s6_addr32[2], dest->s6_addr32[3], destp,
 		sp->state, 
 		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
-		timer_active, timer_expires-jiffies, 0,
+		sock_timer_active, timer_expires-jiffies, 0,
 		sp->socket->inode->i_uid, 0,
 		sp->socket ? sp->socket->inode->i_ino : 0,
 		atomic_read(&sp->refcnt), sp);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c
--- v2.3.99-pre6/linux/net/ipv6/reassembly.c	Tue Jan 11 22:31:46 2000
+++ linux/net/ipv6/reassembly.c	Wed May  3 01:48:04 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: reassembly.c,v 1.16 2000/01/09 02:19:51 davem Exp $
+ *	$Id: reassembly.c,v 1.17 2000/05/03 06:37:07 davem Exp $
  *
  *	Based on: net/ipv4/ip_fragment.c
  *
@@ -87,9 +87,6 @@
 
 static struct frag_queue ipv6_frag_queue = {
 	&ipv6_frag_queue, &ipv6_frag_queue,
-	0, {{{0}}}, {{{0}}},
-	{0}, NULL, NULL,
-	0, 0, 0, 0
 };
 
 /* Memory Tracking Functions. */
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
--- v2.3.99-pre6/linux/net/ipv6/sit.c	Mon Mar 27 08:08:34 2000
+++ linux/net/ipv6/sit.c	Wed May  3 01:48:04 2000
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: sit.c,v 1.37 2000/03/21 06:14:00 davem Exp $
+ *	$Id: sit.c,v 1.38 2000/05/03 06:37:07 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -58,7 +58,7 @@
 static int ipip6_tunnel_init(struct net_device *dev);
 
 static struct net_device ipip6_fb_tunnel_dev = {
-	NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip6_fb_tunnel_init,
+	"", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip6_fb_tunnel_init,
 };
 
 static struct ip_tunnel ipip6_fb_tunnel = {
@@ -173,7 +173,7 @@
 	dev->priv = (void*)(dev+1);
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
-	dev->name = nt->parms.name;
+	strcpy(dev->name, nt->parms.name);
 	dev->init = ipip6_tunnel_init;
 	dev->new_style = 1;
 	memcpy(&nt->parms, parms, sizeof(*parms));
@@ -810,7 +810,7 @@
 	printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
 
 	ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel;
-	ipip6_fb_tunnel_dev.name = ipip6_fb_tunnel.parms.name;
+	strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
 #ifdef MODULE
 	register_netdev(&ipip6_fb_tunnel_dev);
 #else
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.99-pre6/linux/net/ipv6/tcp_ipv6.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv6/tcp_ipv6.c	Wed May  3 01:48:04 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.123 2000/04/25 04:13:34 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.124 2000/05/03 06:37:07 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -1893,14 +1893,14 @@
 	srcp  = ntohs(sp->sport);
 	timer_active	= 0;
 	timer_expires	= (unsigned) -1;
-	if (tp->retransmit_timer.prev != NULL && tp->retransmit_timer.expires < timer_expires) {
+	if (timer_pending(&tp->retransmit_timer) && tp->retransmit_timer.expires < timer_expires) {
 		timer_active	= 1;
 		timer_expires	= tp->retransmit_timer.expires;
-	} else if (tp->probe_timer.prev != NULL && tp->probe_timer.expires < timer_expires) {
+	} else if (timer_pending(&tp->probe_timer) && tp->probe_timer.expires < timer_expires) {
 		timer_active	= 4;
 		timer_expires	= tp->probe_timer.expires;
 	}
-	if (sp->timer.prev != NULL && sp->timer.expires < timer_expires) {
+	if (timer_pending(&sp->timer) && sp->timer.expires < timer_expires) {
 		timer_active	= 2;
 		timer_expires	= sp->timer.expires;
 	}
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.3.99-pre6/linux/net/ipv6/udp.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipv6/udp.c	Wed May  3 01:48:04 2000
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.52 2000/04/25 04:13:34 davem Exp $
+ *	$Id: udp.c,v 1.53 2000/05/03 06:37:07 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -901,15 +901,15 @@
 {
 	struct in6_addr *dest, *src;
 	__u16 destp, srcp;
-	int timer_active;
+	int sock_timer_active;
 	unsigned long timer_expires;
 
 	dest  = &sp->net_pinfo.af_inet6.daddr;
 	src   = &sp->net_pinfo.af_inet6.rcv_saddr;
 	destp = ntohs(sp->dport);
 	srcp  = ntohs(sp->sport);
-	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
-	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sock_timer_active = timer_pending(&sp->timer) ? 2 : 0;
+	timer_expires = (sock_timer_active == 2 ? sp->timer.expires : jiffies);
 	sprintf(tmpbuf,
 		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
 		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
@@ -920,7 +920,7 @@
 		dest->s6_addr32[2], dest->s6_addr32[3], destp,
 		sp->state, 
 		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
-		timer_active, timer_expires-jiffies, 0,
+		sock_timer_active, timer_expires-jiffies, 0,
 		sp->socket->inode->i_uid, 0,
 		sp->socket ? sp->socket->inode->i_ino : 0,
 		atomic_read(&sp->refcnt), sp);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.3.99-pre6/linux/net/ipx/af_spx.c	Wed Apr 26 16:34:09 2000
+++ linux/net/ipx/af_spx.c	Fri Apr 28 22:50:14 2000
@@ -466,9 +466,7 @@
         ipxh->spx.allocseq      = htons(pdata->alloc);
 
 	/* Reset/Set WD timer */
-        del_timer(&pdata->watchdog);
-        pdata->watchdog.expires = jiffies + VERIFY_TIMEOUT;
-        add_timer(&pdata->watchdog);
+        mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
 
 	switch(type)
 	{
diff -u --recursive --new-file v2.3.99-pre6/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- v2.3.99-pre6/linux/net/irda/irlan/irlan_client.c	Sun Feb 20 21:12:40 2000
+++ linux/net/irda/irlan/irlan_client.c	Thu May  4 11:31:22 2000
@@ -139,7 +139,7 @@
 		 * down by the user
 		 */
 		mgr_event.event = EVENT_IRLAN_START;
-		sprintf(mgr_event.devname, "%s", self->ifname);
+		strcpy(mgr_event.devname, self->dev.name);
 		irmanager_notify(&mgr_event);
 		
 		/* 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.3.99-pre6/linux/net/irda/irlan/irlan_common.c	Sun Feb 20 21:12:40 2000
+++ linux/net/irda/irlan/irlan_common.c	Thu May  4 11:31:22 2000
@@ -124,7 +124,7 @@
 		IRDA_DEBUG(0, __FUNCTION__ 
 		      "(), notifying irmanager to stop irlan!\n");
 		mgr_event.event = EVENT_IRLAN_STOP;
-		sprintf(mgr_event.devname, "%s", self->ifname);
+		sprintf(mgr_event.devname, "%s", self->dev.name);
 		irmanager_notify(&mgr_event);
 
 		/*
@@ -234,10 +234,9 @@
 	if (!eth) {
 		/* Get the first free irlan<x> name */
 		do {
-			sprintf(self->ifname, "%s%d", "irlan", i++);
-		} while (dev_get(self->ifname));
+			sprintf(self->dev.name, "%s%d", "irlan", i++);
+		} while (dev_get(self->dev.name));
 	}
-	self->dev.name = self->ifname;
 	
 	if (register_netdev(&self->dev) != 0) {
 		IRDA_DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n");
@@ -276,7 +275,7 @@
 
 	ASSERT(irlan != NULL, return NULL;);
 	
-	sprintf(self->ifname, "%s", "unknown");
+	sprintf(self->dev.name, "%s", "unknown");
 
 	self->dev.priv = (void *) self;
 	self->dev.next = NULL;
@@ -1173,7 +1172,7 @@
 		/* Don't display the master server */
 		if (self->master == 0) {
 			len += sprintf(buf+len, "ifname: %s,\n",
-				       self->ifname);
+				       self->dev.name);
 			len += sprintf(buf+len, "client state: %s, ",
 				       irlan_state[ self->client.state]);
 			len += sprintf(buf+len, "provider state: %s,\n",
diff -u --recursive --new-file v2.3.99-pre6/linux/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c
--- v2.3.99-pre6/linux/net/irda/irlan/irlan_eth.c	Mon Mar 27 08:08:34 2000
+++ linux/net/irda/irlan/irlan_eth.c	Thu May  4 11:31:22 2000
@@ -90,7 +90,7 @@
 	 * it, so it can be configured with network parameters
 	 */
 	mgr_event.event = EVENT_IRLAN_START;
-	sprintf(mgr_event.devname, "%s", self->ifname);
+	sprintf(mgr_event.devname, "%s", self->dev.name);
 	irmanager_notify(&mgr_event);
 
 	/* 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.3.99-pre6/linux/net/lapb/lapb_iface.c	Tue Aug 31 17:29:15 1999
+++ linux/net/lapb/lapb_iface.c	Thu May  4 11:26:32 2000
@@ -196,12 +196,12 @@
 	parms->window  = lapb->window;
 	parms->mode    = lapb->mode;
 
-	if (lapb->t1timer.prev == NULL && lapb->t1timer.next == NULL)
+	if (!timer_pending(&lapb->t1timer))
 		parms->t1timer = 0;
 	else
 		parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
 
-	if (lapb->t2timer.prev == NULL && lapb->t2timer.next == NULL)
+	if (!timer_pending(&lapb->t2timer))
 		parms->t2timer = 0;
 	else
 		parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
diff -u --recursive --new-file v2.3.99-pre6/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c
--- v2.3.99-pre6/linux/net/lapb/lapb_timer.c	Mon Jul  7 08:19:59 1997
+++ linux/net/lapb/lapb_timer.c	Thu May  4 11:26:52 2000
@@ -73,7 +73,7 @@
 
 int lapb_t1timer_running(lapb_cb *lapb)
 {
-	return (lapb->t1timer.prev != NULL || lapb->t1timer.next != NULL);
+	return timer_pending(&lapb->t1timer);
 }
 
 static void lapb_t2timer_expiry(unsigned long param)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.3.99-pre6/linux/net/netrom/af_netrom.c	Wed Apr 26 16:34:10 2000
+++ linux/net/netrom/af_netrom.c	Thu May  4 11:31:22 2000
@@ -1281,12 +1281,6 @@
 	memset(dev_nr, 0x00, nr_ndevs * sizeof(struct net_device));
 
 	for (i = 0; i < nr_ndevs; i++) {
-		dev_nr[i].name = kmalloc(20, GFP_KERNEL);
-		if(dev_nr[i].name==NULL)
-		{
-			printk(KERN_ERR "Netrom: unable to register devices.\n");
-			break;
-		}
 		sprintf(dev_nr[i].name, "nr%d", i);
 		dev_nr[i].init = nr_init;
 		register_netdev(&dev_nr[i]);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/netrom/nr_loopback.c linux/net/netrom/nr_loopback.c
--- v2.3.99-pre6/linux/net/netrom/nr_loopback.c	Fri Jan 21 18:19:17 2000
+++ linux/net/netrom/nr_loopback.c	Thu May  4 11:27:14 2000
@@ -38,7 +38,7 @@
 
 static int nr_loopback_running(void)
 {
-	return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+	return timer_pending(&loopback_timer);
 }
 
 int nr_loopback_queue(struct sk_buff *skb)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v2.3.99-pre6/linux/net/netrom/nr_timer.c	Mon Jul  7 08:20:00 1997
+++ linux/net/netrom/nr_timer.c	Thu May  4 11:27:39 2000
@@ -129,8 +129,7 @@
 
 int nr_t1timer_running(struct sock *sk)
 {
-	return (sk->protinfo.nr->t1timer.prev != NULL ||
-		sk->protinfo.nr->t1timer.next != NULL);
+	return timer_pending(&sk->protinfo.nr->t1timer);
 }
 
 static void nr_heartbeat_expiry(unsigned long param)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.99-pre6/linux/net/netsyms.c	Wed Apr 26 16:34:10 2000
+++ linux/net/netsyms.c	Mon May  8 11:17:47 2000
@@ -197,7 +197,6 @@
 /* Needed by unix.o */
 EXPORT_SYMBOL(scm_fp_dup);
 EXPORT_SYMBOL(max_files);
-EXPORT_SYMBOL(do_mknod);
 EXPORT_SYMBOL(memcpy_toiovec);
 EXPORT_SYMBOL(csum_partial);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/protocols.c linux/net/protocols.c
--- v2.3.99-pre6/linux/net/protocols.c	Thu Aug 26 13:05:46 1999
+++ linux/net/protocols.c	Mon May  8 22:21:58 2000
@@ -100,6 +100,11 @@
 #include <net/p8022call.h>
 #endif
 
+
+#ifdef CONFIG_PPPOE
+#include <linux/if_pppox.h>
+#endif
+
 /*
  *	Protocol Table
  */
@@ -177,6 +182,8 @@
 #ifdef CONFIG_IRDA
   { "IrDA",     irda_proto_init },                     /* IrDA protocols */
 #endif
-
+#ifdef CONFIG_PPPOE
+  { "PPPoX",	pppox_proto_init },			/* PPP over Ethernet */
+#endif
   { NULL,	NULL		}			/* End marker			*/
 };
diff -u --recursive --new-file v2.3.99-pre6/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.3.99-pre6/linux/net/rose/af_rose.c	Wed Apr 26 16:34:10 2000
+++ linux/net/rose/af_rose.c	Thu May  4 11:31:22 2000
@@ -1453,12 +1453,6 @@
 	memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device));
 
 	for (i = 0; i < rose_ndevs; i++) {
-		dev_rose[i].name = kmalloc(20, GFP_KERNEL);
-		if(dev_rose[i].name == NULL)
-		{
-			printk(KERN_ERR "Rose: unable to register ROSE devices.\n");
-			break;
-		}
 		sprintf(dev_rose[i].name, "rose%d", i);
 		dev_rose[i].init = rose_init;
 		register_netdev(&dev_rose[i]);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.3.99-pre6/linux/net/rose/rose_link.c	Thu Aug 26 13:05:46 1999
+++ linux/net/rose/rose_link.c	Thu May  4 11:28:23 2000
@@ -76,12 +76,12 @@
 
 int rose_ftimer_running(struct rose_neigh *neigh)
 {
-	return (neigh->ftimer.prev != NULL || neigh->ftimer.next != NULL);
+	return timer_pending(&neigh->ftimer);
 }
 
 int rose_t0timer_running(struct rose_neigh *neigh)
 {
-	return (neigh->t0timer.prev != NULL || neigh->t0timer.next != NULL);
+	return timer_pending(&neigh->t0timer);
 }
 
 static void rose_ftimer_expiry(unsigned long param)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/rose/rose_loopback.c linux/net/rose/rose_loopback.c
--- v2.3.99-pre6/linux/net/rose/rose_loopback.c	Wed Aug 18 11:38:49 1999
+++ linux/net/rose/rose_loopback.c	Thu May  4 11:28:47 2000
@@ -37,7 +37,7 @@
 
 static int rose_loopback_running(void)
 {
-	return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+	return timer_pending(&loopback_timer);
 }
 
 int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
diff -u --recursive --new-file v2.3.99-pre6/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c
--- v2.3.99-pre6/linux/net/sched/sch_generic.c	Thu Mar  2 14:36:23 2000
+++ linux/net/sched/sch_generic.c	Tue May  2 16:48:16 2000
@@ -513,7 +513,7 @@
         }
 #endif
 	BUG_TRAP(dev->qdisc_list == NULL);
-	BUG_TRAP(dev->watchdog_timer.prev == NULL);
+	BUG_TRAP(!timer_pending(&dev->watchdog_timer));
 	dev->qdisc_list = NULL;
 	spin_unlock_bh(&dev->queue_lock);
 	write_unlock(&qdisc_tree_lock);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- v2.3.99-pre6/linux/net/sched/sch_tbf.c	Sun Feb 20 21:12:40 2000
+++ linux/net/sched/sch_tbf.c	Fri Apr 28 22:50:14 2000
@@ -232,9 +232,7 @@
 			if (delay == 0)
 				delay = 1;
 
-			del_timer(&q->wd_timer);
-			q->wd_timer.expires = jiffies + delay;
-			add_timer(&q->wd_timer);
+			mod_timer(&q->wd_timer, jiffies+delay);
 		}
 
 		/* Maybe we have a shorter packet in the queue,
diff -u --recursive --new-file v2.3.99-pre6/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c
--- v2.3.99-pre6/linux/net/sched/sch_teql.c	Sun Feb 20 21:12:40 2000
+++ linux/net/sched/sch_teql.c	Thu May  4 11:31:22 2000
@@ -70,7 +70,6 @@
 	struct net_device dev;
 	struct Qdisc *slaves;
 	struct net_device_stats stats;
-	char name[IFNAMSIZ];
 };
 
 struct teql_sched_data
@@ -469,11 +468,10 @@
 	rtnl_lock();
 
 	the_master.dev.priv = (void*)&the_master;
-	the_master.dev.name = (void*)&the_master.name;
 	err = dev_alloc_name(&the_master.dev, "teql%d");
 	if (err < 0)
 		return err;
-	memcpy(the_master.qops.id, the_master.name, IFNAMSIZ);
+	memcpy(the_master.qops.id, the_master.dev.name, IFNAMSIZ);
 	the_master.dev.init = teql_master_init;
 
 	err = register_netdevice(&the_master.dev);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/socket.c linux/net/socket.c
--- v2.3.99-pre6/linux/net/socket.c	Wed Apr 26 16:34:10 2000
+++ linux/net/socket.c	Tue May  2 12:36:09 2000
@@ -269,6 +269,8 @@
 		}
 
 		file->f_dentry = d_alloc_root(sock->inode);
+		/* MOUNT_REWRITE: set to sockfs internal vfsmnt */
+		file->f_vfsmnt = NULL;
 		if (!file->f_dentry) {
 			put_filp(file);
 			put_unused_fd(fd);
diff -u --recursive --new-file v2.3.99-pre6/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.3.99-pre6/linux/net/sunrpc/sched.c	Wed Apr 26 16:34:10 2000
+++ linux/net/sunrpc/sched.c	Thu May  4 22:40:17 2000
@@ -1005,6 +1005,7 @@
 	rpciod_pid = current->pid;
 	up(&rpciod_running);
 
+	exit_fs(current);
 	exit_files(current);
 	exit_mm(current);
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/sunrpc/svcauth.c linux/net/sunrpc/svcauth.c
--- v2.3.99-pre6/linux/net/sunrpc/svcauth.c	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/svcauth.c	Fri Apr 28 22:50:39 2000
@@ -4,6 +4,9 @@
  * The generic interface for RPC authentication on the server side.
  * 
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ *
+ * CHANGES
+ * 19-Apr-2000 Chris Evans      - Security fix
  */
 
 #include <linux/types.h>
@@ -116,8 +119,8 @@
 	struct svc_buf	*argp = &rqstp->rq_argbuf;
 	struct svc_buf	*resp = &rqstp->rq_resbuf;
 	struct svc_cred	*cred = &rqstp->rq_cred;
-	u32		*bufp = argp->buf;
-	int		len   = argp->len, slen, i;
+	u32		*bufp = argp->buf, slen, i;
+	int		len   = argp->len;
 
 	if ((len -= 3) < 0) {
 		*statp = rpc_garbage_args;
@@ -127,7 +130,7 @@
 	bufp++;					/* length */
 	bufp++;					/* time stamp */
 	slen = (ntohl(*bufp++) + 3) >> 2;	/* machname length */
-	if (slen > 64 || (len -= slen) < 0)
+	if (slen > 64 || (len -= slen + 3) < 0)
 		goto badcred;
 	bufp += slen;				/* skip machname */
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.99-pre6/linux/net/unix/af_unix.c	Wed Apr 26 16:34:10 2000
+++ linux/net/unix/af_unix.c	Mon May  8 22:21:58 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.94 2000/04/25 04:13:35 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.95 2000/05/09 04:48:37 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -330,6 +330,7 @@
 static int unix_release_sock (unix_socket *sk, int embrion)
 {
 	struct dentry *dentry;
+	struct vfsmount *mnt;
 	unix_socket *skpair;
 	struct sk_buff *skb;
 	int state;
@@ -342,6 +343,8 @@
 	sk->shutdown = SHUTDOWN_MASK;
 	dentry = sk->protinfo.af_unix.dentry;
 	sk->protinfo.af_unix.dentry=NULL;
+	mnt = sk->protinfo.af_unix.mnt;
+	sk->protinfo.af_unix.mnt=NULL;
 	state = sk->state;
 	sk->state = TCP_CLOSE;
 	unix_state_wunlock(sk);
@@ -379,6 +382,7 @@
 	if (dentry) {
 		lock_kernel();
 		dput(dentry);
+		mntput(mnt);
 		unlock_kernel();
 	}
 
@@ -459,6 +463,7 @@
 	sk->max_ack_backlog = sysctl_unix_max_dgram_qlen;
 	sk->destruct = unix_sock_destructor;
 	sk->protinfo.af_unix.dentry=NULL;
+	sk->protinfo.af_unix.mnt=NULL;
 	sk->protinfo.af_unix.lock = RW_LOCK_UNLOCKED;
 	atomic_set(&sk->protinfo.af_unix.inflight, 0);
 	init_MUTEX(&sk->protinfo.af_unix.readsem);/* single task reading lock */
@@ -564,30 +569,30 @@
 				    int type, unsigned hash, int *error)
 {
 	unix_socket *u;
-	struct dentry *dentry;
-	int err;
+	struct nameidata nd;
+	int err = 0;
 	
 	if (sunname->sun_path[0]) {
 		/* Do not believe to VFS, grab kernel lock */
 		lock_kernel();
-		dentry = lookup_dentry(sunname->sun_path,LOOKUP_POSITIVE);
-		err = PTR_ERR(dentry);
-		if (IS_ERR(dentry)) {
+		if (path_init(sunname->sun_path, LOOKUP_POSITIVE, &nd))
+			err = path_walk(sunname->sun_path, &nd);
+		if (err) {
 			unlock_kernel();
 			goto fail;
 		}
-		err = permission(dentry->d_inode,MAY_WRITE);
+		err = permission(nd.dentry->d_inode,MAY_WRITE);
 		if (err)
 			goto put_fail;
 
 		err = -ECONNREFUSED;
-		if (!S_ISSOCK(dentry->d_inode->i_mode))
+		if (!S_ISSOCK(nd.dentry->d_inode->i_mode))
 			goto put_fail;
-		u=unix_find_socket_byinode(dentry->d_inode);
+		u=unix_find_socket_byinode(nd.dentry->d_inode);
 		if (!u)
 			goto put_fail;
 
-		dput(dentry);
+		path_release(&nd);
 		unlock_kernel();
 
 		err=-EPROTOTYPE;
@@ -604,7 +609,7 @@
 	return u;
 
 put_fail:
-	dput(dentry);
+	path_release(&nd);
 	unlock_kernel();
 fail:
 	*error=err;
@@ -617,6 +622,7 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
 	struct dentry * dentry = NULL;
+	struct nameidata nd;
 	int err;
 	unsigned hash;
 	struct unix_address *addr;
@@ -654,15 +660,29 @@
 
 	if (sunaddr->sun_path[0]) {
 		lock_kernel();
-		dentry = do_mknod(sunaddr->sun_path, S_IFSOCK|sock->inode->i_mode, 0);
-		if (IS_ERR(dentry)) {
-			err = PTR_ERR(dentry);
-			unlock_kernel();
-			if (err==-EEXIST)
-				err=-EADDRINUSE;
-			unix_release_addr(addr);
-			goto out_up;
-		}
+		err = 0;
+		if (path_init(sunaddr->sun_path, LOOKUP_PARENT, &nd))
+			err = path_walk(sunaddr->sun_path, &nd);
+		if (err)
+			goto out_mknod_parent;
+		err = -EEXIST;
+		if (nd.last_type != LAST_NORM)
+			goto out_mknod;
+		down(&nd.dentry->d_inode->i_sem);
+		dentry = lookup_hash(&nd.last, nd.dentry);
+		err = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
+			goto out_mknod_unlock;
+		err = -ENOENT;
+		if (nd.last.name[nd.last.len] && !dentry->d_inode)
+			goto out_mknod_dput;
+		err = vfs_mknod(nd.dentry->d_inode, dentry,
+			S_IFSOCK|sock->inode->i_mode, 0);
+		if (err)
+			goto out_mknod_dput;
+		up(&nd.dentry->d_inode->i_sem);
+		dput(nd.dentry);
+		nd.dentry = dentry;
 		unlock_kernel();
 
 		addr->hash = UNIX_HASH_SIZE;
@@ -681,7 +701,8 @@
 		list = &unix_socket_table[addr->hash];
 	} else {
 		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
-		sk->protinfo.af_unix.dentry = dentry;
+		sk->protinfo.af_unix.dentry = nd.dentry;
+		sk->protinfo.af_unix.mnt = nd.mnt;
 	}
 
 	err = 0;
@@ -695,6 +716,19 @@
 	up(&sk->protinfo.af_unix.readsem);
 out:
 	return err;
+
+out_mknod_dput:
+	dput(dentry);
+out_mknod_unlock:
+	up(&nd.dentry->d_inode->i_sem);
+out_mknod:
+	path_release(&nd);
+out_mknod_parent:
+	unlock_kernel();
+	if (err==-EEXIST)
+		err=-EADDRINUSE;
+	unix_release_addr(addr);
+	goto out_up;
 }
 
 static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
@@ -904,6 +938,7 @@
 		/* Damn, even dget is not SMP safe. It becomes ridiculous... */
 		lock_kernel();
 		newsk->protinfo.af_unix.dentry=dget(other->protinfo.af_unix.dentry);
+		newsk->protinfo.af_unix.mnt=mntget(other->protinfo.af_unix.mnt);
 		unlock_kernel();
 	}
 
diff -u --recursive --new-file v2.3.99-pre6/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.3.99-pre6/linux/net/x25/x25_timer.c	Mon Jul  7 08:20:00 1997
+++ linux/net/x25/x25_timer.c	Thu May  4 11:29:26 2000
@@ -111,8 +111,7 @@
 
 unsigned long x25_display_timer(struct sock *sk)
 {
-	if (sk->protinfo.x25->timer.prev == NULL &&
-	    sk->protinfo.x25->timer.next == NULL)
+	if (!timer_pending(&sk->protinfo.x25->timer))
 		return 0;
 
 	return sk->protinfo.x25->timer.expires - jiffies;
