diff -u --recursive --new-file v2.1.105/linux/CREDITS linux/CREDITS
--- v2.1.105/linux/CREDITS	Sun Jun  7 11:16:25 1998
+++ linux/CREDITS	Sat Jun 13 10:23:41 1998
@@ -1492,6 +1492,12 @@
 E: rubini@ipvvis.unipv.it
 D: the gpm mouse server and kernel support for it
 
+N: Paul Russell
+E: Paul.Russell@rustcorp.com.au
+W: http://www.adelaide.net.au/~rustcorp
+D: Ruggedly handsome.
+D: Developed Generic IP Firewalling Chains with Michael Neuling.
+
 N: Thomas Sailer
 E: sailer@ife.ee.ethz.ch
 E: HB9JNX@HB9W.CHE.EU (packet radio)
@@ -1786,6 +1792,11 @@
 S: Chudenicka 8
 S: 10200 Prague 10, Hostivar
 S: Czech Republic
+
+N: Andrew Veliath
+E: andrewtv@usa.net
+D: Turtle Beach MultiSound sound driver
+S: USA
 
 N: Dirk Verworner
 D: Co-author of german book ``Linux-Kernel-Programmierung''
diff -u --recursive --new-file v2.1.105/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.105/linux/Documentation/Changes	Sun Jun  7 11:16:25 1998
+++ linux/Documentation/Changes	Thu Jun 11 22:52:32 1998
@@ -33,7 +33,7 @@
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: May 12, 1998
+Last updated: May 31, 1998
 Current Author: Chris Ricker (kaboom@gatech.edu).
 
 Current Minimal Requirements
@@ -47,10 +47,10 @@
 - Gnu C 		 2.7.2.3                 ; gcc --version
 - Binutils		 2.8.1.0.23              ; ld -v
 - Linux C Library	 5.4.44                  ; ls -l /lib/libc.so.*
-- Dynamic Linker (ld.so) 1.9.5                   ; ldd --version
+- Dynamic Linker (ld.so) 1.9.9                   ; ldd --version or ldd -v
 - Linux C++ Library	 2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
 - Procps		 1.2.7                   ; ps --version
-- Procinfo               13                      ; procinfo -v
+- Procinfo               14                      ; procinfo -v
 - Mount                  2.7l                    ; mount --version
 - Net-tools              1.45                    ; hostname -V
 - Loadlin                1.6a
@@ -190,6 +190,17 @@
 of /proc/net/dev changed; as a result, an older ifconfig will
 incorrectly report errors.
 
+   As of 2.1.102, the firewalling code has been replaced with
+firewalling chains.  See
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html for
+more information.  Among other things, you'll now need to use ipchains
+instead of ipfwadm to configure your filters.
+
+   The IP firewalling code has been replaced: ipfwadm will no longer
+work.  You need to obtain `ipchains', available from
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+which includes an ipfwadm wrapper.
+
 Memory
 ======
 
@@ -209,8 +220,8 @@
 RPM
 ===
 
-   If you run Red Hat Linux or any other distribution that uses RPM, you
-need to upgrade RPM to version 2.2.7 or later.
+   If you run Red Hat Linux or any other distribution that uses RPM,
+you need to upgrade RPM to version 2.2.7 or later.
 
 DOSEMU
 ======
@@ -344,9 +355,9 @@
 Dynamic Linker
 ==============
 
-The 1.9.5 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.5.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.5.tar.gz
+The 1.9.9 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.9.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz
 
 Modules utilities
 =================
@@ -364,21 +375,21 @@
 Procinfo utilities
 ==================
 
-The 13 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-13.tar.gz
+The 14 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-14.tar.gz
 
 RPM utilities
 =============
 
 The 2.2.7 release for Intel:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
 The 2.2.7 release for Alpha:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
 The 2.2.7 release for SPARC:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.sparc.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-devel-2.2.7-1.sparc.rpm
 
 DOSEMU
 ======
@@ -455,6 +466,13 @@
 
 The 2.3.5 release:
 ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz
+
+IP Chains
+=========
+
+The 1.3.3 release:
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2
 
 Other Info
 ==========
diff -u --recursive --new-file v2.1.105/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.105/linux/Documentation/Configure.help	Tue Jun  9 11:57:28 1998
+++ linux/Documentation/Configure.help	Sat Jun 13 12:59:16 1998
@@ -154,14 +154,22 @@
 CONFIG_BLK_DEV_LOOP
   Saying Y here will allow you to mount a file as a file system. This
   is useful if you want to check an ISO9660 file system before burning
-  the CD, or want to use floppy images without first writing them to
-  floppy. This option also allows you to mount a filesystem with
-  encryption. To use these features, you need a recent version of
-  mount (available via FTP (user: anonymous) from
-  ftp://ftp.win.tue.nl/pub/linux/util/). Note that this loop device
-  has nothing to do with the loopback device used for network
-  connections from the machine to itself. Most users will answer N
-  here.
+  the CD, or if you want to use floppy images without first writing
+  them to floppy.
+
+  This option also allows you to mount a filesystem with encryption.
+  (Note that an alternative way to encrypt filesystems is provided by
+  the cfs package, which can be gotten via FTP (user: anonymous) from
+  ftp://ftp.replay.com/pub/crypto/disk).
+
+  To use the loop device, you need a recent version of mount
+  (available via FTP (user: anonymous) from
+  ftp://ftp.win.tue.nl/pub/linux/util/).
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  Most users will answer N here.
 
 Network Block Device support
 CONFIG_BLK_DEV_NBD
@@ -314,12 +322,21 @@
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
   and will allow you to use a SCSI device driver instead of a native
-  ATAPI driver. This is useful if you have an ATAPI device for which
-  no native driver has been written (for example, an ATAPI PD-CD or
-  CDR drive); you can then use this emulation together with an
-  appropriate SCSI device driver. If both this SCSI emulation and
-  native ATAPI support are compiled into the kernel, the native
-  support will be used.  Normally, say N.
+  ATAPI driver.
+
+  This is useful if you have an ATAPI device for which no native
+  driver has been written (for example, an ATAPI PD-CD or CDR drive);
+  you can then use this emulation together with an appropriate SCSI
+  device driver. In order to do this, say Y here and to "SCSI support"
+  and "SCSI generic support", below.
+
+  Note that this option does NOT allow you to attach SCSI devices to a
+  box that doesn't have a SCSI host adapter installed.
+
+  If both this SCSI emulation and native ATAPI support are compiled
+  into the kernel, the native support will be used.
+
+  If unsure, say N.
 
 CMD640 chipset bugfix/support
 CONFIG_BLK_DEV_CMD640
@@ -451,46 +468,51 @@
 CONFIG_BLK_DEV_NS87415
   This driver adds detection and support for the NS87415 chip
   (used in SPARC64, among others).
+
   Please read the comments at the top of drivers/block/ns87415.c.
 
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
   boot parameter.  It permits faster I/O speeds to be set.  See the
-  Documentation/ide.txt and qd6580.c files for more info.
+  files Documentation/ide.txt and qd6580.c for more info.
 
 UMC 8672 support
 CONFIG_BLK_DEV_UMC8672
   This driver is enabled at runtime using the "ide0=umc8672" kernel
   boot parameter.  It enables support for the secondary IDE interface
   of the UMC-8672, and permits faster I/O speeds to be set as well.
-  See the Documentation/ide.txt and umc8672.c files for more info.
+  See the files Documentation/ide.txt and umc8672.c for more info.
 
 ALI M14xx support
 CONFIG_BLK_DEV_ALI14XX
   This driver is enabled at runtime using the "ide0=ali14xx" kernel
   boot parameter.  It enables support for the secondary IDE interface
   of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-  I/O speeds to be set as well.  See the Documentation/ide.txt and
-  ali14xx.c files for more info.
+  I/O speeds to be set as well. See the files Documentation/ide.txt
+  and ali14xx.c for more info.
 
 Apple Macintosh builtin IDE interface support (EXPERIMENTAL)
 CONFIG_BLK_DEV_MAC_IDE
   This is the IDE driver for the builtin IDE interface on some Apple
   Macintosh models.  It supports both the Quadra/Performa/LC 630 and
   the PowerBook 190 IDE interface.
+
   Say Y if you have such a Macintosh model and want to use IDE devices
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
-  Very old 8 bit hard disk controllers used in the IBM XT computer. To
-  include a driver for these, say Y. If you want to compile the driver
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. The module will be called xd.o. It's
-  pretty unlikely that you have one of these: say N.
+  Very old 8 bit hard disk controllers used in the IBM XT computer
+  will be supported if you say Y here. 
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called xd.o. 
+
+  It's pretty unlikely that you have one of these: say N.
 
 Parallel port IDE device support
 CONFIG_PARIDE
@@ -560,12 +582,27 @@
   This option enables the high-level driver for ATAPI tape devices
   connected through a parallel port.  If you chose to build PARIDE
   support into your kernel, you may answer Y here to build in the
-  parallel port ATAPI disk driver, otherwise you should answer M
+  parallel port ATAPI tape driver, otherwise you should answer M
   to build it as a loadable module.  The module will be called pt.o.
   You must also have at least one parallel port protocol driver in
   your system.  Among the devices supported by this driver is the
   parallel port version of the HP 5GB drive.
 
+Parallel port generic ATAPI devices
+CONFIG_PARIDE_PG
+  This option enables a special high-level driver for generic ATAPI
+  devices connected through a parallel port. The driver allows user
+  programs, such as cdrecord, to send ATAPI commands directly to a
+  device. If you chose to build PARIDE support into your kernel, you 
+  may answer Y here to build in the parallel port generic ATAPI driver, 
+  otherwise you should answer M to build it as a loadable module.
+  The module will be called pg.o.  You must also have at least one 
+  parallel port protocol driver in your system.  This driver 
+  implements an API loosely related to the generic SCSI driver.  
+  See /usr/include/linux/pg.h for details, or visit 
+  http://www.torque.net/parport/cdr.html for more information and
+  the required patches to cdrecord.
+
 ATEN EH-100 protocol
 CONFIG_PARIDE_ATEN 
   This option enables support for the ATEN EH-100 parallel port IDE
@@ -633,10 +670,21 @@
   adapter that is used in some portable hard drives.  If you chose to 
   build PARIDE support into your kernel, you may answer Y here to 
   build in the protocol driver, otherwise you should answer M to 
-  build it as a loadable module.  The module will be called ktti.o.  
+  build it as a loadable module.  The module will be called fit2.o.
   You must also have a high-level driver for the type of device 
   that you want to support.
 
+FIT TD-3000 protocol
+CONFIG_PARIDE_FIT3
+  This option enables support for the TD-3000 parallel port IDE protocol
+  from Fidelity International Technology. This protocol is used in newer
+  models of their portable disk, CD-ROM and PD/CD devices.   If you chose
+  to build PARIDE support into your kernel, you may answer Y here to
+  build in the protocol driver, otherwise you should answer M to
+  build it as a loadable module.  The module will be called fit3.o.
+  You must also have a high-level driver for the type of device
+  that you want to support.
+
 FreeCom power protocol
 CONFIG_PARIDE_FRPW 
   This option enables support for the Freecom power parallel port IDE 
@@ -766,6 +814,24 @@
 
 IDE card support
 CONFIG_BLK_DEV_IDE_CARDS
+  On Acorn systems, say Y here if you wish to use an IDE interface
+  expansion card. If you do not or are unsure, say N.
+
+ICS IDE interface
+CONFIG_BLK_DEV_IDE_ICS
+  On Acorn systems, say Y here if you wish to use the ICS IDE
+  interface card. This is not required for ICS partition support. If
+  you are unsure, say.
+
+ADFS partition support
+CONFIG_BLK_DEV_PART
+  This allows Linux on Acorn systems to determine its partitions in
+  the 'non-ADFS' partition area of the hard disk - usually located
+  after the ADFS partition.  You are probably using this system, so
+  you should say Y here.
+
+IDE card support
+CONFIG_BLK_DEV_IDE_CARDS
   On Acorn systems, enable this if you wish to use an IDE interface
   expansion card. If you do not or are unsure, say N to this.
 
@@ -920,11 +986,10 @@
   is talking to the firewall box -- makes the local network completely
   invisible to the outside world and avoids the need to allocate
   globally valid IP host addresses for the machines on the local net)
-  and IP packet accounting (keeping track of what is using up all your
-  network bandwidth) and IP transparent proxying (makes the computers
-  on the local network think they're talking to a remote computer,
-  while in reality the traffic is redirected by your Linux firewall to
-  a local proxy server).
+  and IP transparent proxying (makes the computers on the local
+  network think they're talking to a remote computer, while in reality
+  the traffic is redirected by your Linux firewall to a local proxy
+  server).
   
   Make sure to say N to "Fast switching" below if you intend to say Y
   here.
@@ -948,6 +1013,11 @@
   about SYN cookies, check out
   ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
 
+  If you are SYN flooded, the source address reported by the kernel is
+  likely to have been forged by the attacker; it is only reported as
+  an aid in tracing the packets to their actual source and should not
+  be taken as absolute truth.
+
   If you say Y here, note that SYN cookies aren't enabled by default;
   you can enable them by saying Y to "/proc filesystem support" and
   "Sysctl support" below and executing the command
@@ -1060,18 +1130,15 @@
   serial ports on the same board to share a single IRQ.  To enable
   support for this in the serial driver, say Y here.
 
-Autodetect IRQ on standard ports (unsafe)
+Auto detect IRQ on standard ports (unsafe)
 CONFIG_SERIAL_DETECT_IRQ
-  Enable this option if you want the kernel to try to guess which IRQ
-  is configured during the boot sequence and you're too lazy to edit
-  the boot scripts to use the setserial command.  This option can be
-  unsafe and should not be enabled on most machines.  It is far
-  better to dynamically request autoconfiguration during the boot-time
-  scripts using the setserial command.  You can change the IRQ and/or 
-  request automatic IRQ configuration at any time by using the 
-  "setserial" program.  I wouldn't include this config option at all except
-  people keep bellyaching about it.  I guess they are really are too lazy 
-  to edit their boot scripts.  :-)   If unsure, say No.
+  Say Y here if you want the kernel to try to guess which IRQ
+  to use for your serial port. 
+
+  This is considered unsafe; it is far better to configure the IRQ in
+  a boot script using the setserial command.
+
+  If unsure, say N.
 
 Support special multiport boards
 CONFIG_SERIAL_MULTIPORT
@@ -1099,9 +1166,10 @@
   bus system, i.e. the way the CPU talks to the other stuff inside
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
   VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available
-  via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO,
-  contains valuable information about which PCI hardware does work
-  under Linux and which doesn't.
+  via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
 
   If some of your PCI devices don't work and you get a warning during
   boot time ("man dmesg"), please follow the instructions at the top
@@ -1131,8 +1199,9 @@
 PCI quirks
 CONFIG_PCI_QUIRKS
   If you have a broken BIOS, it may fail to set up the PCI bus in a
-  correct or optimal fashion. If your BIOS is fine you can say N here
-  for a very slightly smaller kernel. If unsure, say Y.
+  correct or optimal fashion. Saying Y here will correct that problem.
+  If your BIOS is fine you can say N here for a very slightly smaller
+  kernel. If unsure, say Y.
 
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
@@ -1588,10 +1657,10 @@
 CONFIG_IP_ROUTE_TOS
   The header of every IP packet carries a TOS (Type of Service) value
   with which the packet requests a certain treatment, e.g. low latency
-  (for interactive traffic), high throughput, or high
-  reliability. Normally, these values are ignored, but if you say Y
-  here, you will be able to specify different routes for packets with
-  different TOS values.
+  (for interactive traffic), high throughput, or high reliability.
+  Normally, these values are ignored, but if you say Y here, you will
+  be able to specify different routes for packets with different TOS
+  values.
 
 IP: verbose route monitoring
 CONFIG_IP_ROUTE_VERBOSE
@@ -1641,22 +1710,19 @@
   More powerful than the old IP firewalling but also provides similar
   structure to original firewalling for experienced users.  IP
   accounting and packet logging are automatically included with firewall
-  chains, so you don't need them them if you say Y here.  See
+  chains.  See
   http://www.adelaide.net.au/~rustcorp for new ipfwadm (called ipchains).
   If in doubt, say N here.
 
 IP: firewall packet netlink device
 CONFIG_IP_FIREWALL_NETLINK
-  If you say Y here and then packets hit your Linux firewall and are
-  blocked, the first 128 bytes of each such packet are passed on to
-  optional user space monitoring software that can then look for
-  attacks and take actions such as paging the administrator of the
-  site. To use this, you need to create a character special file under
-  /dev with major number 36 and minor number 3 using mknod ("man
-  mknod"), and you need (to write) a program that reads from that
-  device and takes appropriate action.
-  With the current generic firewalling chains you can specify which
-  packets go to this device, as well as how many bytes.
+  If you say Y here, then packets which hit your Linux firewall can
+  be copied to optional user space monitoring software that can then
+  respond accordingly: see the ipchains source distributions for an
+  example if this.  To use this, you need to create a character
+  special file under /dev with major number 36 and minor number 3
+  using mknod ("man mknod"), and you need (to write) a program that
+  reads from that device and takes appropriate action.
 
 IP: kernel level autoconfiguration
 CONFIG_IP_PNP
@@ -1728,12 +1794,6 @@
   Network), but can be distributed all over the Internet. If you want
   to do that, say Y here and to "IP: multicast routing" below.
 
-IP: firewall packet logging
-CONFIG_IP_FIREWALL_VERBOSE
-  This gives you information about what your firewall did with
-  packets it received. The information is handled by the klogd daemon
-  which is responsible for kernel messages ("man klogd").
-
 IP: transparent proxying
 CONFIG_IP_TRANSPARENT_PROXY
   This enables your Linux firewall to transparently redirect any
@@ -1775,7 +1835,9 @@
 
   Details on how to set things up are contained in the IP Masquerade
   mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini.
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
+  information on the WWW at
+  http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. 
 
   If you say Y here, you should also say Y to "IP: always defragment",
   below. If you say Y here, then the modules ip_masq_ftp.o (for ftp
@@ -1814,13 +1876,23 @@
 
 IP: ipportfw masquerade support
 CONFIG_IP_MASQUERADE_IPPORTFW
-  ipportfw is an addition to IP Masquerading written by Steven Clarke
-  to allow some forwarding of packets from outside to inside a
-  firewall on given ports. Information and source for ipportfw is
-  available from
+  Port Forwarding is an addition to IP Masquerading written by Steven
+  Clarke to allow some forwarding of packets from outside to inside a
+  firewall on given ports. This could be useful if, for example, you
+  want to run a web server behind the firewall or masquerading host
+  and this web server should be visible to the outside world. An
+  external client connects to port 80 of the firewall, the firewall
+  forwards requests to this port to the web server, the web server
+  handles the request and the results are sent through the firewall to
+  the original client. The client thinks that the firewall machine
+  itself is running the web server.
+
+  Information about it is available from
   http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to
   browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape).
+  that has a program like lynx or netscape). You will need the user
+  space program ipportfw which can be downloaded from
+  ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/
 
   The portfw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
@@ -2005,18 +2077,20 @@
 Unix domain sockets
 CONFIG_UNIX
   This includes Unix domain sockets, the standard Unix mechanism for
-  establishing and accessing network connections. Unless you are
-  working on an embedded system or something, you definitely want to
-  say Y here.
+  establishing and accessing network connections. Many commonly used
+  programs such as the X Window system and syslog use these sockets
+  even if your machine is not connected to any network. Unless you are
+  working on an embedded system or something similar, you therefore
+  definitely want to say Y here.
 
   The socket support is also available as a module ( = code which can
   be inserted in and removed from the running kernel whenever you
   want). The module will be called unix.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt. If you
   try building this as a module and you are running kerneld, be sure
-  to add 'alias net-pf-1 unix' to your /etc/conf.module file. If
-  unsure, say Y.  (NOTE: X Windows and syslog probably won't work
-  if you say N to this or fail to configure it correctly)
+  to add 'alias net-pf-1 unix' to your /etc/conf.module file. 
+
+  If unsure, say Y.
 
 The IPv6 protocol
 CONFIG_IPV6
@@ -2056,26 +2130,45 @@
   some problems caused by the presence of two link-local addresses on
   an interface.
 
+IPv6: routing messages via old netlink
+CONFIG_IPV6_NETLINK
+  You can say Y here to receive routing messages from the IPv6 code
+  through the old netlink interface. However, a better option is to
+  say Y to "Kernel/User network link driver" and to "Routing
+  messages" instead.
+  
 IPX networking
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX, commonly
   used for local networks of Windows machines. You need it if you want
   to access Novell NetWare file or print servers using the Linux
   Novell client ncpfs (available via FTP (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the
-  Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former,
-  you'll also have to say Y to "NCP filesystem support", below. To
-  turn your Linux box into a fully featured NetWare file server and
+  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
+  the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
+  former, you'll also have to say Y to "NCP filesystem support",
+  below.
+
+  IPX is similar in scope to IP, while SPX, which runs on top of IPX,
+  is similar to TCP. There is also experimental support for SPX in
+  Linux (see "SPX networking", below).
+
+  To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
-  sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from
-  ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the
-  IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
-  would enlarge your kernel by about 5 kB. This driver is also
-  available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). The module will be
-  called ipx.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt.  Unless you want to integrate
+  ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from
+  ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the
+  IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape). 
+
+  The IPX driver would enlarge your kernel by about 5 kB. This driver
+  is also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called ipx.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. Unless you want to integrate
   your Linux box with a local Novell network, say N.
 
 IPX: Full internal IPX network
@@ -2083,11 +2176,12 @@
   Every IPX network has an address that identifies it. Sometimes it is
   useful to give an IPX "network" address to your Linux box as well
   (for example if your box is acting as a fileserver for different IPX
-  networks: it will then be accessible form everywhere using the same
+  networks: it will then be accessible from everywhere using the same
   address).  The way this is done is to create a virtual internal
   "network" inside your box and to assign an IPX address to this
   network. Say Y here if you want to do this; read the IPX-HOWTO at
-  sunsite.unc.edu:/pub/Linux/docs/howto for details.  
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.  
+
   The full internal IPX network enables you to allocate sockets on
   different virtual nodes of the internal network. This is done by
   evaluating the field sipx_node of the socket address given to the
@@ -2099,14 +2193,28 @@
   'special' sockets to sockets listening on the primary network is
   disabled. This might break existing applications, especially RIP/SAP
   daemons. A RIP/SAP daemon that works well with the full internal net
-  can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.  If you don't
+  can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs.  If you don't
   know what you are doing, say N.
 
 IPX: SPX networking (EXPERIMENTAL)
 CONFIG_SPX
-  The (SPP-derived) Sequenced Packet eXchange (SPX) protocol. Novell's
-  networking protocol which monitors transmissions to guarantee
-  successful delivery. It is safe to say Y/M here.
+  The Sequenced Packet eXchange protocol is a transport layer protocol
+  built on top of IPX. It is used in Novell NetWare systems for
+  client-server applications and is similar to TCP (which runs on top
+  of IP).
+
+  Note that Novell NetWare file sharing does not use SPX; it uses a
+  protocol called NCP, for which separate Linux support is available
+  ("NCP filesystem support" below for the client side, and the user
+  space programs lwared or mars_nwe for the server side).
+
+  Say Y here if you have use for SPX; read the IPX-HOWTO at
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called af_spx.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Appletalk DDP
 CONFIG_ATALK
@@ -2115,36 +2223,42 @@
   want to join the conversation, say Y. You will need to use the
   netatalk package so that your Linux box can act as a print and file
   server for Macs as well as access Appletalk printers. Check out
-  http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
-  WWW for details (to browse the WWW, you need to have access to a
-  machine on the Internet that has a program like lynx or
-  netscape). EtherTalk is the name used for Appletalk over Ethernet
-  and the cheaper and slower LocalTalk is appletalk over a proprietary
-  apple network using serial links. Ethertalk and Localtalk are fully 
-  supported by Linux. The NET-2-HOWTO, available via FTP (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
-  as well. This driver is also available as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). The module is called appletalk.o. If you want to compile
-  it as a module, say M here and read Documentation/modules.txt. I
-  hear that the GNU boycott of Apple is over, so even politically
-  correct people are allowed to say Y here.
+  http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
+  for details (to browse the WWW, you need to have access to a machine
+  on the Internet that has a program like lynx or netscape). EtherTalk
+  is the name used for Appletalk over Ethernet and the cheaper and
+  slower LocalTalk is appletalk over a proprietary apple network using
+  serial links. Ethertalk and Localtalk are fully supported by Linux.
+  The NET-2-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable
+  information as well.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called appletalk.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. I hear that
+  the GNU boycott of Apple is over, so even politically correct people
+  are allowed to say Y here.
 
 Appletalk-IP driver support
 CONFIG_IPDDP
   This allows IP networking for users who only have Appletalk
   networking available.  This feature is experimental. With this
   driver, you can either encapsulate IP inside Appletalk (e.g. if your
-  Linux box is stuck on an appletalk only network) or decapsulate
-  (e.g. if you want your Linux box to act as a Internet gateway for a
+  Linux box is stuck on an Appletalk only network) or decapsulate
+  (e.g. if you want your Linux box to act as an Internet gateway for a
   zoo of appletalk connected Macs). You decide which one of the two
   you want in the following two questions; you can say Y to only one
   of them. Please see Documentation/networking/ipddp.txt for more
-  information.  This driver is also available as a module ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). The module is called ipddp.o. If you want to
-  compile it as a module, say M here and read
-  Documentation/modules.txt.
+  information.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called ipddp.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
 
 IP to Appletalk-IP Encapsulation support
 CONFIG_IPDDP_ENCAP
@@ -2406,6 +2520,21 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called baycom_par.o.
 
+BAYCOM epp driver for AX.25
+CONFIG_BAYCOM_EPP
+  This is a driver for Baycom style simple amateur radio modems that
+  connect to a parallel interface. The driver supports the epp
+  designs. To configure the driver, use the sethdlc utility available
+  in the standard ax25 utilities package. For information on the
+  modems, see http://www.baycom.de (to browse the WWW, you need to
+  have access to a machine on the Internet that has a program like
+  lynx or netscape) and Documentation/networking/baycom.txt.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called baycom_par.o.
+
 BAYCOM ser12 full duplex driver for AX.25
 CONFIG_BAYCOM_SER_FDX
   This is one of two drivers for Baycom style simple amateur radio
@@ -2915,7 +3044,7 @@
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
   This is support for BusLogic MultiMaster and FlashPoint SCSI Host
-  Adapters.  Consult the SCSI-HOWTO, available via anonymous ftp from
+  Adapters.  Consult the SCSI-HOWTO, available via anonymous FTP from
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, and the files
   README.BusLogic and README.FlashPoint in drivers/scsi for more
   information.  If this driver does not work correctly without
@@ -3197,7 +3326,7 @@
   interface.
 
   If all the boards of your system are genuine SYMBIOS boards or use
-  BIOS and drivers from SYMBIOS, you would want to enable this option.
+  BIOS and drivers from SYMBIOS, you would want to say Y here.
   The driver behaves correctly on my system with this option enabled.
   (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
   0x12).  This option must be set to N if your system has at least one
@@ -3205,10 +3334,10 @@
   DC-390/U/W/F). 
 
   However, if all your non Symbios compatible boards have NVRAM,
-  setting option "detect and read serial NVRAMs"
+  saying Y to "detect and read serial NVRAMs"
   (CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT) above allows the driver to
-  distinguish Symbios compatible boards from other ones.  So, you can
-  answer Y if all non Symbios compatible boards have NVRAM.
+  distinguish Symbios compatible boards from other ones; you can then
+  also answer Y here.
 
   If unsure, say N.
 
@@ -3428,7 +3557,7 @@
   This driver supports all the EATA/DMA-compliant SCSI host adapters
   and does not need any BIOS32 service.  DPT ISA and all EISA i/o
   addresses are probed looking for the "EATA" signature. If you said Y
-  to "PCI bios support", the addresses of all the PCI SCSI controllers
+  to "PCI BIOS support", the addresses of all the PCI SCSI controllers
   reported by BIOS32 are probed as well.  You want to read
   the start of drivers/scsi/eata.c and the SCSI-HOWTO, available via
   FTP (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.  
@@ -3560,6 +3689,59 @@
 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
   Say Y here to enable tagged queuing support on the Acorn SCSI card.
 
+  This is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Some SCSI devices don't
+  implement this properly, so the safe answer is N.
+
+Acorn SCSI Synchronous transfers support
+CONFIG_SCSI_ACORNSCSI_SYNC
+  Say Y here to enable synchronous transfer negotiation with all targets
+  on the Acorn SCSI card.
+
+  In general, this improves performance; however some SCSI devices
+  don't implement it properly, so the safe answer is N.
+
+Oak SCSI support
+CONFIG_SCSI_OAK1
+  This enables support for the Oak SCSI card.  If you have an Acorn system
+  with one of these, say Y.  If unsure, say N.
+
+Cumana SCSI I support
+CONFIG_SCSI_CUMANA_1
+  This enables support for the Cumana SCSI I card.  If you have an Acorn
+  system with one of these, say Y.  If unsure, say N.
+
+Cumana SCSI II support
+CONFIG_SCSI_CUMANA_2
+  This enables support for the Cumana SCSI II card.  If you have an Acorn
+  system with one of these, say Y.  If unsure, say N.
+
+EcoSCSI support
+CONFIG_SCSI_ECOSCSI
+  This enables support for the EcoSCSI card - a small card that sits in
+  the Econet socket.  If you have an Acorn system with one of these,
+  say Y.  If unsure, say N.
+
+EESOX SCSI support
+CONFIG_SCSI_EESOXSCSI
+  This enables support for the EESOX SCSI card.  If you have an Acorn
+  system with one of these, say Y, otherwise say N.
+
+Powertec SCSI support
+CONFIG_SCSI_POWERTECSCSI
+  This enables support for the Powertec SCSI card on Acorn systems.  If
+  you have one of these, say Y.  If unsure, say N.  
+
+AcornSCSI support
+CONFIG_SCSI_ACORNSCSI_3
+  This enables support for the Acorn SCSI card (aka30).  If you have an
+  Acorn system with one of these, say Y.  If unsure, say N.
+
+Acorn SCSI tagged queue support
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+  Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
 Acorn SCSI Synchronous transfers support
 CONFIG_SCSI_ACORNSCSI_SYNC
   Say Y here to enable synchronous transfer negociation with all targets
@@ -3788,18 +3970,23 @@
 
 AT&T WaveLAN & DEC RoamAbout DS support
 CONFIG_WAVELAN
-  The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS) is
+  The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
   a Radio LAN (wireless Ethernet-like Local Area Network) using the
   radio frequencies 900 MHz and 2.4 GHz.
   
   This driver support the ISA version of the Wavelan card. A separate
-  driver for the pcmcia hardware is available in David Hinds's pcmcia
-  package. If you want to use an ISA Wavelan card under Linux, say Y
-  and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  driver for the pcmcia hardware is available in David Hinds's
+  pcmcia-cs package (see the file Documentation/Changes for location).
+
+  If you want to use an ISA Wavelan card under Linux, say Y and read
+  the Ethernet-HOWTO, available via FTP (user: anonymous) in
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Some more specific
-  information is contained in Documentation/networking/wavelan.txt.
+  information is contained in Documentation/networking/wavelan.txt and
+  in the source code drivers/net/wavelan.p.h.
+
   You will also need the wireless tools package available from
   ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
+  Please read the man pages contained therein.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3817,10 +4004,21 @@
   something at ftp://ftp.lmh.ox.ac.uk/users/weejock/linux/, but I haven't
   written anything too useful yet...)
 
-AIMSlab RadioTrack card
+AIMSlab RadioTrack (aka RadioReveal) support
 CONFIG_RADIO_RTRACK
-  Choose Y here if you have one of these, and then fill in the port
-  address below.
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+  
+  In order to control your radio card under the X window system, you
+  may use the program X-Tuner, available on the WWW at
+  http://gatekeeper.dec.com/pub/X11/R6-contrib/applications/; to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-aimslab.o.
 
 RadioTrack i/o port
 CONFIG_RADIO_RTRACK_PORT
@@ -3829,8 +4027,13 @@
 
 Aztech/Packard Bell Radio
 CONFIG_RADIO_AZTECH
-  Choose Y here if you have one of these, and then fill in the port
-  address below.
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+  
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-aztech.o.
 
 Aztech/Packard Bell radio card i/o port
 CONFIG_RADIO_AZTECH_PORT
@@ -3838,6 +4041,20 @@
   haven't changed the setting of jumper JP3 on the card.  Removing the
   jumper sets the card to 0x358.
 
+SF16FMI Radio
+CONFIG_RADIO_SF16FMI
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-sf16fmi.o
+
+SF16FMI I/O port (0x284 or 0x384)
+CONFIG_RADIO_SF16FMI_PORT
+  Enter the I/O port of your SF16FMI radio card.
+
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -4005,6 +4222,35 @@
   The module will be called sdla.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Acorn Econet/AUN protocols (EXPERIMENTAL)
+CONFIG_ECONET
+  Econet is a fairly old and slow networking protocol mainly used by
+  Acorn computers to access file and print servers. It uses native
+  Econet network cards. AUN is an implementation of the higher level
+  parts of Econet that runs over ordinary Ethernet connections, on
+  top of the UDP packet protocol, which in turn runs on top of the
+  Internet protocol IP.
+
+  If you say Y here, you can choose with the next two options whether
+  to send Econet/AUN traffic over a UDP Ethernet connection or over
+  a native Econet network card.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called econet.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+AUN over UDP
+CONFIG_ECONET_AUNUDP
+  Say Y here if you want to send Econet/AUN traffic over a a UDP
+  connection (UDP is a packet based protocol that runs on top of the
+  Internet protocol IP) using an ordinary Ethernet network card.
+
+Native Econet
+CONFIG_ECONET_NATIVE
+  Say Y here if you have a native Econet network card installed in
+  your computer.
+
 WAN Router
 CONFIG_WAN_ROUTER
   Wide Area Networks (WANs), such as X.25, frame relay and leased
@@ -4074,14 +4320,18 @@
   called packet schedulers. You can attach different schedulers to
   different network devices. If you want to stick to the default
   scheduling algorithm, say N here. If you want to experiment with a
-  couple of different algorithms, say Y. 
+  couple of different algorithms, say Y. Currently, this is only
+  recommended for experts.
 
   To administer these schedulers, you'll need the user-level utilities
   from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/
 
-  The available schedulers are
-  listed in the following questions; you can say Y to as many as you
-  like.  If unsure, say N now.
+  If you say Y here and to "/proc filesystem" below, you will be able
+  to read status information about priority schedulers from
+  the file /proc/net/psched.
+  
+  The available schedulers are listed in the following questions; you
+  can say Y to as many as you like. If unsure, say N now.
 
 CBQ packet scheduler
 CONFIG_NET_SCH_CBQ
@@ -4090,8 +4340,8 @@
   algorithm classifies the waiting packets into a tree-like hierarchy
   of classes; the leaves of this tree are in turn scheduled by
   separate algorithms (called "disciplines" in this context) which you
-  can choose below from among the "auxiliary disciplines".  See the top
-  of net/sched/sch_cbq.c for references about the CBQ algorithm.
+  can choose below from among the various queueing algorithms. See the
+  top of net/sched/sch_cbq.c for references about the CBQ algorithm.
 
   This code is also available as a module called sch_cbq.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4113,7 +4363,18 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-RED queueing discipline
+The simplest PRIO pseudo scheduler
+CONFIG_NET_SCH_PRIO
+  Say Y here if you want to use an n-band priority queue packet
+  "scheduler" for some of your network devices or as a leaf discipline
+  for the CBQ scheduling algorithm. 
+
+  This code is also available as a module called sch_prio.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+RED queue
 CONFIG_NET_SCH_RED
   Say Y here if you want to use the Random Early Detection (RED)
   packet scheduling algorithm for some of your network devices (see
@@ -4125,7 +4386,7 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-SFQ queueing discipline
+SFQ queue
 CONFIG_NET_SCH_SFQ
   Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
   packet scheduling algorithm for some of your network devices or as a
@@ -4138,7 +4399,21 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-auxiliary TBF queue
+TEQL queue
+CONFIG_NET_SCH_TEQL
+  Say Y here if you want to use the True Link Equalizer (TLE) packet
+  scheduling algorithm for some of your network devices or as a leaf
+  discipline for the CBQ scheduling algorithm. This queueing
+  discipline allows the combination of several physical devices into
+  one virtual device. (see the top of net/sched/sch_teql.c for
+  details).
+
+  This code is also available as a module called sch_teql.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+TBF queue
 CONFIG_NET_SCH_TBF
   Say Y here if you want to use the Simple Token Bucket Filter (TBF)
   packet scheduling algorithm for some of your network devices or as a
@@ -4150,27 +4425,49 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-auxiliary FIFO queue
-CONFIG_NET_SCH_PFIFO
-  Say Y here if you want to use a simple FIFO (first in - first out)
-  packet "scheduler" for some of your network devices or as a leaf
-  discipline for the CBQ scheduling algorithm. 
-
-  This code is also available as a module called sch_fifo.o ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+QoS support
+CONFIG_NET_QOS
+  Say Y here if you want to include Quality Of Service scheduling
+  features, which means that you will be able to request certain
+  rate-of-flow limits for your net devices.
 
-auxiliary PRIO queue
-CONFIG_NET_SCH_PRIO
-  Say Y here if you want to use an n-band priority queue packet
-  "scheduler" for some of your network devices or as a leaf discipline
-  for the CBQ scheduling algorithm. 
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause this configure script to skip all
+  the questions about QoS support.
 
-  This code is also available as a module called sch_prio.o ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+Rate estimator
+CONFIG_NET_ESTIMATOR
+  In order for Quality of Service scheduling to work, the current
+  rate-of-flow for a network device has to be estimated; if you say Y
+  here, the kernel will do just that.
+
+Packet classifier API
+CONFIG_NET_CLS
+  The CBQ scheduling algorithm requires that network packets which are
+  scheduled to be sent out over a network device be classified in some
+  way. If you say Y here, you will get a choice of several different
+  packet classifiers with the following questions. 
+#
+# Routing tables based classifier
+# CONFIG_NET_CLS_ROUTE
+#
+# Firewall based classifier
+# CONFIG_NET_CLS_FW
+#
+# U32 classifier
+# CONFIG_NET_CLS_U32
+#
+# Special RSVP classifier
+# CONFIG_NET_CLS_RSVP
+#
+# Special RSVP classifier for IPv6
+# CONFIG_NET_CLS_RSVP6
+#
+# Ingres traffic policing
+# CONFIG_NET_CLS_POLICE
+###
+### Some expert please fill these in
+###
 
 Network code profiler
 CONFIG_NET_PROFILE
@@ -4245,9 +4542,9 @@
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
-  type of Local Area Networks (LANs) in universities or
-  companies. 10-base-2 or Thinnet (10 Mbps over coaxial cable, linking
-  computers in a chain), 10-base-T (10 Mbps over twisted pair
+  type of Local Area Networks (LANs) in universities or companies.
+  10-base-2 or Thinnet (10 Mbps over coaxial cable, linking computers
+  in a chain), 10-base-T or TwistedPair (10 Mbps over twisted pair
   telephone cable, linking computers to a central hub) and
   100-base-<whatever> (100 Mbps) are common types of Ethernet. 
 
@@ -4359,6 +4656,18 @@
   it as a module, say M here and read Documentation/modules.txt as
   well as Documentation/networking/net-modules.txt.
 
+PCI NE2000 support
+CONFIG_NE2K_PCI
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ne2k-pci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
 Racal-Interlan (Micom) NI cards
 CONFIG_NET_VENDOR_RACAL
   If you have a network (Ethernet) card belonging to this class, such
@@ -4408,6 +4717,32 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+RealTek 8129/8139 (not 8019/8029!) support
+CONFIG_RTL8139
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8129 and RTL8139 chips. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called rtl8139.o.
+
+Packet Engines Yellowfin Gigabit-NIC support
+CONFIG_YELLOWFIN
+  Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+  adapter. This adapter is used by the Beowulf Linux cluster project.
+  See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for
+  more information about this driver in particular and Beowulf in
+  general (to browse the WWW, you need to have access to a machine on
+  the Internet that has a program like lynx or netscape).
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called yellowfin.o.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -4509,10 +4844,10 @@
 
 3c590 series (592/595/597) "Vortex" support
 CONFIG_VORTEX
-  If you have a 3Com "Vortex" or "Boomerang" series network (Ethernet)
-  card (Fast EtherLink 3c590/3c592/3c595/3c597 or the EtherLink XL
-  3c900 or 3c905), say Y and read the Ethernet-HOWTO, available via
-  FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
+  or "Boomerang" series (EtherLink XL 3c900 or 3c905) network
+  (Ethernet) card, say Y and read the Ethernet-HOWTO, available via FTP
+  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
   More specific information is in Documentation/networking/vortex.txt
   and in the comments at the beginning of drivers/net/3c59x.c.
 
@@ -4820,6 +5155,12 @@
   Y here and read the Ethernet-HOWTO, available via FTP (user:
   anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pcnet32.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
@@ -4941,6 +5282,20 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+PCI NE2000 Support
+CONFIG_NE2K_PCI
+  This driver is for NE2000 compatible PCI cards.  It will not work
+  with ISA NE2000 cards.  If you have a network (Ethernet) card of
+  this type, say Y and read the Ethernet-HOWTO, available via FTP
+  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ne2k-pci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
+
 TI ThunderLAN support (EXPERIMENTAL)
 CONFIG_TLAN
   If you have a TLAN based network card which is supported by this
@@ -4987,7 +5342,7 @@
 
   If you want to plug a network card into the PCMCIA slot of your
   laptop instead (PCMCIA is the standard for credit card size
-  extension cards used by all modern laptops), look on the ftp site
+  extension cards used by all modern laptops), look on the FTP site
   (user: anonymous) ftp://cb-iris.stanford.edu/pub/pcmcia and say N
   here.
 
@@ -5115,6 +5470,26 @@
   If you wish to compile a kernel for the EBSA-110, then you should
   always answer Y to this.
 
+Acorn Ether1 card
+CONFIG_ARM_ETHER1
+  If you have an Acorn system with one of these (AKA25) network cards,
+  you should say Y to this option if you wish to use it with Linux.
+
+Acorn/ANT Ether3 card
+CONFIG_ARM_ETHER3
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
+I Cubed EtherH card
+CONFIG_ARM_ETHERH
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
+EBSA-110 ethernet interface
+CONFIG_AM79C961A
+  If you wish to compile a kernel for the EBSA-110, then you should
+  always answer Y to this.
+
 Support CDROM drives that are not SCSI or IDE/ATAPI
 CONFIG_CD_NO_IDESCSI
   If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y
@@ -5577,28 +5952,35 @@
 Second extended fs support
 CONFIG_EXT2_FS
   This is the de facto standard Linux filesystem (= method to organize
-  files on a storage device) for hard disks. You want to say Y, unless
-  you intend to use Linux exclusively from inside a DOS partition
-  using the umsdos filesystem. The advantage of the latter is that you
-  can get away without repartitioning your hard drive (which often
-  implies backing everything up and restoring afterwards); the
-  disadvantage is that Linux becomes susceptible to DOS viruses and
-  that umsdos is somewhat slower than ext2fs. Even if you want to run
-  Linux in this fashion, it might be a good idea to have ext2fs
-  around: it enables you to read more floppy disks and facilitates the
-  transition to a *real* Linux partition later. Another (rare) case
-  which doesn't require ext2fs is a diskless Linux box which mounts
-  all files over the network using NFS (in this case it's sufficient
-  to say Y to "NFS filesystem support" below). Saying Y here will
-  enlarge your kernel by about 41 kB.
+  files on a storage device) for hard disks. 
+
+  You want to say Y here, unless you intend to use Linux exclusively
+  from inside a DOS partition using the umsdos filesystem. The
+  advantage of the latter is that you can get away without
+  repartitioning your hard drive (which often implies backing
+  everything up and restoring afterwards); the disadvantage is that
+  Linux becomes susceptible to DOS viruses and that umsdos is somewhat
+  slower than ext2fs. Even if you want to run Linux in this fashion,
+  it might be a good idea to have ext2fs around: it enables you to
+  read more floppy disks and facilitates the transition to a *real*
+  Linux partition later. Another (rare) case which doesn't require
+  ext2fs is a diskless Linux box which mounts all files over the
+  network using NFS (in this case it's sufficient to say Y to "NFS
+  filesystem support" below). Saying Y here will enlarge your kernel
+  by about 41 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
   anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini,
   gives information about how to retrieve deleted files on ext2fs
   filesystems.
 
-  To change the behavior of ext2fs filesystems, you can use the
-  tune2fs utility ("man tune2fs"). 
+  To change the behavior of ext2 filesystems, you can use the tune2fs
+  utility ("man tune2fs"). To modify attributes of files and
+  directories on ext2 filesystems, use chattr ("man chattr").
+  
+  Ext2fs partitions can be read from within DOS using the ext2tool
+  package available via FTP (user: anonymous) from
+  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2.
 
   If you want to compile this filesystem as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -5930,7 +6312,7 @@
   The automounter is a tool to automatically mount remote filesystems
   on demand.  This implementation is partially kernel-based to reduce
   overhead in the already-mounted case; this is unlike the BSD
-  automounter (amd), which is only in user space.  
+  automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
   ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say Y to
@@ -6005,13 +6387,15 @@
 
 ADFS filesystem support (read only) (EXPERIMENTAL)
 CONFIG_ADFS_FS
-  The Acorn Disc Filing System is the standard filesystem of the RiscOS
-  operating system which runs on Acorn's ARM based Risc PC systems and
-  the Acorn Archimedes range of machines. These should be the first
-  partition (ie, /dev/[hs]d?1) on each of your drives. If you say Y
+  The Acorn Disc Filing System is the standard filesystem of the
+  RiscOS operating system which runs on Acorn's ARM based Risc PC
+  systems and the Acorn Archimedes range of machines. If you say Y
   here, Linux will be able to read from ADFS partitions on hard drives
   and from ADFS-formatted floppy discs.
 
+  The ADFS partition should be the first partition (i.e.,
+  /dev/[hs]d?1) on each of your drives.
+
   This code is also available as a module called adfs.o ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
@@ -6023,7 +6407,7 @@
 CONFIG_DEVPTS_FS
   If you say Y here, you'll get a virtual filesystem which can be
   mounted on /dev/pts with "mount -t devpts". This, together with the
-  pseudo terminal master multiplexer /dev/ptmx is used for pseudo
+  pseudo terminal master multiplexer /dev/ptmx, is used for pseudo
   terminal support as described in the Open Group's Unix98 standard:
   in order to acquire a pseudo terminal, a process opens /dev/ptmx;
   the number of the pseudo terminal is then made available to the
@@ -6499,6 +6883,13 @@
   or change their color depending on the virtual console you're on.
   See Documentation/VGA-softcursor.txt for more information.
 
+Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
+CONFIG_ADFS_FS
+  The Advanced Disk File System is the filesystem used on floppy and
+  hard disks by Acorn Systems.  Currently in development, as a read-
+  only driver for hard disks.  These should be the first partition
+  (eg. /dev/[sh]d?1) on each of your drives.  If unsure, say N.
+
 Standard/generic serial support
 CONFIG_SERIAL
   This selects whether you want to include the driver for the standard
@@ -6516,8 +6907,12 @@
   be lost when kerneld automatically unloads the driver. This
   limitation may be lifted in the future.] 
 
-  BTW: If you have a mouseman serial mouse which is not recognized by
+  BTW1: If you have a mouseman serial mouse which is not recognized by
   the X window system, try running gpm first. 
+  
+  BTW2: If you intend to connect a so-called Winmodem to your
+  machine's serial port, forget it. These modems require proprietary
+  drivers which are only available under Windows.
 
   Most people will say Y or M here, so that they can use serial mice,
   modems and similar devices connecting to the standard serial ports.
@@ -6586,7 +6981,7 @@
 
 Specialix IO8+ card support
 CONFIG_SPECIALIX
-  This is a driver for the Specialix IO8+ multiport card, that give 
+  This is a driver for the Specialix IO8+ multiport card which gives
   you many serial ports. You would need something like this to 
   connect more than two modems to your Linux box, for instance in
   order to become a BBS. 
@@ -6598,9 +6993,9 @@
 
 Specialix DTR/RTS pin is RTS
 CONFIG_SPECIALIX_RTSCTS
-  The Specialix card can only support either RTS or DTR. When you say
+  The Specialix card can only support either RTS or DTR. If you say
   N here, the driver will use the pin as "DTR" when the tty is in
-  software handshake mode. When you say Y here or hardware handshake
+  software handshake mode. If you say Y here or hardware handshake
   is on, it will always be RTS. Read the file
   Documentation/specialix.txt for more information.
 
@@ -7168,7 +7563,7 @@
 
 MTRR control and configuration
 CONFIG_MTRR
-  On Intel Pentium Pro/Pentium II systems the Memory Type Range
+  On Intel Pentium Pro and Pentium II systems the Memory Type Range
   Registers (MTRRs) may be used to control processor access to memory
   ranges. This is most useful when you have a video (VGA) card on a
   PCI or AGP bus. Enabling write-combining allows bus write transfers
@@ -7179,12 +7574,16 @@
   your MTRRs. Typically the X server should use this. This should have
   a reasonably generic interface so that similar control registers on
   other processors can be easily supported.
-  This option also fixes a problem with buggy SMP BIOSes which only
+
+  Saying Y here also fixes a problem with buggy SMP BIOSes which only
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
   lead to all sorts of problems.
-  Compiling this as a module is not available because the BIOS fix
-  needs to be done early in the boot sequence, otherwise your machine
-  could lock up.
+
+  In general you should compile this into the kernel, rather than as a
+  loadable module, because the BIOS fix needs to be done early in the
+  boot sequence. If you compile this as a module, the BIOS fix will be
+  delayed until when you load the module. You do this at your own risk.
+
   See Documentation/mtrr.txt for more information.
 
 Main CPU frequency, only for DEC alpha machine
@@ -7242,11 +7641,12 @@
    3) passing the "floppy=nodma" option to the kernel
    4) passing the "mem=4M" option to the kernel (thereby disabling 
       all but the first 4M of RAM)
-   5) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
-   6) disabling the cache from your BIOS settings
-   7) installing a better fan
-   8) exchanging RAM chips 
-   9) exchanging the motherboard.
+   5) making sure that the CPU is not over clocked.
+   6) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
+   7) disabling the cache from your BIOS settings
+   8) installing a better fan
+   9) exchanging RAM chips 
+   10) exchanging the motherboard.
 
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
@@ -7457,6 +7857,17 @@
   The module will be called nvram.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Atomwide Serial Support
+CONFIG_ATOMWIDE_SERIAL
+  If you have an Atomwide Serial card for an Acorn system, say Y to
+  this option.  The driver can handle 1, 2, or 3 port cards.
+  If unsure, say N
+
+The Serial Port Dual Serial Port
+CONFIG_DUALSP_SERIAL
+  If you have the Serial Port's dual serial card for an Acorn system,
+  say Y to this option.  If unsure, say N
+
 PC joystick support
 CONFIG_JOYSTICK
   If you have a PC compatible analog or digital joystick, you can say
@@ -7509,11 +7920,12 @@
   I'm told that even without a sound card, you can make your computer
   say more than an occasional beep, by programming the PC speaker.
   Kernel patches and programs to do that are in the pcsndrv package on
-  sunsite.unc.edu:/pub/Linux/kernel/patches/console/.
+  ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the
+  pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ .
 
 Support for Aztech Sound Galaxy (non-Pnp) cards
 CONFIG_SOUND_SGALAXY
-  This module initialises the older non Plug and Play sound galaxy cards
+  This module initializes the older non Plug and Play sound galaxy cards
   from Aztech. It supports the Waverider Pro 32 - 3D and the Galaxy
   Washington 16.
 
@@ -7548,12 +7960,12 @@
   these cards may cause trouble (I don't currently know of any such
   cards, however). If unsure, say Y.
 
-Loopback MIDI device support
-CONFIG_VMIDI
+#Loopback MIDI device support
+#CONFIG_SOUND_VMIDI
 ###
 ### somebody please fill this in.
 ###
-
+#
 Gravis Ultrasound support
 CONFIG_SOUND_GUS
   Say Y here for any type of Gravis Ultrasound card, including
@@ -7583,6 +7995,12 @@
   card based on the PSS chipset (AD1848 codec + ADSP-2115 DSP chip +
   Echo ESC614 ASIC CHIP).
 
+#Enable PSS mixer (Beethoven ADSP-16 and other compatible)
+#CONFIG_PSS_MIXER
+###
+### Don't know what this is
+###
+#
 Have DSPxxx.LD firmware file
 CONFIG_PSS_HAVE_BOOT
   If you want to emulate the Sound Blaster card and you have a DSPxxx.LD
@@ -7671,8 +8089,9 @@
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_SOUND_CS4232
   Say Y here if you have a card based on the Crystal CS4232 chip set,
-  which use its own Plug and Play protocol. See Documentation/sound/CS4232
-  for more information on configuring this card.
+  which uses its own Plug and Play protocol. See
+  Documentation/sound/CS4232 for more information on configuring this
+  card.
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_SOUND_MAUI
@@ -7689,6 +8108,43 @@
 CONFIG_MAUI_BOOT_FILE
   Enter the full pathname of your OSWF.MOT file, starting from /.
 
+Support for Turtle Beach MultiSound Classic, Tahiti, Monterey
+CONFIG_SOUND_MSNDCLAS
+  Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+  Monterey (not for the Pinnacle or Fiji).  See
+  Documentation/sound/MultiSound for important information about this
+  driver.
+
+Full pathname of MSNDINIT.BIN firmware file
+CONFIG_MSNDCLAS_INIT_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Full pathname of MSNDPERM.BIN firmware file
+CONFIG_MSNDCLAS_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Support for Turtle Beach MultiSound Pinnacle, Fiji
+CONFIG_SOUND_MSNDPIN
+  Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
+  See Documentation/sound/MultiSound for important information about
+  this driver.
+
+Full pathname of PNDSPINI.BIN firmware file
+CONFIG_MSNDPIN_INIT_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Full pathname of PNDSPERM.BIN firmware file
+CONFIG_MSNDPIN_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
 /dev/dsp and /dev/audio support
 CONFIG_SOUND_AUDIO
   Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
@@ -7717,11 +8173,6 @@
   affect the kernel; saying Y will simply cause this configure script
   to present you with more options. If unsure, say Y.
 
-SB32/AWE support
-CONFIG_AWE32_SYNTH
-  Say Y here if you have a SB32 or SB AWE soundcard. See
-  drivers/sound/lowlevel/README.awe for more info.
-
 ACI mixer (miroPCM12)
 CONFIG_ACI_MIXER
   Audio Command Interface (ACI) driver.  ACI is a protocol used to
@@ -8167,9 +8618,12 @@
 
 Macintosh support
 CONFIG_MAC
-  This option enables support for the Apple Macintosh series of computers
-  (yes, there is experimental support now, at least for part of the series).  
-  Say N unless you're willing to code the remaining necessary support. ;)
+  This option enables support for the Apple Macintosh series of
+  computers (yes, there is experimental support now, at least for part
+  of the series).
+  
+  Say N unless you're willing to code the remaining necessary support.
+  ;)
 
 # CONFIG_APOLLO, etc. coming soon (?)
 
@@ -8729,11 +9183,43 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+CPU Optimisation
+CONFIG_CPU_ARM2
+  This selects the processor type of your CPU.  This is only used to
+  determine C compiler optimisation options, and can affect the
+  compatability of the kernel on other processors.  If you specify
+  ARM6, the kernel should work on all 32-bit processors.  If you
+  specify ARM2, ARM250 or ARM3, it should work on all 26-bit
+  processors.  If you're not sure, set it to "None".
+
+ARM System type
+CONFIG_ARCH_ARC
+  This selects what ARM system you wish to build the kernel for.  It
+  also selects to some extent the CPU type.  If you are unsure what
+  to set this option to, please consult any information supplied with
+  your system.
+
+Build Tools Selection
+CONFIG_BINUTILS_NEW
+  Say Y here if you're using GCC 2.8.1/EGCS with a binutils version >= 2.8.1
+  to compile the kernel.  Otherwise, say N.
+
+Compile kernel with frame pointer
+CONFIG_FRAME_POINTER
+  In order to give useful debugging/error results, say Y here, otherwise
+  say N.
+
+VIDC Sound
+CONFIG_VIDC_SOUND
+  Say 'Y' here for ARM systems with the VIDC video controller and 16-bit
+  Linear sound DACs.  If unsure, say N.
+
 #
 # A couple of things I keep forgetting:
-#   capitalize: DMA, Internet, Intel, IRQ, Linux, NetWare, NFS, PCI, SCSI
-#   two words: hard drive, hard disk, sound card
-#   other: it's safe to save; daemon
+#   capitalize: Appletalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, 
+#               Linux, NetWare, NFS, PCI, SCSI
+#   two words:  hard drive, hard disk, sound card
+#   other:      it's safe to save; daemon
 #
 # This is used by Emacs' spell checker ispell.el:
 #
@@ -8753,7 +9239,7 @@
 # LocalWords:  buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
 # LocalWords:  QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES
 # LocalWords:  unix BBS linux nullmodem CSLIP PLIP Kirch's LDP CSlip SL SCC IRQ
-# LocalWords:  Turbo Laplink plip NCSA ReQuest IRQs EQL SMC AMD PCnet NE
+# LocalWords:  Turbo Laplink plip NCSA port's ReQuest IRQs EQL SMC AMD PCnet NE
 # LocalWords:  COM ELPLUS Com EtherLinkIII VLB Arcnet arcnet Cabletron DEPCA DE
 # LocalWords:  depca EtherWorks EWRK ewrk SEEQ EtherExpressPro EEXPRESS NI xxx
 # LocalWords:  EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET
@@ -8774,7 +9260,7 @@
 # LocalWords:  chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
 # LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
 # LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
-# LocalWords:  carleton Deskstation DECstation SUNFD JENSEN Noname SLiRP
+# LocalWords:  carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
 # LocalWords:  pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
 # LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
@@ -8796,10 +9282,10 @@
 # LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
 # LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
-# LocalWords:  FC DC dc PPA ppa RNFS FMV Fujitsu ARPD arpd loran layes
+# LocalWords:  FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes
 # LocalWords:  FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec
 # LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
-# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu HBAs MEX
+# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX
 # LocalWords:  Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
 # LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
 # LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs
@@ -8808,7 +9294,7 @@
 # LocalWords:  Bernd informatik rwth aachen uae affs multihosting bytecode java
 # LocalWords:  applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
 # LocalWords:  winsock RNIS caltech OSPF honour Honouring Mbit Localtalk DEFRAG
-# LocalWords:  download Packetwin Baycom baycom interwork ascii JNT
+# LocalWords:  localtalk download Packetwin Baycom baycom interwork ascii JNT
 # LocalWords:  Camtec proxying indyramp defragment defragmented UDP FAS FASXX
 # LocalWords:  FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ
 # LocalWords:  ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro
@@ -8851,7 +9337,7 @@
 # LocalWords:  smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
 # LocalWords:  Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
 # LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy
-# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's PnP
+# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp
 # LocalWords:  AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP
 # LocalWords:  Autoprobe bart patrickr HDLS READBACK AB usr DAMA DS SparQ aten
 # LocalWords:  Symbios PCscsi tmscsim RoamAbout GHz Hinds' contrib mathematik
@@ -8904,4 +9390,12 @@
 # LocalWords:  mwave OLDCARD isdnloop linklevel loopctrl Eicon Diehl DIEHLDIVA
 # LocalWords:  ASUSCOM AsusCom TELEINT semiactiv Sedlbauer Sportster TA MIC ITH
 # LocalWords:  NETjet NetJet Niccy Neuhaus sparcs AOC AOCD AOCE Microlink SAA
-# LocalWords:  teletext WinTV saa iproute tc
+# LocalWords:  teletext WinTV saa iproute tc Quadra Performa PowerBook tor AUN
+# LocalWords:  setserial compsoc steve Econet econet AUNUDP psched TEQL TLE CLS
+# LocalWords:  teql FW Ingres TwistedPair MTRR MTRRs mtrr cfs crypto TD ktti KT
+# LocalWords:  PHd ICS ipchains adelaide rustcorp syslog epp Cumana
+# LocalWords:  AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF
+# LocalWords:  RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis
+# LocalWords:  Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
+# LocalWords:  EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson
+# LocalWords:  SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT
diff -u --recursive --new-file v2.1.105/linux/Documentation/filesystems/isofs.txt linux/Documentation/filesystems/isofs.txt
--- v2.1.105/linux/Documentation/filesystems/isofs.txt	Thu Feb 12 20:56:03 1998
+++ linux/Documentation/filesystems/isofs.txt	Sat Jun 13 13:39:15 1998
@@ -21,7 +21,8 @@
   check=strict  Matches only filenames with the exact same case
   cruft         Try to handle badly formatted CDs.
   map=off       Do not map non-rockridge filenames to lowercase
-  map=normal    Map rockridge filenames to lowercase
+  map=normal    Map non-rockridge filenames to lowecase
+  map=acorn     As map=normal but also apply Acorn extensions if present
   mode=xxx      Sets the permissions on files to xxx
   nojoliet      Ignore Joliet extensions if they are present.
   norock        Ignore rockridge extensions if they are present.
diff -u --recursive --new-file v2.1.105/linux/Documentation/paride.txt linux/Documentation/paride.txt
--- v2.1.105/linux/Documentation/paride.txt	Sun Jun  7 11:16:26 1998
+++ linux/Documentation/paride.txt	Sat Jun 13 12:08:19 1998
@@ -44,6 +44,7 @@
 	Imation Superdisk LS-120
 	FreeCom Power CD
 	Hewlett-Packard 5GB tape drive
+	Hewlett-Packard 7100 and 7200 CD-RW drives
 
 as well as most of the clone and no-name products on the market.
 
@@ -57,8 +58,9 @@
 	pcd	ATAPI CD-ROM
 	pf	ATAPI disk
 	pt	ATAPI tape
+	pg	ATAPI generic
 
-(Support for ATAPI CD-R and CD-RW drives is in the design phase.)
+(Currently, the pg driver is only used with CD-R drives).
 
 The high-level drivers function according to the relevant standards.
 The third component of PARIDE is a set of low-level protocol drivers
@@ -72,7 +74,8 @@
         dstr    DataStor EP-2000                       (TW)
         epat    Shuttle EPAT                           (UK)
         epia    Shuttle EPIA                           (UK)
-	fit2    FIT TD-2000
+	fit2    FIT TD-2000			       (US)
+	fit3    FIT TD-3000			       (US)
         frpw    Freecom Power                          (DE)
         kbic    KingByte KBIC-951A and KBIC-971A       (TW)
 	ktti    KT Technology PHd adapter              (SG)
@@ -111,6 +114,7 @@
 	Avatar			Shark		pd	epat
 	FreeCom			CD-ROM		pcd	frpw
 	Hewlett-Packard		5GB Tape	pt	epat
+	Hewlett-Packard		7100/7200	pg	epat
 
 2.1  Configuring built-in drivers
 
@@ -258,6 +262,7 @@
 for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
 for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
 for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done 
 #
 # end of mkd
 
@@ -285,6 +290,11 @@
 	mkdosfs /dev/pf0
 	mount /dev/pf0 /mnt
 
+2.4  Using the pg driver
+
+The pg driver can be used in conjunction with the cdrecord program
+to create CD-ROMs.  For more information, and the required patches 
+to cdrecord, please visit http://www.torque.net/parport/cdr.html .
 
 3. Troubleshooting
 
@@ -333,6 +343,6 @@
 You might also find some useful information on the linux-parport
 web pages (although they are not always up to date) at
 
-	http://www.torque.net/linux-pp.html
+	http://www.torque.net/parport/
 
 
diff -u --recursive --new-file v2.1.105/linux/Documentation/sound/ALS007 linux/Documentation/sound/ALS007
--- v2.1.105/linux/Documentation/sound/ALS007	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/ALS007	Sat Jun 13 10:23:41 1998
@@ -0,0 +1,40 @@
+ALS-007 based soundcards
+========================
+
+Support for soundcards based around the Avance Logic ALS-007 chip is
+included.  The ALS-007 is a single chip PnP sound solution which is mostly
+hardware compatible with the Sound Blaster 16 card, with most differences
+occuring in the use of the mixer registers.  For this reason the ALS-007 
+code is integrated as part of the Sound Blaster 16 driver (adding only 800
+bytes to the SB16 driver).
+
+To use an ALS-007 soundcard under Linux, enable the following options in the
+sound configuration section of the kernel config:
+  - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
+  - FM synthesizer (YM3812/OPL-3) support 
+Since the ALS-007 is a PnP card, the sound driver probably should be
+compiled as a module, with the isapnptools used to wake up the soundcard.
+Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
+either 0, 1 or 3) to the values used in your particular installation (they
+should match the values used to configure the card using isapnp).  The
+ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA"
+should be set to -1.  If you wish to use the externel MPU-401 interface on
+the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to
+the appropriate values for your installation.  (Note that the ALS-007
+requires a separate IRQ for the MPU-401, so don't specify -1 here).  (Note
+that the base port of the internal FM synth is fixed at 0x388 on the ALS007; 
+in any case the FM synth location is not setable in the kernel config).
+
+The resulting sound driver will provide the following capabilities:
+  - 8 and 16 bit audio playback
+  - 8 and 16 bit audio recording
+  - Software selection of record source (line in, CD, FM, mic, master)
+  - Record and playback of midi data via the external MPU-401
+  - Playback of midi data using inbuilt FM synthesizer
+  - Control of the ALS-007 mixer via any OSS-compatible mixer programs. 
+    Controls available are Master (L&R), Line in (L&R), CD (L&R), 
+    DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
+
+Jonathan Woithe
+jwoithe@physics.adelaide.edu.au
+30 March 1998
diff -u --recursive --new-file v2.1.105/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32
--- v2.1.105/linux/Documentation/sound/AWE32	Sat May  2 14:19:52 1998
+++ linux/Documentation/sound/AWE32	Sat Jun 13 12:10:30 1998
@@ -5,7 +5,7 @@
 be issued (of course with the suitable values for the parameters)
 after PNP setup:
 
-insmod  sound.o
+modprobe  sound.o
 insmod  uart401.o
 insmod  sb.o io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
 insmod  awe_wave.o
@@ -59,5 +59,6 @@
 rmmod sb
 rmmod uart401
 rmmod sound
+rmmod soundcore
  -----
 
diff -u --recursive --new-file v2.1.105/linux/Documentation/sound/MultiSound linux/Documentation/sound/MultiSound
--- v2.1.105/linux/Documentation/sound/MultiSound	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/MultiSound	Sat Jun 13 10:23:41 1998
@@ -0,0 +1,146 @@
+Getting Firmware
+~~~~~~~~~~~~~~~~
+
+See the end of this document on how to obtain and create the necessary
+firmware files.
+
+
+Supported Features
+~~~~~~~~~~~~~~~~~~
+
+Currently digital audio and mixer functionality is supported.  (memory
+mapped digital audio is not yet supported).  MultiSound support is
+fully modularized, and can only be used as modules:
+
+msnd		- MultiSound base (requires soundcore)
+msnd_classic	- Base audio/mixer support for Classic, Monetery and
+                  Tahiti cards
+msnd_pinnacle	- Base audio/mixer support for Pinnacle and Fiji cards
+
+
+Important Notes - Read Before Using
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* The firmware files are not included (may change in future).  You
+must obtain these images from Turtle Beach (they are included in the
+MultiSound Development Kits), and place them in /etc/sound for
+example, and give the full paths in the Linux configuration.  Please
+note these files must be binary files, not assember.
+
+* You need the following information to use this driver: the card's
+I/O base (i.e. 0x250), the IRQ (i.e. 5), and the shared memory area
+(i.e. 0xd8000).
+
+* Probing is not currently implemented, and only the msnd_classic
+driver will actually program the card's IRQ and SMA locations; the
+msnd_pinnacle is primarily for use with the card in PnP mode, however
+it should work if you know what the card's resource values are (this
+will change in the future).
+
+* Note the Turtle Beach Pinnacle card contains a Kurzweil MA-1
+synthesizer with an MPU compatible interface, which should work with
+the mpu401 module.  You must know the resource values of the MA-1.
+
+
+Examples
+~~~~~~~~
+
+* If you have a MultiSound Classic/Monterey/Tahiti:
+
+insmod soundcore
+insmod msnd
+insmod msnd_classic io=0x290 irq=7 mem=0xd0000
+
+* If you have a MultiSound Pinnacle:
+
+insmod soundcore
+insmod msnd
+insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000
+
+* To use the MPU-compatible Kurzweil synth on the Pinnacle, add the
+following:
+
+insmod sound
+insmod mpu401 io=0x330 irq=9
+
+
+msnd_classic, msnd_pinnacle Required Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the following options are not given, the module will not load.
+Examine the kernel message log for informative error messages.
+WARNING--probing isn't supported so try to make sure you have the
+correct shared memory area, otherwise you may experience problems.
+
+io		        I/O base of DSP, e.g. io=0x210
+irq		        IRQ number, e.g. irq=5
+mem		        Shared memory area, e.g. mem=0xd8000
+
+
+msnd_classic, msnd_pinnacle Additional Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+fifosize		The digital audio FIFOs, in kilobytes.  The default is
+			64kB (two FIFOs are allocated, so this uses up 128kB).
+
+calibrate_signal	Setting this to one calibrates the ADCs to the
+			signal, zero calibrates to the card (defaults
+			to zero).
+
+
+Creating and Obtaining Firmware
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	For the Classic/Tahiti/Monterey
+	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	
+
+Download to /tmp and unzip the following file from Turtle Beach:
+
+	ftp://ftp.tbeach.com/pub/tbs/pinn/msndvkit.zip
+
+When unzipped, unzip the file named MsndFiles.zip.  Then copy the
+following firmware files to /etc/sound (note the file renaming):
+
+  cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
+  cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
+
+When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
+/etc/sound/msndperm.bin for the two firmware files.
+
+
+	For the Pinnacle/Fiji
+	~~~~~~~~~~~~~~~~~~~~~
+
+Download to /tmp and unzip the following file from Turtle Beach (be
+sure to use the entire URL; some have had trouble navigating to the
+URL):
+
+	ftp://ftp.tbeach.com/oldpub/tbs/pinn/pnddk100.zip
+
+Put the following lines into a file named conv.l (between the start
+and end lines):
+
+-- conv.l start --
+%%
+[ \n\t,\r]	;
+\;.*		;
+DB		;
+[0-9A-Fa-f]+H	{ int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
+-- conv.l end --
+
+Then, compile the conv program with GNU make with the following
+command:
+
+  make LEX=flex LOADLIBES=-lfl conv
+
+This should give you an executable named conv.  Now, we create the
+binary firmware files by doing the following conversion (assuming the
+archive unpacked into a directory named PINNDDK):
+
+  ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
+  ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
+
+The conv (and conv.l) program is not needed after conversion and can
+be safely deleted.  Then, when configuring the Linux kernel, specify
+/etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
+firmware files.
diff -u --recursive --new-file v2.1.105/linux/Documentation/sound/Multisound linux/Documentation/sound/Multisound
--- v2.1.105/linux/Documentation/sound/Multisound	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/Multisound	Sat Jun 13 11:36:52 1998
@@ -0,0 +1,4 @@
+Turtle Beach Multisound support is not yet integrated. If you'd like
+to test it or help out in finishing the module please see
+
+	http://www.rpi.edu/~veliaa/pinlinux.html
diff -u --recursive --new-file v2.1.105/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster
--- v2.1.105/linux/Documentation/sound/Soundblaster	Sun Jun  7 11:16:26 1998
+++ linux/Documentation/sound/Soundblaster	Sat Jun 13 10:23:52 1998
@@ -32,7 +32,11 @@
 to warm boot from DOS/Windows with the required firmware loaded under this
 OS. IBM are being difficult about documenting how to load this firmware.
 
-Advance Logic ALS007
+Avance Logic ALS007
 
-This card isn't currently supported. I have patches to merge however that
-add limited support.
+This card is supported; see the separate file ALS007 for full details.
+
+Avance Logic ALS100
+
+This card is supported; setup should be as for a standard Sound Blaster 16.
+The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)".
diff -u --recursive --new-file v2.1.105/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.105/linux/MAINTAINERS	Sun Jun  7 11:16:26 1998
+++ linux/MAINTAINERS	Sat Jun 13 12:59:16 1998
@@ -277,7 +277,7 @@
 
 HIGH-SPEED SCC DRIVER FOR AX.25
 P:	Klaus Kudielka
-M:	oe1kib@oe1xtu.ampr.org
+M:	oe1kib@oe1kib.ampr.org
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
 
@@ -304,6 +304,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+IP FIREWALL
+P:	Paul Russell
+M:	Paul.Russell@rustcorp.com.au
+W:	http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S:	Maintained
+
 IPX/SPX NETWORK LAYER
 P:	Jay Schulist
 M:	Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
@@ -379,6 +385,11 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+MULTISOUND SOUND DRIVER
+P:	Andrew Veliath
+M:	andrewtv@usa.net
+S:	Maintained
+
 NCP FILESYSTEM:
 P:	Petr Vandrovec
 M:	vandrove@vc.cvut.cz
@@ -539,6 +550,12 @@
 L:	linux-kernel@vger.rutgers.edu ?
 S:	Supported
 
+SPX NETWORK LAYER
+P:	Jay Schulist
+M:	Jay.Schulist@spacs.k12.wi.us
+L:	linux-net@vger.rutgers.edu
+S:	Supported
+
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
 P:	Greg Ungerer
 M:	support@stallion.oz.au
@@ -571,8 +588,9 @@
 
 TOKEN-RING NETWORK DRIVER
 P:	Paul Norton
-M:	pnorton@cts.com
+M:	p.norton@computer.org
 L:	linux-net@vger.rutgers.edu
+L:	linux-tr@emissary.aus-etc.com
 S:	Maintained
 
 U14-34F SCSI DRIVER
@@ -629,6 +647,19 @@
 W:	http://poboxes.com/jreuter/
 W:	http://qsl.net/dl1bke/
 L:	linux-hams@vger.rutgers.edu
+S:	Maintained
+
+ARM PORT
+P:	Russell King
+M:	linux@arm.uk.linux.org
+L:	linux-arm@vger.rutgers.edu
+L:	arm-linux@tardis.ed.ac.uk
+W:	http://www.arm.uk.linux.org/~rmk/armlinux.html
+S:	Maintained
+
+ARM MFM AND FLOPPY DRIVERS
+P:	Dave Gilbert
+M:	linux@treblig.org
 S:	Maintained
 
 REST:
diff -u --recursive --new-file v2.1.105/linux/Makefile linux/Makefile
--- v2.1.105/linux/Makefile	Tue Jun  9 11:57:28 1998
+++ linux/Makefile	Sat Jun 13 13:33:50 1998
@@ -1,8 +1,8 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 105
+SUBLEVEL = 106
 
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm*/arm/ -e s/sa110/arm/)
 
 #
 # For SMP kernels, set this. We don't want to have this in the config file
diff -u --recursive --new-file v2.1.105/linux/README linux/README
--- v2.1.105/linux/README	Sun Jun  7 11:16:26 1998
+++ linux/README	Sat Jun 13 12:59:16 1998
@@ -39,8 +39,8 @@
 ON WHAT HARDWARE DOES IT RUN?
 
   Linux was first developed for 386/486-based PCs.  These days it also
-  runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga),
-  MIPS, PowerPC, and others.
+  runs on ARMs, DEC Alphas, SUN Sparcs, M68000 machines (like Atari and
+  Amiga), MIPS and PowerPC, and others.
 
 DOCUMENTATION:
 
diff -u --recursive --new-file v2.1.105/linux/Rules.make linux/Rules.make
--- v2.1.105/linux/Rules.make	Tue Jun  9 11:57:28 1998
+++ linux/Rules.make	Tue Jun  9 01:40:49 1998
@@ -189,9 +189,14 @@
 endif
 
 $(MODINCL)/%.ver: %.c
-	$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<\
-	| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
-	mv $@.tmp $@
+	@if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
+		echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
+		echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
+		$(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
+		| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
+		if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
+		else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
+	fi; touch $(MODINCL)/$*.stamp
 	
 $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h
 
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.105/linux/arch/alpha/kernel/entry.S	Sun Jun  7 11:16:26 1998
+++ linux/arch/alpha/kernel/entry.S	Tue Jun  9 13:34:01 1998
@@ -924,7 +924,7 @@
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall			/* 110 */
 	.quad sys_sigsuspend
-	.quad sys_ni_syscall
+	.quad osf_sigstack
 	.quad sys_recvmsg
 	.quad sys_sendmsg
 	.quad alpha_ni_syscall			/* 115 */
@@ -1047,7 +1047,7 @@
 	.quad alpha_ni_syscall
 	.quad sys_getpgid
 	.quad sys_getsid
-	.quad alpha_ni_syscall			/* 235 */
+	.quad sys_sigaltstack			/* 235 */
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall
@@ -1181,5 +1181,6 @@
 	.quad sys_wait4				/* 365 */
 	.quad sys_adjtimex
 	.quad sys_getcwd
-	.quad sys_ni_syscall
-	.quad sys_ni_syscall			/* 369 */
+	.quad sys_capget
+	.quad sys_capset
+	.quad sys_ni_syscall			/* 370 */
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.105/linux/arch/alpha/kernel/osf_sys.c	Tue Mar 10 10:03:30 1998
+++ linux/arch/alpha/kernel/osf_sys.c	Sat Jun 13 11:36:52 1998
@@ -537,11 +537,15 @@
 	error = verify_area(VERIFY_WRITE, name, 5 * 32);
 	if (error)
 		goto out;
+		
+	down(&uts_sem);
 	copy_to_user(name + 0, system_utsname.sysname, 32);
 	copy_to_user(name + 32, system_utsname.nodename, 32);
 	copy_to_user(name + 64, system_utsname.release, 32);
 	copy_to_user(name + 96, system_utsname.version, 32);
 	copy_to_user(name + 128, system_utsname.machine, 32);
+	up(&uts_sem);
+	
 out:
 	unlock_kernel();
 	return error;
@@ -602,11 +606,13 @@
 	if (namelen > 32)
 		len = 32;
 
+	down(&uts_sem);
 	for (i = 0; i < len; ++i) {
-		put_user(system_utsname.domainname[i], name + i);
+		__put_user(system_utsname.domainname[i], name + i);
 		if (system_utsname.domainname[i] == '\0')
 			break;
 	}
+	up(&uts_sem);
 out:
 	unlock_kernel();
 	return error;
@@ -743,6 +749,50 @@
 	return error;
 }
 
+asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
+{
+	unsigned long usp = rdusp();
+	unsigned long oss_sp, oss_os;
+	int error;
+
+	if (uoss) {
+		oss_sp = current->sas_ss_sp + current->sas_ss_size;
+		oss_os = on_sig_stack(usp);
+	}
+
+	if (uss) {
+		unsigned long ss_sp;
+
+		error = -EFAULT;
+		if (get_user(ss_sp, &uss->ss_sp))
+			goto out;
+
+		/* If the current stack was set with sigaltstack, don't
+		   swap stacks while we are on it.  */
+		error = -EPERM;
+		if (current->sas_ss_sp && on_sig_stack(usp))
+			goto out;
+
+		/* Since we don't know the extent of the stack, and we don't
+		   track onstack-ness, but rather calculate it, we must 
+		   presume a size.  Ho hum this interface is lossy.  */
+		current->sas_ss_sp = ss_sp - SIGSTKSZ;
+		current->sas_ss_size = SIGSTKSZ;
+	}
+
+	if (uoss) {
+		error = -EFAULT;
+		if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))
+		    || __put_user(oss_sp, &uoss->ss_sp)
+		    || __put_user(oss_os, &uoss->ss_onstack))
+			goto out;
+	}
+
+	error = 0;
+out:
+	return error;
+}
+
 /*
  * The Linux kernel isn't good at returning values that look
  * like negative longs (they are mistaken as error values).
@@ -799,6 +849,8 @@
 		printk("sysinfo(%d)", command);
 		goto out;
 	}
+	
+	down(&uts_sem);
 	res = sysinfo_table[offset];
 	len = strlen(res)+1;
 	if (len > count)
@@ -807,6 +859,7 @@
 		err = -EFAULT;
 	else
 		err = 0;
+	up(&uts_sem);
 out:
 	unlock_kernel();
 	return err;
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.1.105/linux/arch/alpha/kernel/process.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/kernel/process.c	Sat Jun 13 12:48:10 1998
@@ -120,6 +120,7 @@
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
+		check_pgt_cache();
 		schedule();
 	}
 	ret = 0;
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.1.105/linux/arch/alpha/kernel/signal.c	Fri Jan 30 11:28:05 1998
+++ linux/arch/alpha/kernel/signal.c	Tue Jun  9 13:34:01 1998
@@ -203,6 +203,12 @@
 	}
 }
 
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	return do_sigaltstack(uss, uoss, rdusp());
+}
+
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -225,67 +231,65 @@
 #define INSN_LDI_R0		0x201f0000
 #define INSN_CALLSYS		0x00000083
 
-
-static void
+static long
 restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 		   struct switch_stack *sw)
 {
 	unsigned long usp;
-	int i;
+	long i, err = 0;
 
-	__get_user(regs->pc, &sc->sc_pc);
+	err |= __get_user(regs->pc, &sc->sc_pc);
 	sw->r26 = (unsigned long) ret_from_sys_call;
 
-	__get_user(regs->r0, sc->sc_regs+0);
-	__get_user(regs->r1, sc->sc_regs+1);
-	__get_user(regs->r2, sc->sc_regs+2);
-	__get_user(regs->r3, sc->sc_regs+3);
-	__get_user(regs->r4, sc->sc_regs+4);
-	__get_user(regs->r5, sc->sc_regs+5);
-	__get_user(regs->r6, sc->sc_regs+6);
-	__get_user(regs->r7, sc->sc_regs+7);
-	__get_user(regs->r8, sc->sc_regs+8);
-	__get_user(sw->r9, sc->sc_regs+9);
-	__get_user(sw->r10, sc->sc_regs+10);
-	__get_user(sw->r11, sc->sc_regs+11);
-	__get_user(sw->r12, sc->sc_regs+12);
-	__get_user(sw->r13, sc->sc_regs+13);
-	__get_user(sw->r14, sc->sc_regs+14);
-	__get_user(sw->r15, sc->sc_regs+15);
-	__get_user(regs->r16, sc->sc_regs+16);
-	__get_user(regs->r17, sc->sc_regs+17);
-	__get_user(regs->r18, sc->sc_regs+18);
-	__get_user(regs->r19, sc->sc_regs+19);
-	__get_user(regs->r20, sc->sc_regs+20);
-	__get_user(regs->r21, sc->sc_regs+21);
-	__get_user(regs->r22, sc->sc_regs+22);
-	__get_user(regs->r23, sc->sc_regs+23);
-	__get_user(regs->r24, sc->sc_regs+24);
-	__get_user(regs->r25, sc->sc_regs+25);
-	__get_user(regs->r26, sc->sc_regs+26);
-	__get_user(regs->r27, sc->sc_regs+27);
-	__get_user(regs->r28, sc->sc_regs+28);
-	__get_user(regs->gp, sc->sc_regs+29);
-	__get_user(usp, sc->sc_regs+30);
+	err |= __get_user(regs->r0, sc->sc_regs+0);
+	err |= __get_user(regs->r1, sc->sc_regs+1);
+	err |= __get_user(regs->r2, sc->sc_regs+2);
+	err |= __get_user(regs->r3, sc->sc_regs+3);
+	err |= __get_user(regs->r4, sc->sc_regs+4);
+	err |= __get_user(regs->r5, sc->sc_regs+5);
+	err |= __get_user(regs->r6, sc->sc_regs+6);
+	err |= __get_user(regs->r7, sc->sc_regs+7);
+	err |= __get_user(regs->r8, sc->sc_regs+8);
+	err |= __get_user(sw->r9, sc->sc_regs+9);
+	err |= __get_user(sw->r10, sc->sc_regs+10);
+	err |= __get_user(sw->r11, sc->sc_regs+11);
+	err |= __get_user(sw->r12, sc->sc_regs+12);
+	err |= __get_user(sw->r13, sc->sc_regs+13);
+	err |= __get_user(sw->r14, sc->sc_regs+14);
+	err |= __get_user(sw->r15, sc->sc_regs+15);
+	err |= __get_user(regs->r16, sc->sc_regs+16);
+	err |= __get_user(regs->r17, sc->sc_regs+17);
+	err |= __get_user(regs->r18, sc->sc_regs+18);
+	err |= __get_user(regs->r19, sc->sc_regs+19);
+	err |= __get_user(regs->r20, sc->sc_regs+20);
+	err |= __get_user(regs->r21, sc->sc_regs+21);
+	err |= __get_user(regs->r22, sc->sc_regs+22);
+	err |= __get_user(regs->r23, sc->sc_regs+23);
+	err |= __get_user(regs->r24, sc->sc_regs+24);
+	err |= __get_user(regs->r25, sc->sc_regs+25);
+	err |= __get_user(regs->r26, sc->sc_regs+26);
+	err |= __get_user(regs->r27, sc->sc_regs+27);
+	err |= __get_user(regs->r28, sc->sc_regs+28);
+	err |= __get_user(regs->gp, sc->sc_regs+29);
+	err |= __get_user(usp, sc->sc_regs+30);
 	wrusp(usp);
 
 	for (i = 0; i < 31; i++)
-		__get_user(sw->fp[i], sc->sc_fpregs+i);
-	__get_user(sw->fp[31], &sc->sc_fpcr);
+		err |= __get_user(sw->fp[i], sc->sc_fpregs+i);
+	err |= __get_user(sw->fp[31], &sc->sc_fpcr);
+
+	return err;
 }
 
 asmlinkage void
 do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
 	     struct switch_stack *sw)
 {
-	unsigned long ps;
 	sigset_t set;
 
 	/* Verify that it's a good sigcontext before using it */
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto give_sigsegv;
-	if (__get_user(ps, &frame->sc.sc_ps) || ps != 8)
-		goto give_sigsegv;
 	if (__get_user(set.sig[0], &frame->sc.sc_mask)
 	    || (_NSIG_WORDS > 1
 		&& __copy_from_user(&set.sig[1], &frame->extramask,
@@ -298,7 +302,8 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	restore_sigcontext(&frame->sc, regs, sw);
+	if (restore_sigcontext(&frame->sc, regs, sw))
+		goto give_sigsegv;
 
 	/* Send SIGTRAP if we're single-stepping: */
 	if (ptrace_cancel_bpt (current))
@@ -306,22 +311,19 @@
 	return;
 
 give_sigsegv:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
 }
 
 asmlinkage void
 do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
 		struct switch_stack *sw)
 {
-	unsigned long ps;
 	sigset_t set;
+	stack_t st;
 
 	/* Verify that it's a good sigcontext before using it */
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto give_sigsegv;
-	if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8)
-		goto give_sigsegv;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto give_sigsegv;
 
@@ -331,7 +333,14 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	restore_sigcontext(&frame->uc.uc_mcontext, regs, sw);
+	if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
+		goto give_sigsegv;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto give_sigsegv;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, rdusp());
 
 	/* Send SIGTRAP if we're single-stepping: */
 	if (ptrace_cancel_bpt (current))
@@ -339,8 +348,7 @@
 	return;
 
 give_sigsegv:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
 }
 
 
@@ -348,99 +356,113 @@
  * Set up a signal frame.
  */
 
-static void 
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	return (void *)((sp - frame_size) & -32ul);
+}
+
+static long
 setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, 
 		 struct switch_stack *sw, unsigned long mask, unsigned long sp)
 {
-	long i;
+	long i, err = 0;
 
-	__put_user(0, &sc->sc_onstack);
-	__put_user(mask, &sc->sc_mask);
-	__put_user(regs->pc, &sc->sc_pc);
-	__put_user(8, &sc->sc_ps);
-
-	__put_user(regs->r0 , sc->sc_regs+0);
-	__put_user(regs->r1 , sc->sc_regs+1);
-	__put_user(regs->r2 , sc->sc_regs+2);
-	__put_user(regs->r3 , sc->sc_regs+3);
-	__put_user(regs->r4 , sc->sc_regs+4);
-	__put_user(regs->r5 , sc->sc_regs+5);
-	__put_user(regs->r6 , sc->sc_regs+6);
-	__put_user(regs->r7 , sc->sc_regs+7);
-	__put_user(regs->r8 , sc->sc_regs+8);
-	__put_user(sw->r9   , sc->sc_regs+9);
-	__put_user(sw->r10  , sc->sc_regs+10);
-	__put_user(sw->r11  , sc->sc_regs+11);
-	__put_user(sw->r12  , sc->sc_regs+12);
-	__put_user(sw->r13  , sc->sc_regs+13);
-	__put_user(sw->r14  , sc->sc_regs+14);
-	__put_user(sw->r15  , sc->sc_regs+15);
-	__put_user(regs->r16, sc->sc_regs+16);
-	__put_user(regs->r17, sc->sc_regs+17);
-	__put_user(regs->r18, sc->sc_regs+18);
-	__put_user(regs->r19, sc->sc_regs+19);
-	__put_user(regs->r20, sc->sc_regs+20);
-	__put_user(regs->r21, sc->sc_regs+21);
-	__put_user(regs->r22, sc->sc_regs+22);
-	__put_user(regs->r23, sc->sc_regs+23);
-	__put_user(regs->r24, sc->sc_regs+24);
-	__put_user(regs->r25, sc->sc_regs+25);
-	__put_user(regs->r26, sc->sc_regs+26);
-	__put_user(regs->r27, sc->sc_regs+27);
-	__put_user(regs->r28, sc->sc_regs+28);
-	__put_user(regs->gp , sc->sc_regs+29);
-	__put_user(sp, sc->sc_regs+30);
-	__put_user(0, sc->sc_regs+31);
+	err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
+	err |= __put_user(mask, &sc->sc_mask);
+	err |= __put_user(regs->pc, &sc->sc_pc);
+	err |= __put_user(8, &sc->sc_ps);
+
+	err |= __put_user(regs->r0 , sc->sc_regs+0);
+	err |= __put_user(regs->r1 , sc->sc_regs+1);
+	err |= __put_user(regs->r2 , sc->sc_regs+2);
+	err |= __put_user(regs->r3 , sc->sc_regs+3);
+	err |= __put_user(regs->r4 , sc->sc_regs+4);
+	err |= __put_user(regs->r5 , sc->sc_regs+5);
+	err |= __put_user(regs->r6 , sc->sc_regs+6);
+	err |= __put_user(regs->r7 , sc->sc_regs+7);
+	err |= __put_user(regs->r8 , sc->sc_regs+8);
+	err |= __put_user(sw->r9   , sc->sc_regs+9);
+	err |= __put_user(sw->r10  , sc->sc_regs+10);
+	err |= __put_user(sw->r11  , sc->sc_regs+11);
+	err |= __put_user(sw->r12  , sc->sc_regs+12);
+	err |= __put_user(sw->r13  , sc->sc_regs+13);
+	err |= __put_user(sw->r14  , sc->sc_regs+14);
+	err |= __put_user(sw->r15  , sc->sc_regs+15);
+	err |= __put_user(regs->r16, sc->sc_regs+16);
+	err |= __put_user(regs->r17, sc->sc_regs+17);
+	err |= __put_user(regs->r18, sc->sc_regs+18);
+	err |= __put_user(regs->r19, sc->sc_regs+19);
+	err |= __put_user(regs->r20, sc->sc_regs+20);
+	err |= __put_user(regs->r21, sc->sc_regs+21);
+	err |= __put_user(regs->r22, sc->sc_regs+22);
+	err |= __put_user(regs->r23, sc->sc_regs+23);
+	err |= __put_user(regs->r24, sc->sc_regs+24);
+	err |= __put_user(regs->r25, sc->sc_regs+25);
+	err |= __put_user(regs->r26, sc->sc_regs+26);
+	err |= __put_user(regs->r27, sc->sc_regs+27);
+	err |= __put_user(regs->r28, sc->sc_regs+28);
+	err |= __put_user(regs->gp , sc->sc_regs+29);
+	err |= __put_user(sp, sc->sc_regs+30);
+	err |= __put_user(0, sc->sc_regs+31);
 
 	for (i = 0; i < 31; i++)
-		__put_user(sw->fp[i], sc->sc_fpregs+i);
-	__put_user(0, sc->sc_fpregs+31);
-	__put_user(sw->fp[31], &sc->sc_fpcr);
-
-	__put_user(regs->trap_a0, &sc->sc_traparg_a0);
-	__put_user(regs->trap_a1, &sc->sc_traparg_a1);
-	__put_user(regs->trap_a2, &sc->sc_traparg_a2);
+		err |= __put_user(sw->fp[i], sc->sc_fpregs+i);
+	err |= __put_user(0, sc->sc_fpregs+31);
+	err |= __put_user(sw->fp[31], &sc->sc_fpcr);
+
+	err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
+	err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
+	err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
+
+	return err;
 }
 
 static void
 setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
 	    struct pt_regs *regs, struct switch_stack * sw)
 {
-	unsigned long oldsp;
+	unsigned long oldsp, r26, err = 0;
 	struct sigframe *frame;
 
 	oldsp = rdusp();
-	frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32);
-
-	/* XXX: Check here if we would need to switch stacks.. */
+	frame = get_sigframe(ka, oldsp, sizeof(*frame));
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-	setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
+	err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
 	if (_NSIG_WORDS > 1) {
-		__copy_to_user(frame->extramask, &set->sig[1], 
-			       sizeof(frame->extramask));
+		err |= __copy_to_user(frame->extramask, &set->sig[1], 
+				      sizeof(frame->extramask));
 	}
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->ka_restorer) {
-		regs->r26 = (unsigned long) ka->ka_restorer;
+		r26 = (unsigned long) ka->ka_restorer;
 	} else {
-		__put_user(INSN_MOV_R30_R16, frame->retcode+0);
-		__put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
-		__put_user(INSN_CALLSYS, frame->retcode+2);
+		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+		err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
+		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
 		imb();
-		regs->r26 = (unsigned long) frame->retcode;
+		r26 = (unsigned long) frame->retcode;
 	}
 
+	/* Check that everything was written properly.  */
+	if (err)
+		goto give_sigsegv;
+
 	/* "Return" to the handler */
+	regs->r26 = r26;
 	regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
 	regs->r16 = sig;			/* a0: signal number */
 	regs->r17 = 0;				/* a1: exception code */
 	regs->r18 = (unsigned long) &frame->sc;	/* a2: sigcontext pointer */
 	wrusp((unsigned long) frame);
-
+	
 #if DEBUG_SIG
 	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
 		current->comm, current->pid, frame, regs->pc, regs->r26);
@@ -449,47 +471,54 @@
 	return;
 
 give_sigsegv:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 static void
 setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	       sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
 {
-	unsigned long oldsp;
+	unsigned long oldsp, r26, err = 0;
 	struct rt_sigframe *frame;
 
 	oldsp = rdusp();
-	frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32);
-
-	/* XXX: Check here if we would need to switch stacks.. */
+	frame = get_sigframe(ka, oldsp, sizeof(*frame));
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-	__copy_to_user(&frame->info, info, sizeof(siginfo_t));
+	err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
 
-	/* Zero all bits of the ucontext besides the sigcontext.  */
-	__clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
-	/* Copy in the bits we actually use.  */
-	__put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
-	setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp);
-	__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
+				set->sig[0], oldsp);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->ka_restorer) {
-		regs->r26 = (unsigned long) ka->ka_restorer;
+		r26 = (unsigned long) ka->ka_restorer;
 	} else {
-		__put_user(INSN_MOV_R30_R16, frame->retcode+0);
-		__put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1);
-		__put_user(INSN_CALLSYS, frame->retcode+2);
+		err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+		err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
+				  frame->retcode+1);
+		err |= __put_user(INSN_CALLSYS, frame->retcode+2);
 		imb();
-		regs->r26 = (unsigned long) frame->retcode;
+		r26 = (unsigned long) frame->retcode;
 	}
 
+	if (err)
+		goto give_sigsegv;
+
 	/* "Return" to the handler */
+	regs->r26 = r26;
 	regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
 	regs->r16 = sig;			  /* a0: signal number */
 	regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
@@ -504,8 +533,9 @@
 	return;
 
 give_sigsegv:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.1.105/linux/arch/alpha/mm/fault.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/mm/fault.c	Tue Jun  9 13:34:23 1998
@@ -114,8 +114,8 @@
 	   (or is suppressed by the PALcode).  Support that for older cpu's
 	   by ignoring such an instruction.  */
 	if (cause == 0) {
-		/* No need for get_user.. we know the insn is there.  */
-		unsigned int insn = *(unsigned int *)regs->pc;
+		unsigned int insn;
+		__get_user(insn, (unsigned int *)regs->pc);
 		if ((insn >> 21 & 0x1f) == 0x1f &&
 		    /* ldq ldl ldt lds ldg ldf ldwu ldbu */
 		    (1ul << (insn >> 26) & 0x30f00001400ul)) {
@@ -124,8 +124,8 @@
 		}
 	}
 
-	lock_kernel();
 	down(&mm->mmap_sem);
+	lock_kernel();
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.1.105/linux/arch/alpha/mm/init.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/mm/init.c	Sat Jun 13 12:48:10 1998
@@ -28,6 +28,67 @@
 
 struct thread_struct * original_pcb_ptr;
 
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
+
+void __bad_pmd(pgd_t *pgd)
+{
+	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+	pgd_set(pgd, BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+	pmd_t *pmd;
+
+	pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+	if (pgd_none(*pgd)) {
+		if (pmd) {
+			clear_page((unsigned long)pmd);
+			pgd_set(pgd, pmd);
+			return pmd + offset;
+		}
+		pgd_set(pgd, BAD_PAGETABLE);
+		return NULL;
+	}
+	free_page((unsigned long)pmd);
+	if (pgd_bad(*pgd)) {
+		__bad_pmd(pgd);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			clear_page((unsigned long)pte);
+			pmd_set(pmd, pte);
+			return pte + offset;
+		}
+		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	free_page((unsigned long)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -56,7 +117,7 @@
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
-	int shared = 0;
+	int shared = 0, cached = 0;
 
 	printk("\nMem-info:\n");
 	show_free_areas();
@@ -66,6 +127,8 @@
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
+		else if (PageSwapCache(mem_map+i))
+			cached++;
 		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
@@ -75,6 +138,8 @@
 	printk("%d free pages\n",free);
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
+	printk("%d pages swap cached\n",cached);
+	printk("%d pages in page table cache\n",pgtable_cache_size);
 	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
@@ -213,16 +278,16 @@
 
 void free_initmem (void)
 {
-        extern char __init_begin, __init_end;
-        unsigned long addr;
+	extern char __init_begin, __init_end;
+	unsigned long addr;
 
-        addr = (unsigned long)(&__init_begin);
-        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-                mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-                atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-                free_page(addr);
-        }
-        printk ("Freeing unused kernel memory: %ldk freed\n",
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+		free_page(addr);
+	}
+	printk ("Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
 
diff -u --recursive --new-file v2.1.105/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.1.105/linux/arch/arm/kernel/sys_arm.c	Fri May  8 23:14:42 1998
+++ linux/arch/arm/kernel/sys_arm.c	Sat Jun 13 11:36:52 1998
@@ -309,16 +309,20 @@
 asmlinkage int sys_uname (struct old_utsname * name)
 {
 	static int warned = 0;
-
+	int err;
+	
 	if (warned == 0) {
 		warned ++;
 		printk (KERN_NOTICE "%s (%d): obsolete uname call\n",
 			current->comm, current->pid);
 	}
 
-	if (name && !copy_to_user (name, &system_utsname, sizeof (*name)))
-		return 0;
-	return -EFAULT;
+	if(!name)
+		return -EFAULT;
+	down(&uts_sem);
+	err=copy_to_user (name, &system_utsname, sizeof (*name));
+	up(&uts_sem);
+	return err?-EFAULT:0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -338,6 +342,8 @@
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
 
+	down(&uts_sem);
+	
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
 	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -348,6 +354,9 @@
 	error -= __put_user(0,name->version+__OLD_UTS_LEN);
 	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error -= __put_user(0,name->machine+__OLD_UTS_LEN);
+	
+	up(&uts_sem);
+	
 	error = error ? -EFAULT : 0;
 
 	return error;
diff -u --recursive --new-file v2.1.105/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.1.105/linux/arch/i386/boot/setup.S	Mon Feb 23 18:12:02 1998
+++ linux/arch/i386/boot/setup.S	Wed Jun 10 14:01:49 1998
@@ -531,6 +531,24 @@
 	out	#0x60,al
 	call	empty_8042
 
+! wait until a20 really *is* enabled; it can take a fair amount of
+! time on any
+	
+	push	ds
+	push	es
+	xor	ax,ax			! segment 0x0000
+	mov	ds,ax
+	dec	ax			! segment 0xffff (HMA)
+	mov	es,ax
+a20_wait:
+	inc	ax
+	mov	[0x7c00],ax		! any unused memory location < 64K
+	seg	es
+	cmp	ax,[0x7c10]		! corresponding HMA address
+	je	a20_wait		! loop until no longer aliased
+	pop	es
+	pop	ds
+		
 ! make sure any possible coprocessor is properly reset..
 
 	xor	ax,ax
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.105/linux/arch/i386/kernel/entry.S	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/entry.S	Tue Jun  9 00:55:09 1998
@@ -546,7 +546,8 @@
 	.long SYMBOL_NAME(sys_getcwd)
 	.long SYMBOL_NAME(sys_capget)
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
+	.long SYMBOL_NAME(sys_sigaltstack)
 	
-	.rept NR_syscalls-185
+	.rept NR_syscalls-186
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.105/linux/arch/i386/kernel/head.S	Wed May 20 19:10:37 1998
+++ linux/arch/i386/kernel/head.S	Wed Jun 10 14:01:52 1998
@@ -104,11 +104,6 @@
  * in 16-bit mode for the "real" operations.
  */
 	call setup_idt
-	xorl %eax,%eax
-1:	incl %eax		# check that A20 really IS enabled
-	movl %eax,0x000000	# loop forever if it isn't
-	cmpl %eax,0x100000
-	je 1b
 /*
  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
  * confuse the debugger if this code is traced.
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.105/linux/arch/i386/kernel/process.c	Sun Jun  7 11:16:27 1998
+++ linux/arch/i386/kernel/process.c	Sat Jun 13 12:48:10 1998
@@ -125,8 +125,10 @@
 		 *	the APM bios knowing only one CPU at a time will do
 		 *	so.
 		 */
-		if (!start_idle) 
+		if (!start_idle) {
+			check_pgt_cache();
 			start_idle = jiffies;
+		}
 		if (jiffies - start_idle > HARD_IDLE_TIMEOUT) 
 			hard_idle();
 		else  {
@@ -158,6 +160,7 @@
 		if(current_cpu_data.hlt_works_ok &&
 		 		!hlt_counter && !need_resched)
 			__asm("hlt");
+		check_pgt_cache();
 		/*
 		 * tq_scheduler currently assumes we're running in a process
 		 * context (ie that we hold the kernel lock..)
@@ -551,9 +554,9 @@
 
 	if ((fpvalid = current->used_math) != 0) {
 		if (boot_cpu_data.hard_math) {
-		  if (last_task_used_math == current) {
-			  __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
-		  }
+			if (last_task_used_math == current) {
+				__asm__("clts ; fsave %0; fwait": :"m" (*fpu));
+			}
 			else
 				memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
 		} else {
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.105/linux/arch/i386/kernel/setup.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/setup.c	Sat Jun 13 11:48:01 1998
@@ -361,7 +361,7 @@
 	{ X86_VENDOR_AMD,	5,
 	  { "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
 	    "K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
-	    "K6 (166 - 266)", "K6 (166 - 300)", "K6-3D (200 - 450)",
+	    "K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)",
 	    "K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_UMC,	4,
 	  { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -442,11 +442,11 @@
 {
 	char *p = buffer;
 	int sep_bug;
-        static const char *x86_cap_flags[] = {
-                "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-                "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
-                "fcmov", "17", "18", "19", "20", "21", "22", "mmx",
-                "osfxsr", "25", "26", "27", "28", "29", "30", "amd3d"
+        static char *x86_cap_flags[] = {
+                "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
+                "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+                "16", "17", "18", "19", "20", "21", "22", "mmx",
+                "24", "25", "26", "27", "28", "29", "30", "31"
         };
 	struct cpuinfo_x86 *c = cpu_data;
 	int i, n;
@@ -473,6 +473,24 @@
 				p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
 		} else
 			p += sprintf(p, "stepping\t: unknown\n");
+
+		/* Modify the capabilities according to chip type */
+		if (c->x86_mask) {
+			if (c->x86_vendor == X86_VENDOR_CYRIX) {
+				x86_cap_flags[24] = "cxmmx";
+			} else if (c->x86_vendor == X86_VENDOR_AMD) {
+				x86_cap_flags[16] = "fcmov";
+				x86_cap_flags[31] = "amd3d";
+			} else if (c->x86_vendor == X86_VENDOR_INTEL) {
+				x86_cap_flags[6] = "pae";
+				x86_cap_flags[9] = "apic";
+				x86_cap_flags[12] = "mtrr";
+				x86_cap_flags[14] = "mca";
+				x86_cap_flags[16] = "pat";
+				x86_cap_flags[17] = "pse";
+				x86_cap_flags[24] = "osfxsr";
+			}
+		}
 
 		sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
 			  c->x86 == 0x06 &&
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.105/linux/arch/i386/kernel/signal.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/i386/kernel/signal.c	Tue Jun  9 13:34:01 1998
@@ -116,6 +116,13 @@
 	return ret;
 }
 
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	struct pt_regs *regs = (struct pt_regs *) &uss;
+	return do_sigaltstack(uss, uoss, regs->esp);
+}
+
 
 /*
  * Do a signal return; undo the signal stack.
@@ -144,7 +151,7 @@
 };
 
 
-static inline void restore_i387_hard(struct _fpstate *buf)
+static inline int restore_i387_hard(struct _fpstate *buf)
 {
 #ifdef __SMP__
 	if (current->flags & PF_USEDFPU) {
@@ -157,31 +164,33 @@
 	}
 #endif
 	current->flags &= ~PF_USEDFPU;
-	__copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
+	return __copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
 }
 
-static inline void restore_i387(struct _fpstate *buf)
+static inline int restore_i387(struct _fpstate *buf)
 {
+	int err;
 #ifndef CONFIG_MATH_EMULATION
-	restore_i387_hard(buf);
+	err = restore_i387_hard(buf);
 #else
 	if (boot_cpu_data.hard_math)
-		restore_i387_hard(buf);
+		err = restore_i387_hard(buf);
 	else
-		restore_i387_soft(&current->tss.i387.soft, buf);
+		err = restore_i387_soft(&current->tss.i387.soft, buf);
 #endif
 	current->used_math = 1;
+	return err;
 }
 
 static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax)
 {
-	unsigned int tmp;
+	unsigned int tmp, err = 0;
 
-#define COPY(x)		__get_user(regs->x, &sc->x)
+#define COPY(x)		err |= __get_user(regs->x, &sc->x)
 
 #define COPY_SEG(seg)							\
-	{ __get_user(tmp, &sc->seg);					\
+	{ err |= __get_user(tmp, &sc->seg);				\
 	  if ((tmp & 0xfffc)		/* not a NULL selectors */	\
 	      && (tmp & 0x4) != 0x4	/* not a LDT selector */	\
 	      && (tmp & 3) != 3)	/* not a RPL3 GDT selector */	\
@@ -189,12 +198,12 @@
 	  regs->x##seg = tmp; }
 
 #define COPY_SEG_STRICT(seg)						\
-	{ __get_user(tmp, &sc->seg);					\
+	{ err |= __get_user(tmp, &sc->seg);				\
 	  if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe;		\
 	  regs->x##seg = tmp; }
 
 #define GET_SEG(seg)							\
-	{ __get_user(tmp, &sc->seg);					\
+	{ err |= __get_user(tmp, &sc->seg);				\
 	  if ((tmp & 0xfffc)		/* not a NULL selectors */	\
 	      && (tmp & 0x4) != 0x4	/* not a LDT selector */	\
 	      && (tmp & 3) != 3)	/* not a RPL3 GDT selector */	\
@@ -216,24 +225,23 @@
 	COPY_SEG_STRICT(cs);
 	COPY_SEG_STRICT(ss);
 	
-	__get_user(tmp, &sc->eflags);
+	err |= __get_user(tmp, &sc->eflags);
 	regs->eflags = (regs->eflags & ~0x40DD5) | (tmp & 0x40DD5);
 	regs->orig_eax = -1;		/* disable syscall checks */
 
-	__get_user(tmp, (unsigned long *)&sc->fpstate);
+	err |= __get_user(tmp, (unsigned long *)&sc->fpstate);
 	if (tmp) {
 		struct _fpstate * buf = (struct _fpstate *) tmp;
 		if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
 			goto badframe;
-		restore_i387(buf);
+		err |= restore_i387(buf);
 	}
 
-	__get_user(tmp, &sc->eax);
-	return tmp;
+	err |= __get_user(*peax, &sc->eax);
+	return err;
 
 badframe:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	return 1;
 }
 
 asmlinkage int sys_sigreturn(unsigned long __unused)
@@ -241,6 +249,7 @@
 	struct pt_regs *regs = (struct pt_regs *) &__unused;
 	struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
 	sigset_t set;
+	int eax;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -256,11 +265,13 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	return restore_sigcontext(regs, &frame->sc);
+	if (restore_sigcontext(regs, &frame->sc, &eax))
+		goto badframe;
+	return eax;
 
 badframe:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }	
 
 asmlinkage int sys_rt_sigreturn(unsigned long __unused)
@@ -268,6 +279,8 @@
 	struct pt_regs *regs = (struct pt_regs *) &__unused;
 	struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4);
 	sigset_t set;
+	stack_t st;
+	int eax;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -280,18 +293,27 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	return restore_sigcontext(regs, &frame->uc.uc_mcontext);
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs->esp);
+
+	return eax;
 
 badframe:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }	
 
 /*
  * Set up a signal frame.
  */
 
-static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
+static inline int save_i387_hard(struct _fpstate * buf)
 {
 #ifdef __SMP__
 	if (current->flags & PF_USEDFPU) {
@@ -308,14 +330,15 @@
 	}
 #endif
 	current->tss.i387.hard.status = current->tss.i387.hard.swd;
-	copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf));
-	return buf;
+	if (__copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf)))
+		return -1;
+	return 1;
 }
 
-static struct _fpstate * save_i387(struct _fpstate *buf)
+static int save_i387(struct _fpstate *buf)
 {
 	if (!current->used_math)
-		return NULL;
+		return 0;
 
 	/* This will cause a "finit" to be triggered by the next
 	   attempted FPU operation by the 'current' process.
@@ -330,98 +353,116 @@
 #endif
 }
 
-static void
+static int
 setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
 		 struct pt_regs *regs, unsigned long mask)
 {
-	unsigned int tmp;
+	int tmp, err = 0;
 
 	tmp = 0;
 	__asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp));
-	__put_user(tmp, (unsigned int *)&sc->gs);
+	err |= __put_user(tmp, (unsigned int *)&sc->gs);
 	__asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp));
-	__put_user(tmp, (unsigned int *)&sc->fs);
+	err |= __put_user(tmp, (unsigned int *)&sc->fs);
 
-	__put_user(regs->xes, (unsigned int *)&sc->es);
-	__put_user(regs->xds, (unsigned int *)&sc->ds);
-	__put_user(regs->edi, &sc->edi);
-	__put_user(regs->esi, &sc->esi);
-	__put_user(regs->ebp, &sc->ebp);
-	__put_user(regs->esp, &sc->esp);
-	__put_user(regs->ebx, &sc->ebx);
-	__put_user(regs->edx, &sc->edx);
-	__put_user(regs->ecx, &sc->ecx);
-	__put_user(regs->eax, &sc->eax);
-	__put_user(current->tss.trap_no, &sc->trapno);
-	__put_user(current->tss.error_code, &sc->err);
-	__put_user(regs->eip, &sc->eip);
-	__put_user(regs->xcs, (unsigned int *)&sc->cs);
-	__put_user(regs->eflags, &sc->eflags);
-	__put_user(regs->esp, &sc->esp_at_signal);
-	__put_user(regs->xss, (unsigned int *)&sc->ss);
-
-	__put_user(save_i387(fpstate), &sc->fpstate);
+	err |= __put_user(regs->xes, (unsigned int *)&sc->es);
+	err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
+	err |= __put_user(regs->edi, &sc->edi);
+	err |= __put_user(regs->esi, &sc->esi);
+	err |= __put_user(regs->ebp, &sc->ebp);
+	err |= __put_user(regs->esp, &sc->esp);
+	err |= __put_user(regs->ebx, &sc->ebx);
+	err |= __put_user(regs->edx, &sc->edx);
+	err |= __put_user(regs->ecx, &sc->ecx);
+	err |= __put_user(regs->eax, &sc->eax);
+	err |= __put_user(current->tss.trap_no, &sc->trapno);
+	err |= __put_user(current->tss.error_code, &sc->err);
+	err |= __put_user(regs->eip, &sc->eip);
+	err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
+	err |= __put_user(regs->eflags, &sc->eflags);
+	err |= __put_user(regs->esp, &sc->esp_at_signal);
+	err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
+
+	tmp = save_i387(fpstate);
+	if (tmp < 0)
+	  err = 1;
+	else
+	  err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
 
 	/* non-iBCS2 extensions.. */
-	__put_user(mask, &sc->oldmask);
-	__put_user(current->tss.cr2, &sc->cr2);
+	err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(current->tss.cr2, &sc->cr2);
+
+	return err;
 }
 
 /*
  * Determine which stack to use..
  */
-static inline unsigned long sigstack_esp(struct k_sigaction *ka, struct pt_regs * regs)
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 {
 	unsigned long esp;
 
 	/* Default to using normal stack */
 	esp = regs->esp;
 
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(esp))
+			esp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
 	/* This is the legacy signal stack switching. */
-	if ((regs->xss & 0xffff) != __USER_DS &&
-	    !(ka->sa.sa_flags & SA_RESTORER) &&
-	    ka->sa.sa_restorer)
+	else if ((regs->xss & 0xffff) != __USER_DS &&
+		 !(ka->sa.sa_flags & SA_RESTORER) &&
+		 ka->sa.sa_restorer) {
 		esp = (unsigned long) ka->sa.sa_restorer;
+	}
 
-	return esp;
+	return (void *)((esp - frame_size) & -8ul);
 }
 
 static void setup_frame(int sig, struct k_sigaction *ka,
 			sigset_t *set, struct pt_regs * regs)
 {
 	struct sigframe *frame;
+	int err = 0;
 
-	frame = (struct sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8);
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto segv_and_exit;
+		goto give_sigsegv;
 
-	__put_user((current->exec_domain
-		    && current->exec_domain->signal_invmap
-		    && sig < 32
-		    ? current->exec_domain->signal_invmap[sig]
-		    : sig),
-		   &frame->sig);
+	err |= __put_user((current->exec_domain
+		           && current->exec_domain->signal_invmap
+		           && sig < 32
+		           ? current->exec_domain->signal_invmap[sig]
+		           : sig),
+		          &frame->sig);
 
-	setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+	err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
 
 	if (_NSIG_WORDS > 1) {
-		__copy_to_user(frame->extramask, &set->sig[1],
-			       sizeof(frame->extramask));
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
 	}
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
-		__put_user(ka->sa.sa_restorer, &frame->pretcode);
+		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	} else {
-		__put_user(frame->retcode, &frame->pretcode);
+		err |= __put_user(frame->retcode, &frame->pretcode);
 		/* This is popl %eax ; movl $,%eax ; int $0x80 */
-		__put_user(0xb858, (short *)(frame->retcode+0));
-		__put_user(__NR_sigreturn, (int *)(frame->retcode+2));
-		__put_user(0x80cd, (short *)(frame->retcode+6));
+		err |= __put_user(0xb858, (short *)(frame->retcode+0));
+		err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
 	}
 
+	if (err)
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->esp = (unsigned long) frame;
 	regs->eip = (unsigned long) ka->sa.sa_handler;
@@ -443,50 +484,59 @@
 
 	return;
 
-segv_and_exit:
-	lock_kernel();
-	do_exit(SIGSEGV);
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
 	struct rt_sigframe *frame;
+	int err = 0;
 
-	frame = (struct rt_sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8);
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto segv_and_exit;
+		goto give_sigsegv;
 
-	__put_user((current->exec_domain
-		    && current->exec_domain->signal_invmap
-		    && sig < 32
-		    ? current->exec_domain->signal_invmap[sig]
-		    : sig),
-		   &frame->sig);
-	__put_user(&frame->info, &frame->pinfo);
-	__put_user(&frame->uc, &frame->puc);
-	__copy_to_user(&frame->info, info, sizeof(*info));
-
-	/* Clear all the bits of the ucontext we don't use.  */
-	__clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
-	setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
-			 regs, set->sig[0]);
-	__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	err |= __put_user((current->exec_domain
+		    	   && current->exec_domain->signal_invmap
+		    	   && sig < 32
+		    	   ? current->exec_domain->signal_invmap[sig]
+			   : sig),
+			  &frame->sig);
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= __copy_to_user(&frame->info, info, sizeof(*info));
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->esp),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+			        regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
-		__put_user(ka->sa.sa_restorer, &frame->pretcode);
+		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	} else {
-		__put_user(frame->retcode, &frame->pretcode);
+		err |= __put_user(frame->retcode, &frame->pretcode);
 		/* This is movl $,%eax ; int $0x80 */
-		__put_user(0xb8, (char *)(frame->retcode+0));
-		__put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
-		__put_user(0x80cd, (short *)(frame->retcode+5));
+		err |= __put_user(0xb8, (char *)(frame->retcode+0));
+		err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
 	}
 
+	if (err)
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->esp = (unsigned long) frame;
 	regs->eip = (unsigned long) ka->sa.sa_handler;
@@ -508,9 +558,10 @@
 
 	return;
 
-segv_and_exit:
-	lock_kernel();
-	do_exit(SIGSEGV);
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 /*
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.105/linux/arch/i386/kernel/smp.c	Sun Jun  7 11:16:27 1998
+++ linux/arch/i386/kernel/smp.c	Sat Jun 13 12:48:10 1998
@@ -597,6 +597,9 @@
 	struct cpuinfo_x86 *c=&cpu_data[id];
 
 	*c = boot_cpu_data;
+	c->pte_quick = 0;
+	c->pgd_quick = 0;
+	c->pgtable_cache_sz = 0;
 	identify_cpu(c);
 	/*
 	 *	Mask B, Pentium, but not Pentium MMX
diff -u --recursive --new-file v2.1.105/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c
--- v2.1.105/linux/arch/i386/kernel/sys_i386.c	Tue Mar 10 10:03:30 1998
+++ linux/arch/i386/kernel/sys_i386.c	Sat Jun 13 11:36:52 1998
@@ -63,6 +63,7 @@
 	struct file * file = NULL;
 	struct mmap_arg_struct a;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
 		goto out;
@@ -73,11 +74,13 @@
 			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
 	if (file)
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -213,9 +216,13 @@
  */
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
-		return 0;
-	return -EFAULT;
+	int err;
+	if (!name)
+		return -EFAULT;
+	down(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up(&uts_sem);
+	return err?-EFAULT:0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -227,6 +234,8 @@
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
   
+  	down(&uts_sem);
+	
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
 	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -237,7 +246,9 @@
 	error |= __put_user(0,name->version+__OLD_UTS_LEN);
 	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-
+	
+	up(&uts_sem);
+	
 	error = error ? -EFAULT : 0;
 
 	return error;
diff -u --recursive --new-file v2.1.105/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- v2.1.105/linux/arch/i386/lib/checksum.c	Tue Apr 14 14:29:20 1998
+++ linux/arch/i386/lib/checksum.c	Thu Jun 11 22:52:33 1998
@@ -8,6 +8,9 @@
  * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
  *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
  *		Tom May, <ftom@netcom.com>
+ *              Pentium Pro/II routines:
+ *              Alexander Kjeldaas <astor@guardian.no>
+ *              Finn Arne Gangstad <finnag@guardian.no>
  *		Lots of code moved from tcp.c and ip.c; see those files
  *		for more names.
  *
@@ -26,6 +29,8 @@
  * computes a partial checksum, e.g. for TCP/UDP fragments
  */
 
+#if CPU!=686
+
 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
 	  /*
 	   * Experiments with ethernet and slip connections show that buff
@@ -97,6 +102,101 @@
 	return(sum);
 }
 
+#else  /* 686 */
+
+unsigned int csum_partial(const unsigned char * buf, int len, unsigned int sum) {
+         __asm__ ("
+            testl $2, %%esi         
+            jnz 30f                 
+10:
+            movl %%ecx, %%edx
+            movl %%ecx, %%ebx
+            andl $0x7c, %%ebx
+            shrl $7, %%ecx
+            addl %%ebx,%%esi
+            shrl $2, %%ebx  
+            negl %%ebx
+            lea 45f(%%ebx,%%ebx,2), %%ebx
+            testl %%esi, %%esi
+            jmp %%ebx
+
+            # Handle 2-byte-aligned regions
+20:         addw (%%esi), %%ax
+            lea 2(%%esi), %%esi
+            adcl $0, %%eax
+            jmp 10b
+
+30:         subl $2, %%ecx          
+            ja 20b                 
+            je 32f
+            movzbl (%%esi),%%ebx # csumming 1 byte, 2-aligned
+            addl %%ebx, %%eax
+            adcl $0, %%eax
+            jmp 80f
+32:
+            addw (%%esi), %%ax # csumming 2 bytes, 2-aligned
+            adcl $0, %%eax
+            jmp 80f
+
+40: 
+	    addl -128(%%esi), %%eax
+            adcl -124(%%esi), %%eax
+            adcl -120(%%esi), %%eax
+            adcl -116(%%esi), %%eax   
+	    adcl -112(%%esi), %%eax   
+            adcl -108(%%esi), %%eax
+            adcl -104(%%esi), %%eax
+            adcl -100(%%esi), %%eax
+            adcl -96(%%esi), %%eax
+            adcl -92(%%esi), %%eax
+            adcl -88(%%esi), %%eax
+            adcl -84(%%esi), %%eax
+            adcl -80(%%esi), %%eax
+            adcl -76(%%esi), %%eax
+            adcl -72(%%esi), %%eax
+            adcl -68(%%esi), %%eax
+	    adcl -64(%%esi), %%eax     
+            adcl -60(%%esi), %%eax     
+            adcl -56(%%esi), %%eax     
+            adcl -52(%%esi), %%eax   
+            adcl -48(%%esi), %%eax   
+            adcl -44(%%esi), %%eax
+            adcl -40(%%esi), %%eax
+            adcl -36(%%esi), %%eax
+            adcl -32(%%esi), %%eax
+            adcl -28(%%esi), %%eax
+            adcl -24(%%esi), %%eax
+            adcl -20(%%esi), %%eax
+            adcl -16(%%esi), %%eax
+            adcl -12(%%esi), %%eax
+            adcl -8(%%esi), %%eax
+            adcl -4(%%esi), %%eax
+45:
+            lea 128(%%esi), %%esi
+            adcl $0, %%eax
+            dec %%ecx
+            jge 40b
+            movl %%edx, %%ecx
+50:         andl $3, %%ecx
+            jz 80f
+
+            # Handle the last 1-3 bytes without jumping
+            notl %%ecx            # 1->2, 2->1, 3->0, higher bits are masked
+	    movl $0xffffff,%%ebx  # by the shll and shrl instructions
+	    shll $3,%%ecx
+	    shrl %%cl,%%ebx
+	    andl -128(%%esi),%%ebx # esi is 4-aligned so should be ok
+	    addl %%ebx,%%eax
+	    adcl $0,%%eax
+80:          "
+        : "=a"(sum)
+        : "0"(sum), "c"(len), "S"(buf)
+        : "bx", "cx", "dx", "si");
+        return(sum);
+}
+
+#endif
+
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
  *
@@ -112,13 +212,15 @@
 "	9999: "#y";			\n \
 	.section __ex_table, \"a\";	\n \
 	.long 9999b, 6001f		\n \
-	.previous"
+	.previous\n"
 
 #define DST(y...)			\
 "	9999: "#y";			\n \
 	.section __ex_table, \"a\";	\n \
 	.long 9999b, 6002f		\n \
-	.previous"
+	.previous\n"
+
+#if CPU!=686
 
 unsigned int csum_partial_copy_generic (const char *src, char *dst,
 				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
@@ -241,6 +343,79 @@
 
     return(sum);
 }
+
+#else /* CPU == 686 */
+
+#define ROUND1(x) \
+        SRC(movl x(%%esi), %%ebx         ) \
+        "addl %%ebx, %%eax\n" \
+        DST(movl %%ebx, x(%%edi)         )
+
+#define ROUND(x) \
+        SRC(movl x(%%esi), %%ebx         ) \
+        "adcl %%ebx, %%eax\n" \
+        DST(movl %%ebx, x(%%edi)         )
+
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+{
+	__asm__ __volatile__ ("
+        movl %%ecx, %%edx  
+        movl %%ecx, %%ebx  
+        shrl $6, %%ecx     
+        andl $0x3c, %%ebx  
+        negl %%ebx
+        subl %%ebx, %%esi  
+        subl %%ebx, %%edi  
+        lea 3f(%%ebx,%%ebx), %%ebx
+        testl %%esi, %%esi 
+        jmp %%ebx         
+1:      addl $64,%%esi
+        addl $64,%%edi\n" 
+ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)
+"3:     adcl $0,%%eax
+        dec %%ecx
+        jge 1b
+4:      andl $3, %%edx
+        jz 7f
+        cmpl $2, %%edx
+        jb 5f
+  " SRC(movw (%%esi), %%dx         )"
+        leal 2(%%esi), %%esi
+  " DST(movw %%dx, (%%edi)         )"
+        leal 2(%%edi), %%edi
+        je 6f
+        shll $16,%%edx
+5:" SRC(movb (%%esi), %%dl         )"
+  " DST(movb %%dl, (%%edi)         )"
+6:      addl %%edx, %%eax
+        adcl $0, %%eax
+7:
+.section .fixup, \"ax\"
+6000:	movl	%7, (%%ebx)
+# FIXME: do zeroing of rest of the buffer here.
+	jmp	7b
+6001:	movl    %1, %%ebx	
+	jmp	6000b	
+6002:	movl    %2, %%ebx
+	jmp	6000b
+.previous
+        "
+	: "=a"(sum), "=m"(src_err_ptr), "=m"(dst_err_ptr)
+        : "0"(sum), "c"(len), "S"(src), "D" (dst),
+		"i" (-EFAULT)
+        : "bx", "cx", "dx", "si", "di" );
+	return(sum);
+}
+
+#undef ROUND
+#undef ROUND1
+
+#endif
+
 
 #undef SRC
 #undef DST
diff -u --recursive --new-file v2.1.105/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.1.105/linux/arch/i386/math-emu/fpu_entry.c	Fri Jan 30 11:28:06 1998
+++ linux/arch/i386/math-emu/fpu_entry.c	Tue Jun  9 00:55:09 1998
@@ -677,14 +677,15 @@
 #define sstatus_word() \
   ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
 
-void restore_i387_soft(void *s387, struct _fpstate *buf)
+int restore_i387_soft(void *s387, struct _fpstate *buf)
 {
   u_char *d = (u_char *)buf;
   int offset, other, i, tags, regnr, tag, newtop;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
-  __copy_from_user(&S387->cwd, d, 7*4);
+  if (__copy_from_user(&S387->cwd, d, 7*4))
+    return -1;
   RE_ENTRANT_CHECK_ON;
 
   d += 7*4;
@@ -695,9 +696,11 @@
 
   RE_ENTRANT_CHECK_OFF;
   /* Copy all registers in stack order. */
-  __copy_from_user(((u_char *)&S387->st_space)+offset, d, other);
+  if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other))
+    return -1;
   if ( offset )
-    __copy_from_user((u_char *)&S387->st_space, d+other, offset);
+    if (__copy_from_user((u_char *)&S387->st_space, d+other, offset))
+      return -1;
   RE_ENTRANT_CHECK_ON;
 
   /* The tags may need to be corrected now. */
@@ -716,10 +719,11 @@
     }
   S387->twd = tags;
 
+  return 0;
 }
 
 
-struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf)
+int save_i387_soft(void *s387, struct _fpstate * buf)
 {
   u_char *d = (u_char *)buf;
   int offset = (S387->ftop & 7) * 10, other = 80 - offset;
@@ -742,10 +746,12 @@
 
   RE_ENTRANT_CHECK_OFF;
   /* Copy all registers in stack order. */
-  __copy_to_user(d, ((u_char *)&S387->st_space)+offset, other);
+  if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other))
+    return -1;
   if ( offset )
-    __copy_to_user(d+other, (u_char *)&S387->st_space, offset);
+    if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset))
+      return -1
   RE_ENTRANT_CHECK_ON;
 
-  return buf;
+  return 1;
 }
diff -u --recursive --new-file v2.1.105/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.105/linux/arch/i386/mm/fault.c	Tue Jan 20 12:52:09 1998
+++ linux/arch/i386/mm/fault.c	Tue Jun  9 16:02:42 1998
@@ -102,11 +102,11 @@
 
 	if (local_irq_count[smp_processor_id()])
 		die_if_kernel("page fault from irq handler",regs,error_code);
-	lock_kernel();
 	tsk = current;
 	mm = tsk->mm;
 
 	down(&mm->mmap_sem);
+
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -151,7 +151,7 @@
 				goto bad_area;
 	}
 	handle_mm_fault(tsk, vma, address, write);
-	up(&mm->mmap_sem);
+
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
 	 */
@@ -160,7 +160,8 @@
 		if (bit < 32)
 			tsk->tss.screen_bitmap |= 1 << bit;
 	}
-	goto out;
+	up(&mm->mmap_sem);
+	return;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -175,7 +176,7 @@
 		tsk->tss.error_code = error_code;
 		tsk->tss.trap_no = 14;
 		force_sig(SIGSEGV, tsk);
-		goto out;
+		return;
 	}
 
 	/*
@@ -187,7 +188,6 @@
 		nr = (address - (unsigned long) idt) >> 3;
 
 		if (nr == 6) {
-			unlock_kernel();
 			do_invalid_op(regs, 0);
 			return;
 		}
@@ -196,7 +196,7 @@
 	/* Are we prepared to handle this kernel fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
 		regs->eip = fixup;
-		goto out;
+		return;
 	}
 
 /*
@@ -215,7 +215,7 @@
 		 * CPU state on certain buggy processors.
 		 */
 		printk("Ok");
-		goto out;
+		return;
 	}
 
 	if (address < PAGE_SIZE)
@@ -234,8 +234,8 @@
 		page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
 		printk(KERN_ALERT "*pte = %08lx\n", page);
 	}
+	lock_kernel();
 	die_if_kernel("Oops", regs, error_code);
 	do_exit(SIGKILL);
-out:
 	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.105/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.105/linux/arch/i386/mm/init.c	Sun Jun  7 11:16:27 1998
+++ linux/arch/i386/mm/init.c	Sat Jun 13 12:48:10 1998
@@ -27,11 +27,66 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 
-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
-
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
+void __bad_pte_kernel(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			clear_page((unsigned long)pte);
+			pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+			return pte + offset;
+		}
+		pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+		return NULL;
+	}
+	free_page((unsigned long)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte_kernel(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	unsigned long pte;
+
+	pte = (unsigned long) __get_free_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			clear_page(pte);
+			pmd_val(*pmd) = _PAGE_TABLE + __pa(pte);
+			return (pte_t *)(pte + offset);
+		}
+		pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+		return NULL;
+	}
+	free_page(pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte(pmd);
+		return NULL;
+	}
+	return (pte_t *) (pmd_page(*pmd) + offset);
+}
+
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -82,7 +137,7 @@
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
-		if (PageSwapCache(mem_map+i))
+		else if (PageSwapCache(mem_map+i))
 			cached++;
 		else if (!atomic_read(&mem_map[i].count))
 			free++;
@@ -93,6 +148,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
+	printk("%ld pages in page table cache\n",pgtable_cache_size);
 	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.1.105/linux/arch/m68k/Makefile	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/Makefile	Sat Jun 13 13:14:31 1998
@@ -64,6 +64,11 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/mac
 endif
 
+ifdef CONFIG_HP300
+CORE_FILES := $(CORE_FILES) arch/m68k/hp300/hp300.o
+SUBDIRS := $(SUBDIRS) arch/m68k/hp300
+endif
+
 ifdef CONFIG_APOLLO
 CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
 SUBDIRS := $(SUBDIRS) arch/m68k/apollo
@@ -72,6 +77,11 @@
 ifdef CONFIG_MVME16x
 CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
 SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
+endif
+
+ifdef CONFIG_BVME6000
+CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
+SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
 endif
 
 ifdef CONFIG_M68040
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile
--- v2.1.105/linux/arch/m68k/amiga/Makefile	Tue Feb 17 13:12:44 1998
+++ linux/arch/m68k/amiga/Makefile	Mon Jun  8 11:03:49 1998
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := amiga.o
-O_OBJS   := config.o amiints.o cia.o chipram.o amisound.o zorro.o
+O_OBJS   := config.o amiints.o cia.o chipram.o amisound.o
 OX_OBJS  := amiga_ksyms.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- v2.1.105/linux/arch/m68k/amiga/zorro.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/amiga/zorro.c	Wed Dec 31 16:00:00 1969
@@ -1,1234 +0,0 @@
-/*
- *    linux/arch/m68k/amiga/zorro.c
- *
- *    Copyright (C) 1995 Geert Uytterhoeven
- *
- *    This file is subject to the terms and conditions of the GNU General Public
- *    License.  See the file COPYING in the main directory of this archive
- *    for more details.
- */
-
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/setup.h>
-#include <asm/bitops.h>
-#include <asm/amigahw.h>
-#include <linux/zorro.h>
-
-
-#ifdef CONFIG_ZORRO
-
-    /*
-     *  Zorro Expansion Device Manufacturers and Products
-     */
-
-struct Manufacturer {
-    const char *Name;
-    u_short Manuf;
-    u_short NumProd;
-    const struct Product *Products;
-};
-
-struct Product {
-    const char *Name;
-    u_char Class;
-    u_char Prod;
-};
-
-struct GVP_Product {
-    const char *Name;
-    u_char Class;
-    u_char EPC;
-};
-
-
-    /*
-     *  Macro's to make life easier
-     */
-
-#define ARRAYSIZE(x)		(sizeof(x)/sizeof(*(x)))
-
-#define BEGIN_PROD(id) \
-    static struct Product Prod_##id[] = {
-#define PROD(name, class, id) \
-    { name, ZORRO_CLASS_##class, ZORRO_PROD(ZORRO_PROD_##id) },
-
-#define BEGIN_GVP_PROD \
-    static struct GVP_Product Ext_Prod_GVP[] = {
-#define GVP_PROD(name, class, id) \
-    { name, ZORRO_CLASS_##class, ZORRO_EPC(ZORRO_PROD_##id) },
-
-#define BEGIN_MANUF \
-    static struct Manufacturer Manufacturers[] = {
-#define MANUF(name, id) \
-    { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id },
-
-#define END \
-    };
-
-
-    /*
-     *  Recognized Zorro Expansion Devices
-     */
-
-BEGIN_PROD(PACIFIC_PERIPHERALS)
-    PROD("SE 2000 A500", HD, PACIFIC_PERIPHERALS_SE_2000_A500)
-    PROD(NULL, SCSI, PACIFIC_PERIPHERALS_SCSI)
-END
-
-BEGIN_PROD(MACROSYSTEMS_USA_2)
-    PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE)
-END
-
-BEGIN_PROD(KUPKE_1)
-    PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB)
-END
-
-BEGIN_PROD(MEMPHIS)
-    PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER)
-END
-
-BEGIN_PROD(3_STATE)
-    PROD("Megamix 2000", RAM, 3_STATE_MEGAMIX_2000)
-END
-
-BEGIN_PROD(COMMODORE_BRAUNSCHWEIG)
-    PROD("A2088 XT/A2286 AT", BRIDGE, CBM_A2088_A2286)
-    PROD("A2286 AT", BRIDGE, CBM_A2286)
-    PROD("A4091", SCSI, CBM_A4091_1)
-    PROD("A2386-SX", BRIDGE, CBM_A2386SX_1)
-END
-
-BEGIN_PROD(COMMODORE_WEST_CHESTER_1)
-    PROD("A2090/A2090A", SCSI, CBM_A2090A)
-    PROD("A590/A2091", SCSI, CBM_A590_A2091_1)
-    PROD("A590/A2091", SCSI, CBM_A590_A2091_2)
-    PROD("A2090B 2090 Autoboot", SCSI, CBM_A2090B)
-    PROD("A2060", ARCNET, CBM_A2060)
-    PROD("A590/A2052/A2058/A2091", RAM, CBM_A590_A2052_A2058_A2091)
-    PROD("A560", RAM, CBM_A560_RAM)
-    PROD("A2232 Prototype", MULTIIO, CBM_A2232_PROTOTYPE)
-    PROD("A2232", MULTIIO, CBM_A2232)
-    PROD("A2620 68020/RAM", TURBO_RAM, CBM_A2620)
-    PROD("A2630 68030/RAM", TURBO_RAM, CBM_A2630)
-    PROD("A4091", SCSI, CBM_A4091_2)
-    PROD("A2065", ETHERNET, CBM_A2065_1)
-    PROD("Romulator Card", UNKNOWN, CBM_ROMULATOR)
-    PROD("A3000 Test Fixture", MISC, CBM_A3000_TEST_FIXTURE)
-    PROD("A2386-SX", BRIDGE, CBM_A2386SX_2)
-    PROD("A2065", ETHERNET, CBM_A2065_2)
-END
-
-BEGIN_PROD(COMMODORE_WEST_CHESTER_2)
-    PROD("A2090/A2090A Combitec/MacroSystem", SCSI, CBM_A2090A_CM)
-END
-
-BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
-    PROD("EXP8000", RAM, PPS_EXP8000)
-END
-
-BEGIN_PROD(KOLFF_COMPUTER_SUPPLIES)
-    PROD("KCS Power PC Board", BRIDGE, KCS_POWER_PC_BOARD)
-END
-
-BEGIN_PROD(CARDCO_1)
-    PROD("Kronos 2000", SCSI, CARDCO_KRONOS_2000_1)
-    PROD("A1000", SCSI, CARDCO_A1000_1)
-    PROD("Escort", SCSI, CARDCO_ESCORT)
-    PROD("A2410 HiRes", GFX, CARDCO_A2410)
-END
-
-BEGIN_PROD(A_SQUARED)
-    PROD("Live! 2000", VIDEO, A_SQUARED_LIVE_2000)
-END
-
-BEGIN_PROD(COMSPEC_COMMUNICATIONS)
-    PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000)
-END
-
-BEGIN_PROD(ANAKIN_RESEARCH)
-    PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL)
-END
-
-BEGIN_PROD(MICROBOTICS)
-    PROD("StarBoard II", RAM, MICROBOTICS_STARBOARD_II)
-    PROD("StarDrive", SCSI, MICROBOTICS_STARDRIVE)
-    PROD("8-Up (Rev A)", RAM, MICROBOTICS_8_UP_A)
-    PROD("8-Up (Rev Z)", RAM, MICROBOTICS_8_UP_Z)
-    PROD("Delta", RAM, MICROBOTICS_DELTA_RAM)
-    PROD("8-Star", RAM, MICROBOTICS_8_STAR_RAM)
-    PROD("8-Star", MISC, MICROBOTICS_8_STAR)
-    PROD("VXL RAM*32", RAM, MICROBOTICS_VXL_RAM_32)
-    PROD("VXL-30", TURBO, MICROBOTICS_VXL_68030)
-    PROD("Delta", MISC, MICROBOTICS_DELTA)
-    PROD("MBX 1200/1200z", RAM, MICROBOTICS_MBX_1200_1200Z_RAM)
-    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_1)
-    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_2)
-    PROD("MBX 1200/1200z", MISC, MICROBOTICS_MBX_1200_1200Z)
-END
-
-BEGIN_PROD(ACCESS_ASSOCIATES_ALEGRA)
-END
-
-BEGIN_PROD(EXPANSION_TECHNOLOGIES)
-END
-
-BEGIN_PROD(ASDG)
-    PROD(NULL, RAM, ASDG_MEMORY_1)
-    PROD(NULL, RAM, ASDG_MEMORY_2)
-    PROD("EB-920 Lan Rover", ETHERNET, ASDG_EB920_LAN_ROVER)
-    PROD("GPIB/Dual IEEE-488/Twin-X", MULTIIO, ASDG_GPIB_DUALIEEE488_TWIN_X)
-END
-
-BEGIN_PROD(IMTRONICS_1)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2)
-END
-
-BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL)
-    PROD("A2410 HiRes", GFX, CBM_A2410)
-END
-
-BEGIN_PROD(AMERISTAR)
-    PROD("A2065", ETHERNET, AMERISTAR_A2065)
-    PROD("A560", ARCNET, AMERISTAR_A560)
-    PROD("A4066", ETHERNET, AMERISTAR_A4066)
-END
-
-BEGIN_PROD(SUPRA)
-    PROD("SupraDrive 4x4", SCSI, SUPRA_SUPRADRIVE_4x4)
-    PROD("1000", RAM, SUPRA_1000_RAM)
-    PROD("2000 DMA", SCSI, SUPRA_2000_DMA)
-    PROD("500", SCSI_RAM, SUPRA_500)
-    PROD("500", SCSI, SUPRA_500_SCSI)
-    PROD("500XP/2000", RAM, SUPRA_500XP_2000_RAM)
-    PROD("500RX/2000", RAM, SUPRA_500RX_2000_RAM)
-    PROD("2400zi", MODEM, SUPRA_2400ZI)
-    PROD("500XP/SupraDrive WordSync", SCSI, SUPRA_500XP_SUPRADRIVE_WORDSYNC)
-    PROD("SupraDrive WordSync II", SCSI, SUPRA_SUPRADRIVE_WORDSYNC_II)
-    PROD("2400zi+", MODEM, SUPRA_2400ZIPLUS)
-END
-
-BEGIN_PROD(COMPUTER_SYSTEMS_ASSOCIATES)
-    PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM)
-    PROD("12 Gauge", SCSI, CSA_12_GAUGE)
-END
-
-BEGIN_PROD(MARC_MICHAEL_GROTH)
-END
-
-BEGIN_PROD(M_TECH)
-    PROD("AT500", RAM, MTEC_AT500_1)
-END
-
-BEGIN_PROD(GREAT_VALLEY_PRODUCTS_1)
-    PROD("Impact Series I", SCSI_RAM, GVP_IMPACT_SERIES_I)
-END
-
-BEGIN_PROD(BYTEBOX)
-    PROD("A500", UNKNOWN, BYTEBOX_A500)
-END
-
-BEGIN_PROD(DKB_POWER_COMPUTING)
-    PROD("SecureKey", UNKNOWN, DKB_POWER_COMPUTING_SECUREKEY)
-    PROD("DKM 3128", RAM, DKB_POWER_COMPUTING_DKM_3128)
-    PROD("Rapid Fire", SCSI, DKB_POWER_COMPUTING_RAPID_FIRE)
-    PROD("DKM 1202", FPU_RAM, DKB_POWER_COMPUTING_DKM_1202)
-    PROD("Cobra/Viper II 68EC030", TURBO, DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030)
-    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_1)
-    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_2)
-END
-
-BEGIN_PROD(GREAT_VALLEY_PRODUCTS_2)
-    PROD("Impact Series I (4K)", SCSI, GVP_IMPACT_SERIES_I_4K)
-    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_2)
-    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_3)
-    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_1)
-    PROD("Impact 3001", RAM, GVP_IMPACT_3001_RAM)
-    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_1)
-/*  PROD(NULL, UNKNOWN, GVP_EPC_BASE) */
-    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_2)
-/*  PROD("A2000 030", TURBO, GVP_A2000_030) */
-/*  PROD("GForce 040", TURBO_SCSI, GFORCE_040_SCSI_2) */
-    PROD("GForce 040/060", TURBO_SCSI, GVP_GFORCE_040_060)
-    PROD("Impact Vision 24", GFX, GVP_IMPACT_VISION_24)
-    PROD("GForce 040", TURBO, GVP_GFORCE_040_2)
-END
-
-BEGIN_GVP_PROD					/* ZORRO_PROD_GVP_EPC_BASE */
-    GVP_PROD("GForce 040", TURBO, GVP_GFORCE_040_1)
-    GVP_PROD("GForce 040", TURBO_SCSI, GVP_GFORCE_040_SCSI_1)
-    GVP_PROD("A1291", SCSI, GVP_A1291)
-    GVP_PROD("Combo 030 R4", TURBO, GVP_COMBO_030_R4)
-    GVP_PROD("Combo 030 R4", TURBO_SCSI, GVP_COMBO_030_R4_SCSI)
-    GVP_PROD("Phone Pak", UNKNOWN, GVP_PHONEPAK)
-    GVP_PROD("IO-Extender", MULTIIO, GVP_IO_EXTENDER)
-    GVP_PROD("GForce 030", TURBO, GVP_GFORCE_030)
-    GVP_PROD("GForce 030", TURBO_SCSI, GVP_GFORCE_030_SCSI)
-    GVP_PROD("A530", TURBO, GVP_A530)
-    GVP_PROD("A530", TURBO_SCSI, GVP_A530_SCSI)
-    GVP_PROD("Combo 030 R3", TURBO, GVP_COMBO_030_R3)
-    GVP_PROD("Combo 030 R3", TURBO_SCSI, GVP_COMBO_030_R3_SCSI)
-    GVP_PROD("Series-II", SCSI, GVP_SERIES_II)
-END
-
-BEGIN_PROD(CALIFORNIA_ACCESS_SYNERGY)
-    PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU)
-END
-
-BEGIN_PROD(XETEC)
-    PROD("FastCard", SCSI, XETEC_FASTCARD)
-    PROD("FastCard", RAM, XETEC_FASTCARD_RAM)
-    PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS)
-END
-
-BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
-    PROD("Mercury", TURBO, PPS_MERCURY)
-    PROD("A3000 68040", TURBO, PPS_A3000_68040)
-    PROD("A2000 68040", TURBO, PPS_A2000_68040)
-    PROD("Zeus", TURBO_SCSI_RAM, PPS_ZEUS)
-    PROD("A500 68040", TURBO, PPS_A500_68040)
-END
-
-BEGIN_PROD(XEBEC)
-END
-
-BEGIN_PROD(SPIRIT_TECHNOLOGY)
-    PROD("Insider IN1000", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN1000)
-    PROD("Insider IN500", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN500)
-    PROD("SIN500", RAM, SPIRIT_TECHNOLOGY_SIN500)
-    PROD("HDA 506", HD, SPIRIT_TECHNOLOGY_HDA_506)
-    PROD("AX-S", MISC, SPIRIT_TECHNOLOGY_AX_S)
-    PROD("OctaByte", RAM, SPIRIT_TECHNOLOGY_OCTABYTE)
-    PROD("Inmate", SCSI_RAM, SPIRIT_TECHNOLOGY_INMATE)
-END
-
-BEGIN_PROD(SPIRIT_TECHNOLOGY_2)
-END
-
-BEGIN_PROD(BSC_ALFADATA_1)
-    PROD("ALF 3", SCSI, BSC_ALF_3_1)
-END
-
-BEGIN_PROD(BSC_ALFADATA_2)
-    PROD("ALF 2", SCSI, BSC_ALF_2_1)
-    PROD("ALF 2", SCSI, BSC_ALF_2_2)
-    PROD("ALF 3", SCSI, BSC_ALF_3_2)
-END
-
-BEGIN_PROD(CARDCO_2)
-    PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2)
-    PROD("A1000", SCSI, CARDCO_A1000_2)
-END
-
-BEGIN_PROD(JOCHHEIM)
-    PROD(NULL, RAM, JOCHHEIM_RAM)
-END
-
-BEGIN_PROD(CHECKPOINT_TECHNOLOGIES)
-    PROD("Serial Solution", SERIAL, CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION)
-END
-
-BEGIN_PROD(EDOTRONIK)
-    PROD("IEEE-488 Interface Board", UNKNOWN, EDOTRONIK_IEEE_488)
-    PROD("CBM-8032 Board", UNKNOWN, EDOTRONIK_8032)
-    PROD(NULL, SERIAL, EDOTRONIK_MULTISERIAL)
-    PROD("24Bit Realtime Video Digitizer", UNKNOWN, EDOTRONIK_VIDEODIGITIZER)
-    PROD("32Bit Parallel I/O Interface", UNKNOWN, EDOTRONIK_PARALLEL_IO)
-    PROD("PIC Prototyping Board", UNKNOWN, EDOTRONIK_PIC_PROTOYPING)
-    PROD("16 Channel ADC Interface", UNKNOWN, EDOTRONIK_ADC)
-    PROD("VME-Bus Controller", UNKNOWN, EDOTRONIK_VME)
-    PROD("DSP96000 Realtime Data Acquisition", DSP, EDOTRONIK_DSP96000)
-END
-
-BEGIN_PROD(NES_INC)
-    PROD(NULL, RAM, NES_INC_RAM)
-END
-
-BEGIN_PROD(ICD)
-    PROD("Advantage 2000", SCSI, ICD_ADVANTAGE_2000_SCSI)
-    PROD("Advantage", IDE, ICD_ADVANTAGE_2000_SCSI)
-    PROD("Advantage 2080", RAM, ICD_ADVANTAGE_2080_RAM)
-END
-
-BEGIN_PROD(KUPKE_2)
-    PROD("Omti", HD, KUPKE_OMTI)
-    PROD("Golem SCSI-II", SCSI, KUPKE_SCSI_II)
-    PROD("Golem Box", UNKNOWN, KUPKE_GOLEM_BOX)
-    PROD("030/882", TURBO, KUPKE_030_882)
-    PROD("Golem", SCSI, KUPKE_SCSI_AT)
-END
-
-BEGIN_PROD(GREAT_VALLEY_PRODUCTS_3)
-    PROD("A2000-RAM8/2", MISC, GVP_A2000_RAM8)
-    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_2)
-END
-
-BEGIN_PROD(INTERWORKS_NETWORK)
-END
-
-BEGIN_PROD(HARDITAL_SYNTHESIS)
-    PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882)
-END
-
-BEGIN_PROD(APPLIED_ENGINEERING)
-    PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000)
-    PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS)
-END
-
-BEGIN_PROD(BSC_ALFADATA_3)
-    PROD("Oktagon 2008", SCSI, BSC_OKTAGON_2008)
-    PROD("Tandem AT-2008/508", IDE, BSC_TANDEM_AT_2008_508)
-    PROD("Alpha RAM 1200", RAM, BSC_ALFA_RAM_1200)
-    PROD("Oktagon 2008", RAM, BSC_OKTAGON_2008_RAM)
-    PROD("MultiFace I", MULTIIO, BSC_MULTIFACE_I)
-    PROD("MultiFace II", MULTIIO, BSC_MULTIFACE_II)
-    PROD("MultiFace III", MULTIIO, BSC_MULTIFACE_III)
-    PROD("Framebuffer", MISC, BSC_FRAMEBUFFER)
-    PROD("Graffiti", GFXRAM, BSC_GRAFFITI_RAM)
-    PROD("Graffiti", GFX, BSC_GRAFFITI_REG)
-    PROD("ISDN MasterCard", ISDN, BSC_ISDN_MASTERCARD)
-    PROD("ISDN MasterCard II", ISDN, BSC_ISDN_MASTERCARD_II)
-END
-
-BEGIN_PROD(PHOENIX)
-    PROD("ST506", HD, PHOENIX_ST506)
-    PROD(NULL, SCSI, PHOENIX_SCSI)
-    PROD(NULL, RAM, PHOENIX_RAM)
-END
-
-BEGIN_PROD(ADVANCED_STORAGE_SYSTEMS)
-    PROD("Nexus", SCSI, ADVANCED_STORAGE_SYSTEMS_NEXUS)
-    PROD("Nexus", RAM, ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM)
-END
-
-BEGIN_PROD(IMPULSE)
-    PROD("FireCracker 24", GFX, IMPULSE_FIRECRACKER_24)
-END
-
-BEGIN_PROD(IVS)
-    PROD("GrandSlam PIC 2", RAM, IVS_GRANDSLAM_PIC_2)
-    PROD("GrandSlam PIC 1", RAM, IVS_GRANDSLAM_PIC_1)
-    PROD("OverDrive", HD, IVS_OVERDRIVE)
-    PROD("TrumpCard Classic", SCSI, IVS_TRUMPCARD_CLASSIC)
-    PROD("TrumpCard Pro/GrandSlam", SCSI, IVS_TRUMPCARD_PRO_GRANDSLAM)
-    PROD("Meta-4", RAM, IVS_META_4)
-    PROD("Wavetools", AUDIO, IVS_WAVETOOLS)
-    PROD("Vector", SCSI, IVS_VECTOR_1)
-    PROD("Vector", SCSI, IVS_VECTOR_2)
-END
-
-BEGIN_PROD(VECTOR_1)
-    PROD("Connection", MULTIIO, VECTOR_CONNECTION_1)
-END
-
-BEGIN_PROD(XPERT_PRODEV)
-    PROD("Visiona", GFXRAM, XPERT_PRODEV_VISIONA_RAM)
-    PROD("Visiona", GFX, XPERT_PRODEV_VISIONA_REG)
-    PROD("Merlin", GFXRAM, XPERT_PRODEV_MERLIN_RAM)
-    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_1)
-    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_2)
-END
-
-BEGIN_PROD(HYDRA_SYSTEMS)
-    PROD("Amiganet", ETHERNET, HYDRA_SYSTEMS_AMIGANET)
-END
-
-BEGIN_PROD(SUNRIZE_INDUSTRIES)
-    PROD("AD1012", AUDIO, SUNRIZE_INDUSTRIES_AD1012)
-    PROD("AD516", AUDIO, SUNRIZE_INDUSTRIES_AD516)
-    PROD("DD512", AUDIO, SUNRIZE_INDUSTRIES_DD512)
-END
-
-BEGIN_PROD(TRICERATOPS)
-    PROD(NULL, MULTIIO, TRICERATOPS_MULTI_IO)
-END
-
-BEGIN_PROD(APPLIED_MAGIC)
-    PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER)
-    PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER)
-END
-
-BEGIN_PROD(GFX_BASE)
-    PROD("GDA-1 VRAM", GFX, GFX_BASE_GDA_1_VRAM)
-    PROD("GDA-1", GFX, GFX_BASE_GDA_1)
-END
-
-BEGIN_PROD(ROCTEC)
-    PROD("RH 800C", HD, ROCTEC_RH_800C)
-    PROD("RH 800C", RAM, ROCTEC_RH_800C_RAM)
-END
-
-BEGIN_PROD(KATO)
-    PROD("Melody MPEG", AUDIO, KATO_MELODY)
-    PROD("Rainbow II", GFX, HELFRICH_RAINBOW_II)	/* ID clash!! */
-    PROD("Rainbow III", GFX, HELFRICH_RAINBOW_III)	/* ID clash!! */
-END
-
-BEGIN_PROD(ATLANTIS)
-END
-
-BEGIN_PROD(PROTAR)
-END
-
-BEGIN_PROD(ACS)
-END
-
-BEGIN_PROD(SOFTWARE_RESULTS_ENTERPRISES)
-    PROD("Golden Gate 2 Bus+", BRIDGE, SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS)
-END
-
-BEGIN_PROD(MASOBOSHI)
-    PROD("MasterCard SC201", RAM, MASOBOSHI_MASTER_CARD_SC201)
-    PROD("MasterCard MC702", SCSI_IDE, MASOBOSHI_MASTER_CARD_MC702)
-    PROD("MVD 819", UNKNOWN, MASOBOSHI_MVD_819)
-END
-
-BEGIN_PROD(MAINHATTAN_DATA)
-    PROD(NULL, IDE, MAINHATTAN_DATA_IDE)
-END
-
-BEGIN_PROD(VILLAGE_TRONIC)
-    PROD("Domino", GFXRAM, VILLAGE_TRONIC_DOMINO_RAM)
-    PROD("Domino", GFX, VILLAGE_TRONIC_DOMINO_REG)
-    PROD("Domino 16M Prototype", GFX, VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE)
-    PROD("Picasso II/II+", GFXRAM, VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM)
-    PROD("Picasso II/II+", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG)
-    PROD("Picasso II/II+ (Segmented Mode)", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE)
-    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1)
-    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2)
-    PROD("Picasso IV Z2", GFX, VILLAGE_TRONIC_PICASSO_IV_Z2_REG)
-    PROD("Picasso IV Z3", GFX, VILLAGE_TRONIC_PICASSO_IV_Z3)
-    PROD("Ariadne", ETHERNET_PARALLEL, VILLAGE_TRONIC_ARIADNE)
-END
-
-BEGIN_PROD(UTILITIES_UNLIMITED)
-    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE)
-    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE2)
-END
-
-BEGIN_PROD(AMITRIX)
-    PROD(NULL, MULTIIO, AMITRIX_MULTI_IO)
-    PROD("CD-RAM", RAM, AMITRIX_CD_RAM)
-END
-
-BEGIN_PROD(ARMAX)
-    PROD("OmniBus", GFX, ARMAX_OMNIBUS)
-END
-
-BEGIN_PROD(NEWTEK)
-    PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER)
-END
-
-BEGIN_PROD(M_TECH_GERMANY)
-    PROD("AT500", IDE, MTEC_AT500_2)
-    PROD("68030", TURBO, MTEC_68030)
-    PROD("68020i", TURBO, MTEC_68020I)
-    PROD("A1200 T68030 RTC", TURBO, MTEC_A1200_T68030_RTC)
-    PROD("Viper Mk V/E-Matrix 530", TURBO_RAM, MTEC_VIPER_MK_V_E_MATRIX_530)
-    PROD("8MB", RAM, MTEC_8_MB_RAM)
-    PROD("Viper Mk V/E-Matrix 530 SCSI/IDE", SCSI_IDE, MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE)
-END
-
-BEGIN_PROD(GREAT_VALLEY_PRODUCTS_4)
-    PROD("EGS 28/24 Spectrum", GFX, GVP_EGS_28_24_SPECTRUM_REG)
-    PROD("EGS 28/24 Spectrum", GFXRAM, GVP_EGS_28_24_SPECTRUM_RAM)
-END
-
-BEGIN_PROD(APOLLO_1)
-    PROD("A1200", FPU_RAM, APOLLO_A1200)
-END
-
-BEGIN_PROD(HELFRICH_2)
-    PROD("Piccolo", GFXRAM, HELFRICH_PICCOLO_RAM)
-    PROD("Piccolo", GFX, HELFRICH_PICCOLO_REG)
-    PROD("PeggyPlus MPEG", VIDEO, HELFRICH_PEGGY_PLUS_MPEG)
-    PROD("VideoCruncher", VIDEO, HELFRICH_VIDEOCRUNCHER)
-    PROD("Piccolo SD64", GFXRAM, HELFRICH_SD64_RAM)
-    PROD("Piccolo SD64", GFX, HELFRICH_SD64_REG)
-END
-
-BEGIN_PROD(MACROSYSTEMS_USA)
-    PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx)
-END
-
-BEGIN_PROD(ELBOX_COMPUTER)
-    PROD("1200/4", RAM, ELBOX_COMPUTER_1200_4)
-END
-
-BEGIN_PROD(HARMS_PROFESSIONAL)
-    PROD("030 Plus", TURBO, HARMS_PROFESSIONAL_030_PLUS)
-    PROD("3500 Professional", TURBO_RAM, HARMS_PROFESSIONAL_3500)
-END
-
-BEGIN_PROD(MICRONIK)
-    PROD("RCA 120", RAM, MICRONIK_RCA_120)
-END
-
-BEGIN_PROD(MICRONIK2)
-    PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I)
-END
-
-BEGIN_PROD(MEGAMICRO)
-    PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500)
-    PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM)
-END
-
-BEGIN_PROD(IMTRONICS_2)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_3)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_4)
-END
-
-BEGIN_PROD(INDIVIDUAL_COMPUTERS)
-    PROD("Buddha", IDE, INDIVIDUAL_COMPUTERS_BUDDHA)
-    PROD("Catweasel", IDE_FLOPPY, INDIVIDUAL_COMPUTERS_CATWEASEL)
-END
-
-BEGIN_PROD(KUPKE_3)
-    PROD("Golem HD 3000", HD, KUPKE_GOLEM_HD_3000)
-END
-
-BEGIN_PROD(ITH)
-    PROD("ISDN-Master II", ISDN, ITH_ISDN_MASTER_II)
-END
-
-BEGIN_PROD(VMC)
-    PROD("ISDN Blaster Z2", ISDN, VMC_ISDN_BLASTER_Z2)
-    PROD("HyperCom 4", MULTIIO, VMC_HYPERCOM_4)
-END
-
-BEGIN_PROD(INFORMATION)
-    PROD("ISDN Engine I", ISDN, INFORMATION_ISDN_ENGINE_I)
-END
-
-BEGIN_PROD(VORTEX)
-    PROD("Golden Gate 80386SX", BRIDGE, VORTEX_GOLDEN_GATE_80386SX)
-    PROD("Golden Gate", RAM, VORTEX_GOLDEN_GATE_RAM)
-    PROD("Golden Gate 80486", BRIDGE, VORTEX_GOLDEN_GATE_80486)
-END
-
-BEGIN_PROD(EXPANSION_SYSTEMS)
-    PROD("DataFlyer 4000SX", SCSI, EXPANSION_SYSTEMS_DATAFLYER_4000SX)
-    PROD("DataFlyer 4000SX", RAM, EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM)
-END
-
-BEGIN_PROD(READYSOFT)
-    PROD("AMax II/IV", MACEMU, READYSOFT_AMAX_II_IV)
-END
-
-BEGIN_PROD(PHASE5)
-    PROD("Blizzard", RAM, PHASE5_BLIZZARD_RAM)
-    PROD("Blizzard", TURBO, PHASE5_BLIZZARD)
-    PROD("Blizzard 1220-IV", TURBO, PHASE5_BLIZZARD_1220_IV)
-    PROD("FastLane Z3", RAM, PHASE5_FASTLANE_Z3_RAM)
-    PROD("Blizzard 1230-II/Fastlane Z3/CyberSCSI/CyberStorm060", TURBO_SCSI, PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060)
-    PROD("Blizzard 1220/CyberStorm", TURBO_SCSI, PHASE5_BLIZZARD_1220_CYBERSTORM)
-    PROD("Blizzard 1230", TURBO, PHASE5_BLIZZARD_1230)
-    PROD("Blizzard 1230-IV/1260", TURBO, PHASE5_BLIZZARD_1230_IV_1260)
-    PROD("Blizzard 2060", TURBO, PHASE5_BLIZZARD_2060)
-    PROD("CyberStorm Mk II", FLASHROM, PHASE5_CYBERSTORM_MK_II)
-    PROD("CyberVision64", GFX, PHASE5_CYBERVISION64)
-    PROD("CyberVision64-3D Prototype", GFX, PHASE5_CYBERVISION64_3D_PROTOTYPE)
-    PROD("CyberVision64-3D", GFX, PHASE5_CYBERVISION64_3D)
-    PROD("CyberStorm Mk III", TURBO_SCSI, PHASE5_CYBERSTORM_MK_III)
-END
-
-BEGIN_PROD(DPS)
-    PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER)
-END
-
-BEGIN_PROD(APOLLO_2)
-    PROD("A620 68020", TURBO, APOLLO_A620_68020_1)
-    PROD("A620 68020", TURBO, APOLLO_A620_68020_2)
-END
-
-BEGIN_PROD(APOLLO_3)
-    PROD("AT-Apollo", UNKNOWN, APOLLO_AT_APOLLO)
-    PROD("1230/1240/1260/2030/4040/4060", TURBO, APOLLO_1230_1240_1260_2030_4040_4060)
-END
-
-BEGIN_PROD(PETSOFF_LP)
-    PROD("Delfina", AUDIO, PETSOFF_LP_DELFINA)
-    PROD("Delfina Lite", AUDIO, PETSOFF_LP_DELFINA_LITE)
-END
-
-BEGIN_PROD(UWE_GERLACH)
-    PROD("RAM/ROM", MISC, UWE_GERLACH_RAM_ROM)
-END
-
-BEGIN_PROD(MACROSYSTEMS_GERMANY)
-    PROD("Maestro", AUDIO, MACROSYSTEMS_MAESTRO)
-    PROD("VLab", VIDEO, MACROSYSTEMS_VLAB)
-    PROD("Maestro Pro", AUDIO, MACROSYSTEMS_MAESTRO_PRO)
-    PROD("Retina", GFX, MACROSYSTEMS_RETINA)
-    PROD("MultiEvolution", SCSI, MACROSYSTEMS_MULTI_EVOLUTION)
-    PROD("Toccata", AUDIO, MACROSYSTEMS_TOCCATA)
-    PROD("Retina Z3", GFX, MACROSYSTEMS_RETINA_Z3)
-    PROD("VLab Motion", VIDEO, MACROSYSTEMS_VLAB_MOTION)
-    PROD("Altais", GFX, MACROSYSTEMS_ALTAIS)
-    PROD("Falcon '040", TURBO, MACROSYSTEMS_FALCON_040)
-END
-
-BEGIN_PROD(COMBITEC)
-END
-
-BEGIN_PROD(SKI_PERIPHERALS)
-    PROD("MAST Fireball", SCSI, SKI_PERIPHERALS_MAST_FIREBALL)
-    PROD("SCSI/Dual Serial", SCSI_SERIAL, SKI_PERIPHERALS_SCSI_DUAL_SERIAL)
-END
-
-BEGIN_PROD(REIS_WARE_2)
-    PROD("Scan King", SCANNER, REIS_WARE_SCAN_KING)
-END
-
-BEGIN_PROD(CAMERON)
-    PROD("Personal A4", SCANNER, CAMERON_PERSONAL_A4)
-END
-
-BEGIN_PROD(REIS_WARE)
-    PROD("Handyscanner", SCANNER, REIS_WARE_HANDYSCANNER)
-END
-
-BEGIN_PROD(PHOENIX_2)
-    PROD("ST506", HD, PHOENIX_ST506_2)
-    PROD(NULL, SCSI, PHOENIX_SCSI_2)
-    PROD(NULL, RAM, PHOENIX_RAM_2)
-END
-
-BEGIN_PROD(COMBITEC_2)
-    PROD(NULL, HD, COMBITEC_HD)
-    PROD("SRAM", RAM, COMBITEC_SRAM)
-END
-
-BEGIN_PROD(HACKER)	/* Unused */
-END
-
-
-BEGIN_MANUF
-    MANUF("Pacific Peripherals", PACIFIC_PERIPHERALS)
-    MANUF("MacroSystems USA", MACROSYSTEMS_USA_2)
-    MANUF("Kupke", KUPKE_1)
-    MANUF("Memphis", MEMPHIS)
-    MANUF("3-State", 3_STATE)
-    MANUF("Commodore Braunschweig", COMMODORE_BRAUNSCHWEIG)
-    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_1)
-    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_2)
-    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
-    MANUF("Kolff Computer Supplies", KOLFF_COMPUTER_SUPPLIES)
-    MANUF("Cardco Ltd.", CARDCO_1)
-    MANUF("A-Squared", A_SQUARED)
-    MANUF("Comspec Communications", COMSPEC_COMMUNICATIONS)
-    MANUF("Anakin Research", ANAKIN_RESEARCH)
-    MANUF("Microbotics", MICROBOTICS)
-    MANUF("Access Associates Alegra", ACCESS_ASSOCIATES_ALEGRA)
-    MANUF("Expansion Technologies (Pacific Cypress)", EXPANSION_TECHNOLOGIES)
-    MANUF("ASDG", ASDG)
-    MANUF("Ronin/Imtronics", IMTRONICS_1)
-    MANUF("Commodore/University of Lowell", CBM_UNIVERSITY_OF_LOWELL)
-    MANUF("Ameristar", AMERISTAR)
-    MANUF("Supra", SUPRA)
-    MANUF("Computer Systems Assosiates", COMPUTER_SYSTEMS_ASSOCIATES)
-    MANUF("Marc Michael Groth", MARC_MICHAEL_GROTH)
-    MANUF("M-Tech", M_TECH)
-    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_1)
-    MANUF("ByteBox", BYTEBOX)
-    MANUF("DKB/Power Computing", DKB_POWER_COMPUTING)
-    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_2)
-    MANUF("California Access (Synergy)", CALIFORNIA_ACCESS_SYNERGY)
-    MANUF("Xetec", XETEC)
-    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
-    MANUF("Xebec", XEBEC)
-    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY)
-    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY_2)
-    MANUF("BSC/Alfadata", BSC_ALFADATA_1)
-    MANUF("BSC/Alfadata", BSC_ALFADATA_2)
-    MANUF("Cardco Ltd.", CARDCO_2)
-    MANUF("Jochheim", JOCHHEIM)
-    MANUF("Checkpoint Technologies", CHECKPOINT_TECHNOLOGIES)
-    MANUF("Edotronik", EDOTRONIK)
-    MANUF("NES Inc.", NES_INC)
-    MANUF("ICD", ICD)
-    MANUF("Kupke", KUPKE_2)
-    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_3)
-    MANUF("Interworks Network", INTERWORKS_NETWORK)
-    MANUF("Hardital Synthesis", HARDITAL_SYNTHESIS)
-    MANUF("Applied Engineering", APPLIED_ENGINEERING)
-    MANUF("BSC/Alfadata", BSC_ALFADATA_3)
-    MANUF("Phoenix", PHOENIX)
-    MANUF("Advanced Storage Systems", ADVANCED_STORAGE_SYSTEMS)
-    MANUF("Impulse", IMPULSE)
-    MANUF("IVS", IVS)
-    MANUF("Vector", VECTOR_1)
-    MANUF("XPert ProDev", XPERT_PRODEV)
-    MANUF("Hydra Systems", HYDRA_SYSTEMS)
-    MANUF("Sunrize Industries", SUNRIZE_INDUSTRIES)
-    MANUF("Triceratops", TRICERATOPS)
-    MANUF("Applied Magic Inc.", APPLIED_MAGIC)
-    MANUF("GFX-Base", GFX_BASE)
-    MANUF("RocTec", ROCTEC)
-    MANUF("Kato", KATO)
-    MANUF("Atlantis", ATLANTIS)
-    MANUF("Protar", PROTAR)
-    MANUF("ACS", ACS)
-    MANUF("Software Results Enterprises", SOFTWARE_RESULTS_ENTERPRISES)
-    MANUF("Masoboshi", MASOBOSHI)
-    MANUF("Mainhattan-Data (A-Team)", MAINHATTAN_DATA)
-    MANUF("Village Tronic", VILLAGE_TRONIC)
-    MANUF("Utilities Unlimited", UTILITIES_UNLIMITED)
-    MANUF("Amitrix", AMITRIX)
-    MANUF("ArMax", ARMAX)
-    MANUF("NewTek", NEWTEK)
-    MANUF("M-Tech Germany", M_TECH_GERMANY)
-    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_4)
-    MANUF("Apollo", APOLLO_1)
-    MANUF("Ingenieurbüro Helfrich", HELFRICH_2)
-    MANUF("MacroSystems USA", MACROSYSTEMS_USA)
-    MANUF("ElBox Computer", ELBOX_COMPUTER)
-    MANUF("Harms Professional", HARMS_PROFESSIONAL)
-    MANUF("Micronik", MICRONIK)
-    MANUF("Micronik", MICRONIK2)
-    MANUF("MegaMicro", MEGAMICRO)
-    MANUF("Ronin/Imtronics", IMTRONICS_2)
-    MANUF("Individual Computers", INDIVIDUAL_COMPUTERS)
-    MANUF("Kupke", KUPKE_3)
-    MANUF("ITH", ITH)
-    MANUF("VMC", VMC)
-    MANUF("Information", INFORMATION)
-    MANUF("Vortex", VORTEX)
-    MANUF("Expansion Systems", EXPANSION_SYSTEMS)
-    MANUF("ReadySoft", READYSOFT)
-    MANUF("Phase 5", PHASE5)
-    MANUF("DPS", DPS)
-    MANUF("Apollo", APOLLO_2)
-    MANUF("Apollo", APOLLO_3)
-    MANUF("Petsoff LP", PETSOFF_LP)
-    MANUF("Uwe Gerlach", UWE_GERLACH)
-    MANUF("MacroSystems Germany", MACROSYSTEMS_GERMANY)
-    MANUF("Combitec", COMBITEC)
-    MANUF("SKI Peripherals", SKI_PERIPHERALS)
-    MANUF("Reis-Ware", REIS_WARE_2)
-    MANUF("Cameron", CAMERON)
-    MANUF("Reis-Ware", REIS_WARE)
-    MANUF("Hacker Test Board", HACKER)	/* Unused */
-    MANUF("Phoenix", PHOENIX_2)
-    MANUF("Combitec", COMBITEC_2)
-END
-
-#define NUM_MANUF		(ARRAYSIZE(Manufacturers))
-#define NUM_GVP_PROD		(ARRAYSIZE(Ext_Prod_GVP))
-
-
-    /*
-     *  Zorro product classes
-     *
-     *  Make sure to keep these in sync with include/linux/zorro.h!
-     */
-
-static const char *classnames[] = {
-    NULL,				    /* ZORRO_CLASS_UNKNOWN */
-    "ArcNet Card",			    /* ZORRO_CLASS_ARCNET */
-    "Audio Board",			    /* ZORRO_CLASS_AUDIO */
-    "ISA Bus Bridge",			    /* ZORRO_CLASS_BRIDGE */
-    "DSP Board",			    /* ZORRO_CLASS_DSP */
-    "Ethernet Card",			    /* ZORRO_CLASS_ETHERNET */
-    "Ethernet Card and Parallel Ports",	    /* ZORRO_CLASS_ETHERNET_PARALLEL */
-    "Flash ROM",			    /* ZORRO_CLASS_FLASHROM */
-    "FPU and RAM Expansion",		    /* ZORRO_CLASS_FPU_RAM */
-    "Graphics Board",			    /* ZORRO_CLASS_GFX */
-    "Graphics Board (RAM)",		    /* ZORRO_CLASS_GFXRAM */
-    "HD Controller",			    /* ZORRO_CLASS_HD */
-    "HD Controller and RAM Expansion",	    /* ZORRO_CLASS_HD_RAM */
-    "IDE Interface",			    /* ZORRO_CLASS_IDE */
-    "IDE Interface and RAM Expansion",	    /* ZORRO_CLASS_IDE_RAM */
-    "IDE Interface and Floppy Controller",  /* ZORRO_CLASS_IDE_FLOPPY */
-    "ISDN Interface",			    /* ZORRO_CLASS_ISDN */
-    "Macintosh Emulator",		    /* ZORRO_CLASS_MACEMU */
-    "Miscellaneous Expansion Card",	    /* ZORRO_CLASS_MISC */
-    "Modem",				    /* ZORRO_CLASS_MODEM */
-    "Multi I/O",			    /* ZORRO_CLASS_MULTIIO */
-    "RAM Expansion",			    /* ZORRO_CLASS_RAM */
-    "Scanner Interface",		    /* ZORRO_CLASS_SCANNER */
-    "SCSI Host Adapter",		    /* ZORRO_CLASS_SCSI */
-    "SCSI Host Adapter and IDE Interface",  /* ZORRO_CLASS_SCSI_IDE */
-    "SCSI Host Adapter and RAM Expansion",  /* ZORRO_CLASS_SCSI_RAM */
-    "SCSI Host Adapter and Serial Card",    /* ZORRO_CLASS_SCSI_SERIAL */
-    "Multi Serial",			    /* ZORRO_CLASS_SERIAL */
-    "Drawing Tablet Interface",		    /* ZORRO_CLASS_TABLET */
-    "Accelerator",			    /* ZORRO_CLASS_TURBO */
-    "Accelerator and RAM Expansion",	    /* ZORRO_CLASS_TURBO_RAM */
-    "Accelerator and HD Controller",	    /* ZORRO_CLASS_TURBO_HD */
-    "Accelerator and IDE Interface",	    /* ZORRO_CLASS_TURBO_IDE */
-    "Accelerator and SCSI Host Adapter",    /* ZORRO_CLASS_TURBO_SCSI */
-    "Accelerator, SCSI Host Adapter and RAM Expansion",    /* ZORRO_CLASS_TURBO_SCSI */
-    "Video Board",			    /* ZORRO_CLASS_VIDEO */
-};
-
-static inline const char *get_class_name(enum Zorro_Classes class)
-{
-    if (class < ARRAYSIZE(classnames))
-	return(classnames[class]);
-    else
-	return("(**Illegal**)");
-}
-
-#endif /* CONFIG_ZORRO */
-
-
-    /*
-     *  Expansion Devices
-     */
-
-u_int zorro_num_autocon;
-struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
-static u32 BoardPartFlags[ZORRO_NUM_AUTO] = { 0, };
-
-   
-    /*
-     *  Find the key for the next unconfigured expansion device of a specific
-     *  type.
-     *
-     *  Part is a device specific number (0 <= part <= 31) to allow for the
-     *  independent configuration of independent parts of an expansion board.
-     *  Thanks to Jes Soerensen for this idea!
-     *
-     *  Index is used to specify the first board in the autocon list
-     *  to be tested. It was inserted in order to solve the problem
-     *  with the GVP boards that uses the same product code, but
-     *  it should help if there are other companies which use the same
-     *  method as GVP. Drivers for boards which are not using this
-     *  method do not need to think of this - just set index = 0.
-     *
-     *  Example:
-     *
-     *      while ((key = zorro_find(ZORRO_PROD_MY_BOARD, MY_PART, 0))) {
-     *      	cd = zorro_get_board(key);
-     *      	initialise_this_board;
-     *      	zorro_config_board(key, MY_PART);
-     *      }
-     */
-
-u_int zorro_find(zorro_id id, u_int part, u_int index)
-{
-    u_int manuf = ZORRO_MANUF(id);
-    u_int prod = ZORRO_PROD(id);
-    u_int epc = ZORRO_EPC(id);
-    u_int key;
-    const struct ConfigDev *cd;
-    u_long addr;
-
-    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
-	return(0);
-
-    if (part > 31) {
-	printk("zorro_find: bad part %d\n", part);
-	return(0);
-    }
-
-    for (key = index + 1; key <= zorro_num_autocon; key++) {
-	cd = &zorro_autocon[key-1];
-	addr = (u_long)cd->cd_BoardAddr;
-	if ((cd->cd_Rom.er_Manufacturer == manuf) &&
-	    (cd->cd_Rom.er_Product == prod) &&
-	    !(BoardPartFlags[key-1] & (1<<part)) &&
-	    (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
-	     prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE) ||
-	     (*(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK) == epc))
-	    break;
-    }
-    return(key <= zorro_num_autocon ? key : 0);
-}
-
-
-    /*
-     *  Get the board corresponding to a specific key
-     */
-
-const struct ConfigDev *zorro_get_board(u_int key)
-{
-    const struct ConfigDev *cd = NULL;
-
-    if ((key < 1) || (key > zorro_num_autocon))
-	printk("zorro_get_board: bad key %d\n", key);
-    else
-	cd = &zorro_autocon[key-1];
-
-    return(cd);
-}
-
-
-    /*
-     *  Mark a part of a board as configured
-     */
-
-void zorro_config_board(u_int key, u_int part)
-{
-    if ((key < 1) || (key > zorro_num_autocon))
-	printk("zorro_config_board: bad key %d\n", key);
-    else if (part > 31)
-	printk("zorro_config_board: bad part %d\n", part);
-    else if (BoardPartFlags[key-1] & (1<<part))
-	printk("zorro_config_board: key %d part %d is already configured\n",
-	       key, part);
-    else
-	BoardPartFlags[key-1] |= 1<<part;
-}
-
-
-    /*
-     *  Mark a part of a board as unconfigured
-     *
-     *  This function is mainly intended for the unloading of LKMs
-     */
-
-void zorro_unconfig_board(u_int key, u_int part)
-{
-    if ((key < 1) || (key > zorro_num_autocon))
-	printk("zorro_unconfig_board: bad key %d\n", key);
-    else if (part > 31)
-	printk("zorro_unconfig_board: bad part %d\n", part);
-    else if (!(BoardPartFlags[key-1] & (1<<part)))
-	printk("zorro_config_board: key %d part %d is not yet configured\n",
-	       key, part);
-    else
-	BoardPartFlags[key-1] &= ~(1<<part);
-}
-
-
-#ifdef CONFIG_ZORRO
-
-    /*
-     *  Identify an AutoConfig Expansion Device
-     *
-     *  If the board was configured by a Linux/m68k driver, an asterisk will
-     *  be printed before the board address (except for unknown and `Hacker
-     *  Test' boards).
-     */
-
-static int identify(u_int devnum, char *buf, int verbose)
-{
-    const struct ConfigDev *cd = &zorro_autocon[devnum];
-    u32 configured = BoardPartFlags[devnum];
-    u_int manuf = cd->cd_Rom.er_Manufacturer;
-    u_int prod = cd->cd_Rom.er_Product;
-    u_int class = ZORRO_CLASS_UNKNOWN;
-    u_int epc = 0;
-    const char *manufname = "Unknown";
-    const char *prodname = "Unknown";
-    const char *classname;
-    u_int i, j, k, len = 0;
-    u_long addr = (u_long)cd->cd_BoardAddr;
-    u_long size = cd->cd_BoardSize;
-    char mag;
-    int identified = 0, gvp = 0;
-
-    if (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
-	prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) {
-	for (i = 0; i < NUM_MANUF; i++)
-	    if (Manufacturers[i].Manuf == manuf) {
-		manufname = Manufacturers[i].Name;
-		for (j = 0; j < Manufacturers[i].NumProd; j++)
-		    if (Manufacturers[i].Products[j].Prod == prod) {
-			prodname = Manufacturers[i].Products[j].Name;
-			class = Manufacturers[i].Products[j].Class;
-			identified = 1;
-			break;
-		    }
-	    }
-	/* Put workarounds for ID clashes here */
-	if (manuf == ZORRO_MANUF(ZORRO_PROD_HELFRICH_RAINBOW_III) &&
-	    prod == ZORRO_PROD(ZORRO_PROD_HELFRICH_RAINBOW_III))
-	    manufname = "Ingenieurbüro Helfrich";
-    } else {
-	manufname = "Great Valley Products";
-	gvp = 1;
-	epc = *(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK;
-	for (k = 0; k < NUM_GVP_PROD; k++)
-	    if (epc == Ext_Prod_GVP[k].EPC) {
-		prodname = Ext_Prod_GVP[k].Name;
-		class = Ext_Prod_GVP[k].Class;
-		identified = 1;
-		break;
-	    }
-    }
-    classname = get_class_name(class);
-    if (size & 0xfffff) {
-	size >>= 10;
-	mag = 'K';
-    } else {
-	size >>= 20;
-	mag = 'M';
-    }
-    if (verbose) {
-	const char *zorro;
-	int is_mem = cd->cd_Rom.er_Type & ERTF_MEMLIST;
-	switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) {
-	    case ERT_ZORROII:
-		zorro = "Zorro II";
-		break;
-	    case ERT_ZORROIII:
-		zorro = "Zorro III";
-		break;
-	    default:
-		zorro = "Unknown Zorro";
-		break;
-	}
-	if (!prodname)
-	    prodname = "Unknown";
-	if (!classname)
-	    classname = "Unknown";
-	len = sprintf(buf, "  Device %d at 0x%08lx: ID=%04x:%02x", devnum,
-		      addr, manuf, prod);
-	if (gvp)
-	    len += sprintf(buf+len, ":%02x", epc);
-	len += sprintf(buf+len, ", %s, %ld%c", zorro, size, mag);
-	if (is_mem)
-	    len += sprintf(buf+len, ", System RAM");
-	else
-	    len += sprintf(buf+len, ", Configured=%08x", configured);
-	len += sprintf(buf+len, "\n"
-				"    Manufacturer: %s\n"
-				"    Product Name: %s\n"
-				"    Board Class : %s\n",
-				manufname, prodname, classname);
-    } else {
-	len = sprintf(buf, " %c%08lx: ", configured ? '*' : ' ', addr);
-	if (identified) {
-	    len += sprintf(buf+len, "%s", manufname);
-	    if (prodname)
-		len += sprintf(buf+len, " %s", prodname);
-	    if (classname)
-		len += sprintf(buf+len, " %s", classname);
-	} else if (manuf == ZORRO_MANUF_HACKER)
-	    len += sprintf(buf+len, "Hacker Test Board %02x", prod);
-	else if (gvp)
-	    len += sprintf(buf+len, "[%04x:%02x:%02x] made by %s", manuf, prod,
-			   epc, manufname);
-	else
-	    len += sprintf(buf+len, "[%04x:%02x] made by %s", manuf, prod,
-			   manufname);
-	len += sprintf(buf+len, " (%ld%c)\n", size, mag);
-	if (!identified && manuf != ZORRO_MANUF_HACKER)
-	    len += sprintf(buf+len, "    Please report this unknown device to "
-				    "zorro@linux-m68k.org\n");
-    }
-    return(len);
-}
-
-
-    /*
-     *  Identify all known AutoConfig Expansion Devices
-     */
-
-void zorro_identify(void)
-{
-    u_int i;
-    char tmp[256];
-
-    if (!AMIGAHW_PRESENT(ZORRO))
-	return;
-
-    printk("Probing AutoConfig expansion device(s):\n");
-    for (i = 0; i < zorro_num_autocon; i++) {
-	identify(i, tmp, 0);
-	printk(tmp);
-    }
-    if (!zorro_num_autocon)
-	printk("No AutoConfig expansion devices present.\n");
-}
-
-
-    /*
-     *  Get the list of all AutoConfig Expansion Devices
-     */
-
-int zorro_get_list(char *buffer)
-{
-    u_int i, len = 0, len2;
-    char tmp[256];
-
-    if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
-	len = sprintf(buffer, "AutoConfig expansion devices:\n");
-	for (i = 0; i < zorro_num_autocon; i++) {
-	    len2 = identify(i, tmp, 1);
-	    if (len+len2 >= 4075) {
-		len += sprintf(buffer+len, "4K limit reached!\n");
-		break;
-	    }
-	    strcpy(buffer+len, tmp);
-	    len += len2;
-	}
-    }
-    return(len);
-}
-
-#endif /* CONFIG_ZORRO */
-
-
-    /*
-     *  Bitmask indicating portions of available Zorro II RAM that are unused
-     *  by the system. Every bit represents a 64K chunk, for a maximum of 8MB
-     *  (128 chunks, physical 0x00200000-0x009fffff).
-     *
-     *  If you want to use (= allocate) portions of this RAM, you should clear
-     *  the corresponding bits.
-     *
-     *  Possible uses:
-     *      - z2ram device
-     *      - SCSI DMA bounce buffers
-     */
-
-u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 };
-
-
-static void mark_region(u_long addr, u_long size, int flag)
-{
-    u_long start, end, chunk;
-
-    if (flag) {
-	start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
-	end = (addr+size) & ~Z2RAM_CHUNKMASK;
-    } else {
-	start = addr & ~Z2RAM_CHUNKMASK;
-	end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
-    }
-    if (end <= Z2RAM_START || start >= Z2RAM_END)
-	return;
-    start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
-    end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
-    while (start < end) {
-	chunk = start>>Z2RAM_CHUNKSHIFT;
-	if (flag)
-	    set_bit( chunk, zorro_unused_z2ram );
-	else
-	    clear_bit( chunk, zorro_unused_z2ram );
-	start += Z2RAM_CHUNKSIZE;
-    }
-}
-
-
-    /*
-     *  Initialization
-     */
-
-void zorro_init(void)
-{
-    u_int i;
-    const struct ConfigDev *cd;
-
-    if (!AMIGAHW_PRESENT(ZORRO))
-	return;
-
-    /* Mark all available Zorro II memory */
-    for (i = 0; i < zorro_num_autocon; i++) {
-	cd = &zorro_autocon[i];
-	if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
-	    mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1);
-    }
-
-    /* Unmark all used Zorro II memory */
-    for (i = 0; i < m68k_num_memory; i++)
-	mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0);
-}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v2.1.105/linux/arch/m68k/atari/ataints.c	Tue Feb 17 13:12:44 1998
+++ linux/arch/m68k/atari/ataints.c	Sat Jun 13 13:14:32 1998
@@ -294,7 +294,7 @@
 	addql	#8,%%sp
 	addql	#4,%%sp
 	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)
-	 : : "i" (&kstat.irqs), "n" (PT_OFF_FORMATVEC)
+	 : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC)
 );
 }
 
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.1.105/linux/arch/m68k/atari/atakeyb.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/atari/atakeyb.c	Sat Jun 13 13:14:32 1998
@@ -28,7 +28,6 @@
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
 #include <asm/atarikb.h>
-#include <asm/atari_mouse.h>
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
@@ -193,7 +192,7 @@
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
 };
 
-static u_short atashift_alt_map[NR_KEYS] = {
+static u_short atashift_alt_map[NR_KEYS] __initdata = {
 	0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
 	0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
 	0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
@@ -767,14 +766,17 @@
 __initfunc(int atari_keyb_init(void))
 {
     /* setup key map */
-    memcpy(plain_map, ataplain_map, sizeof(plain_map));
-    memcpy(shift_map, atashift_map, sizeof(shift_map));
+    memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+    memcpy(key_maps[1], atashift_map, sizeof(plain_map));
+    memcpy(key_maps[4], atactrl_map, sizeof(plain_map));
+    memcpy(key_maps[5], atashift_ctrl_map, sizeof(plain_map));
+    memcpy(key_maps[8], ataalt_map, sizeof(plain_map));
+    /* Atari doesn't have an altgr_map, so we can reuse its memory for
+       atashift_alt_map */
+    memcpy(key_maps[2], atashift_alt_map, sizeof(plain_map));
+    key_maps[9]  = key_maps[2];
     key_maps[2]  = 0; /* ataaltgr_map */
-    memcpy(ctrl_map, atactrl_map, sizeof(ctrl_map));
-    memcpy(shift_ctrl_map, atashift_ctrl_map, sizeof(shift_ctrl_map));
-    memcpy(alt_map, ataalt_map, sizeof(alt_map));
-    key_maps[9]  = atashift_alt_map;
-    memcpy(ctrl_alt_map, atactrl_alt_map, sizeof(ctrl_alt_map));
+    memcpy(key_maps[12], atactrl_alt_map, sizeof(plain_map));
     key_maps[13] = atashift_ctrl_alt_map;
     keymap_count = 8;
 
@@ -859,4 +861,9 @@
 	k->rate  = key_repeat_rate  * 1000 / HZ;
 	
 	return( 0 );
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
 }
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c
--- v2.1.105/linux/arch/m68k/atari/atasound.c	Tue Feb 17 13:12:44 1998
+++ linux/arch/m68k/atari/atasound.c	Sat Jun 13 13:14:32 1998
@@ -10,6 +10,9 @@
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  *
+ * 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope,
+ *			 no timer, atari_nosound removed.
+ *
  */
 
 
@@ -31,22 +34,6 @@
  * stuff from the old atasound.c
  */
 
-
-static void atari_nosound (unsigned long ignored)
-{
-	unsigned char	tmp;
-	unsigned long flags;
-	
-	/* turn off generator A in mixer control */
-	save_flags(flags);
-	cli();
-	sound_ym.rd_data_reg_sel = 7;
-	tmp = sound_ym.rd_data_reg_sel;
-	sound_ym.wd_data = tmp | 0x39;
-	restore_flags(flags);
-}	
-		
-
 void atari_microwire_cmd (int cmd)
 {
 	tt_microwire.mask = 0x7ff;
@@ -58,90 +45,62 @@
 }
 
 
-#define	PC_FREQ		1192180
+/* PSG base frequency */
 #define	PSG_FREQ	125000
+/* PSG envelope base frequency times 10 */
+#define PSG_ENV_FREQ_10	78125
 
-
-void atari_mksound (unsigned int count, unsigned int ticks)
+void atari_mksound (unsigned int hz, unsigned int ticks)
 {
-	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
-						     atari_nosound };
-	/*
-	 * Generates sound of some count for some number of clock ticks
-	 * [count = 1193180 / frequency]
-	 */
+	/* Generates sound of some frequency for some number of clock
+	   ticks.  */
 	unsigned long flags;
 	unsigned char tmp;
+	int period;
 
 	save_flags(flags);
 	cli();
 
-	if (count == 750 && ticks == HZ/8) {
-		/* Special case: These values are used by console.c to
-		 * generate the console bell. They are cached here and the
-		 * sound actually generated is somehow special: it uses the
-		 * generator B and an envelope. No timer is needed therefore
-		 * and the bell doesn't disturb an other ongoing sound.
-		 */
+	/* Convert from frequency value to PSG period value (base
+	   frequency 125 kHz).  */
+	period = PSG_FREQ / hz;
 
-		/* set envelope duration to 492 ms */
+	if (period > 0xfff) period = 0xfff;
+
+	/* Disable generator A in mixer control.  */
+	sound_ym.rd_data_reg_sel = 7;
+	tmp = sound_ym.rd_data_reg_sel;
+	tmp |= 011;
+	sound_ym.wd_data = tmp;
+	/* Set generator A frequency to hz.  */
+	sound_ym.rd_data_reg_sel = 0;
+	sound_ym.wd_data = period & 0xff;
+	sound_ym.rd_data_reg_sel = 1;
+	sound_ym.wd_data = (period >> 8) & 0xf;
+	if (ticks) {
+		/* Set length of envelope (max 8 sec).  */
+		int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10;
+
+		if (length > 0xffff) length = 0xffff;
 		sound_ym.rd_data_reg_sel = 11;
-		sound_ym.wd_data = 0;
+		sound_ym.wd_data = length & 0xff;
 		sound_ym.rd_data_reg_sel = 12;
-		sound_ym.wd_data = 15;
-		/* envelope form: max -> min single */
+		sound_ym.wd_data = length >> 8;
+		/* Envelope form: max -> min single.  */
 		sound_ym.rd_data_reg_sel = 13;
-		sound_ym.wd_data = 9;
-		/* set generator B frequency to 2400 Hz */
-		sound_ym.rd_data_reg_sel = 2;
-		sound_ym.wd_data = 52;
-		sound_ym.rd_data_reg_sel = 3;
 		sound_ym.wd_data = 0;
-		/* set volume of generator B to envelope control */
-		sound_ym.rd_data_reg_sel = 9;
+		/* Use envelope for generator A.  */
+		sound_ym.rd_data_reg_sel = 8;
 		sound_ym.wd_data = 0x10;
-		/* enable generator B in the mixer control */
-		sound_ym.rd_data_reg_sel = 7;
-		tmp = sound_ym.rd_data_reg_sel;
-		sound_ym.wd_data = (tmp & ~0x02) | 0x38;
-
-		restore_flags(flags);
-		return;
-	}
-
-	del_timer( &sound_timer );
-
-	if (!count) {
-		atari_nosound( 0 );
-	}
-	else {
-
-		/* convert from frequency value
-		 * to PSG period value (base frequency 125 kHz).
-		 */
-		int period = PSG_FREQ / count;
-
-		if (period > 0xfff) period = 0xfff;
-
-		/* set generator A frequency to 0 */
-		sound_ym.rd_data_reg_sel = 0;
-		sound_ym.wd_data = period & 0xff;
-		sound_ym.rd_data_reg_sel = 1;
-		sound_ym.wd_data = (period >> 8) & 0xf;
-		/* turn on generator A in mixer control (but not noise
-		 * generator!) */
-		sound_ym.rd_data_reg_sel = 7;
-		tmp = sound_ym.rd_data_reg_sel;
-		sound_ym.wd_data = (tmp & ~0x01) | 0x38;
-		/* set generator A level to maximum, no envelope */
+	} else {
+		/* Set generator A level to maximum, no envelope.  */
 		sound_ym.rd_data_reg_sel = 8;
 		sound_ym.wd_data = 15;
-		
-		if (ticks) {
-			sound_timer.expires = jiffies + ticks;
-			add_timer( &sound_timer );
-		}
 	}
+	/* Turn on generator A in mixer control.  */
+	sound_ym.rd_data_reg_sel = 7;
+	tmp &= ~1;
+	sound_ym.wd_data = tmp;
 
 	restore_flags(flags);
 }
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v2.1.105/linux/arch/m68k/atari/config.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/atari/config.c	Sat Jun 13 13:14:32 1998
@@ -38,6 +38,7 @@
 #include <asm/atari_stram.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
+#include <asm/hwtest.h>
 
 u_long atari_mch_cookie;
 u_long atari_mch_type = 0;
@@ -98,39 +99,15 @@
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
-/* This function tests for the presence of an address, specially a
- * hardware register address. It is called very early in the kernel
- * initialization process, when the VBR register isn't set up yet. On
- * an Atari, it still points to address 0, which is unmapped. So a bus
- * error would cause another bus error while fetching the exception
- * vector, and the CPU would do nothing at all. So we needed to set up
- * a temporary VBR and a vector table for the duration of the test.
+/* I've moved hwreg_present() and hwreg_present_bywrite() out into
+ * mm/hwtest.c, to avoid having multiple copies of the same routine
+ * in the kernel [I wanted them in hp300 and they were already used
+ * in the nubus code. NB: I don't have an Atari so this might (just
+ * conceivably) break something.
+ * I've preserved the #if 0 version of hwreg_present_bywrite() here
+ * for posterity.
+ *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
  */
-
-__initfunc(static int hwreg_present( volatile void *regp ))
-{
-    int	ret = 0;
-    long	save_sp, save_vbr;
-    long	tmp_vectors[3];
-
-    __asm__ __volatile__
-	(	"movec	%/vbr,%2\n\t"
-		"movel	#Lberr1,%4@(8)\n\t"
-                "movec	%4,%/vbr\n\t"
-		"movel	%/sp,%1\n\t"
-		"moveq	#0,%0\n\t"
-		"tstb	%3@\n\t"  
-		"nop\n\t"
-		"moveq	#1,%0\n"
-                "Lberr1:\n\t"
-		"movel	%1,%/sp\n\t"
-		"movec	%2,%/vbr"
-		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
-		: "a" (regp), "a" (tmp_vectors)
-                );
-
-    return( ret );
-}
   
 #if 0
 __initfunc(static int
@@ -163,35 +140,6 @@
 }
 #endif
 
-/* Basically the same, but writes a value into a word register, protected
- * by a bus error handler */
-
-__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
-{
-	int		ret;
-	long	save_sp, save_vbr;
-	long	tmp_vectors[3];
-
-	__asm__ __volatile__
-	(	"movec	%/vbr,%2\n\t"
-		"movel	#Lberr2,%4@(8)\n\t"
-		"movec	%4,%/vbr\n\t"
-		"movel	%/sp,%1\n\t"
-		"moveq	#0,%0\n\t"
-		"movew	%5,%3@\n\t"  
-		"nop	\n\t"	/* If this nop isn't present, 'ret' may already be
-				 * loaded with 1 at the time the bus error
-				 * happens! */
-		"moveq	#1,%0\n"
-	"Lberr2:\n\t"
-		"movel	%1,%/sp\n\t"
-		"movec	%2,%/vbr"
-		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
-		: "a" (regp), "a" (tmp_vectors), "g" (val)
-	);
-
-	return( ret );
-}
 
 /* ++roman: This is a more elaborate test for an SCC chip, since the plain
  * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c
--- v2.1.105/linux/arch/m68k/atari/joystick.c	Tue Mar 10 10:03:30 1998
+++ linux/arch/m68k/atari/joystick.c	Sat Jun 13 13:14:32 1998
@@ -15,7 +15,6 @@
 
 #include <asm/atarikb.h>
 #include <asm/atari_joystick.h>
-#include <asm/atari_mouse.h>
 #include <asm/uaccess.h>
 
 #define MAJOR_NR    JOYSTICK_MAJOR
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.1.105/linux/arch/m68k/atari/stram.c	Sun Jun  7 11:16:27 1998
+++ linux/arch/m68k/atari/stram.c	Sat Jun 13 13:14:32 1998
@@ -954,7 +954,7 @@
 				return( -ENOMEM );
 			}
 			DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page );
-			read_swap_page( entry, (char *)page );
+			rw_swap_page( READ, entry, (char *)page, 1 );
 
 			for_each_task(p) {
 				if (unswap_process( p->mm, entry, page, 0 )) {
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c
--- v2.1.105/linux/arch/m68k/atari/time.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/atari/time.c	Sat Jun 13 13:14:32 1998
@@ -83,7 +83,7 @@
 
 #define	RTC_READ(reg)				\
     ({	unsigned char	__val;			\
-		writeb(reg,&tt_rtc.regsel);	\
+		(void) writeb(reg,&tt_rtc.regsel);	\
 		__val = tt_rtc.data;		\
 		__val;				\
 	})
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/bvme6000/Makefile linux/arch/m68k/bvme6000/Makefile
--- v2.1.105/linux/arch/m68k/bvme6000/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/bvme6000/Makefile	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/bvme6000 source directory
+#
+# 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 := bvme6000.o
+O_OBJS   := config.o bvmeints.o rtc.o
+#OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/bvme6000/bvmeints.c linux/arch/m68k/bvme6000/bvmeints.c
--- v2.1.105/linux/arch/m68k/bvme6000/bvmeints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/bvme6000/bvmeints.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,154 @@
+/*
+ * arch/m68k/bvme6000/bvmeints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+	unsigned	count;
+} irq_tab[256];
+
+/*
+ * void bvme6000_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+
+void bvme6000_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i < 256; i++) {
+		irq_tab[i].handler = bvme6000_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname = NULL;
+		irq_tab[i].count = 0;
+	}
+}
+
+int bvme6000_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+#if 0
+	/* Nothing special about auto-vectored devices for the BVME6000,
+	 * but treat it specially to avoid changes elsewhere.
+	 */
+
+	if (irq >= VEC_INT1 && irq <= VEC_INT7)
+		return sys_request_irq(irq - VEC_SPUR, handler, flags,
+						devname, dev_id);
+#endif
+	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+		if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+	}
+	irq_tab[irq].handler = handler;
+	irq_tab[irq].flags   = flags;
+	irq_tab[irq].dev_id  = dev_id;
+	irq_tab[irq].devname = devname;
+	return 0;
+}
+
+void bvme6000_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+#if 0
+	if (irq >= VEC_INT1 && irq <= VEC_INT7) {
+		sys_free_irq(irq - VEC_SPUR, dev_id);
+		return;
+	}
+#endif
+	if (irq_tab[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_tab[irq].devname);
+
+	irq_tab[irq].handler = bvme6000_defhand;
+	irq_tab[irq].flags   = IRQ_FLG_STD;
+	irq_tab[irq].dev_id  = NULL;
+	irq_tab[irq].devname = NULL;
+}
+
+void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
+{
+	if (vec > 255)
+		panic ("bvme6000_process_int: Illegal vector %ld", vec);
+	irq_tab[vec].count++;
+	irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+}
+
+int bvme6000_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i < 256; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+			    i, irq_tab[i].count,
+			    irq_tab[i].devname ? irq_tab[i].devname : "free");
+	}
+	return len;
+}
+
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+	printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void bvme6000_enable_irq (unsigned int irq)
+{
+}
+
+
+void bvme6000_disable_irq (unsigned int irq)
+{
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- v2.1.105/linux/arch/m68k/bvme6000/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/bvme6000/config.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,453 @@
+/*
+ *  arch/m68k/bvme6000/config.c
+ *
+ *  Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  linux/amiga/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/bvme6000hw.h>
+
+extern void bvme6000_process_int (int level, struct pt_regs *regs);
+extern void bvme6000_init_IRQ (void);
+extern void bvme6000_free_irq (unsigned int, void *);
+extern int  bvme6000_get_irq_list (char *);
+extern void bvme6000_enable_irq (unsigned int);
+extern void bvme6000_disable_irq (unsigned int);
+static void bvme6000_get_model(char *model);
+static int  bvme6000_get_hardware_list(char *buffer);
+extern int  bvme6000_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void bvme6000_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  bvme6000_keyb_init(void);
+extern int  bvme6000_kbdrate (struct kbd_repeat *);
+extern unsigned long bvme6000_gettimeoffset (void);
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int bvme6000_hwclk (int, struct hwclk_time *);
+extern int bvme6000_set_clock_mmss (unsigned long);
+extern void bvme6000_check_partition (struct gendisk *hd, unsigned int dev);
+extern void bvme6000_mksound( unsigned int count, unsigned int ticks );
+extern void bvme6000_reset (void);
+extern void bvme6000_waitbut(void);
+void bvme6000_set_vectors (void);
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via bvme6000_process_int() */
+
+static void (*tick_handler)(int, void *, struct pt_regs *);
+
+int bvme6000_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+
+void bvme6000_mksound( unsigned int count, unsigned int ticks )
+{
+}
+
+void bvme6000_reset()
+{
+	volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+	printk ("\r\n\nCalled bvme6000_reset\r\n"
+			"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r");
+	/* The string of returns is to delay the reset until the whole
+	 * message is output. */
+	/* Enable the watchdog, via PIT port C bit 4 */
+
+	pit->pcddr	|= 0x10;	/* WDOG enable */
+
+	while(1)
+		;
+}
+
+static void bvme6000_get_model(char *model)
+{
+    /* XXX Need to detect if BVME4000 or BVME6000 */
+    sprintf(model, "BVME6000");
+}
+
+
+/* No hardware options on BVME6000? */
+
+static int bvme6000_get_hardware_list(char *buffer)
+{
+    *buffer = '\0';
+    return 0;
+}
+
+
+__initfunc(void config_bvme6000(void))
+{
+    volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+#if 0
+    /* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug
+     * debugger.  Note trap_init() will splat the abort vector, but
+     * bvme6000_init_IRQ() will put it back again.  Hopefully. */
+
+    bvme6000_set_vectors();
+#endif
+
+    mach_sched_init      = bvme6000_sched_init;
+    mach_keyb_init       = bvme6000_keyb_init;
+    mach_kbdrate         = bvme6000_kbdrate;
+    mach_init_IRQ        = bvme6000_init_IRQ;
+    mach_gettimeoffset   = bvme6000_gettimeoffset;
+    mach_gettod  	 = bvme6000_gettod;
+    mach_hwclk           = bvme6000_hwclk;
+    mach_set_clock_mmss	 = bvme6000_set_clock_mmss;
+/*  mach_mksound         = bvme6000_mksound; */
+    mach_reset		 = bvme6000_reset;
+    mach_free_irq	 = bvme6000_free_irq;
+    mach_process_int	 = bvme6000_process_int;
+    mach_get_irq_list	 = bvme6000_get_irq_list;
+    mach_request_irq	 = bvme6000_request_irq;
+    enable_irq		 = bvme6000_enable_irq;
+    disable_irq          = bvme6000_disable_irq;
+    mach_get_model       = bvme6000_get_model;
+    mach_get_hardware_list = bvme6000_get_hardware_list;
+
+    printk ("Board is %sconfigured as a System Controller\n",
+		*config_reg_ptr & BVME_CONFIG_SW1 ? "" : "not ");
+
+    /* Now do the PIT configuration */
+
+    pit->pgcr	= 0x00;	/* Unidirectional 8 bit, no handshake for now */
+    pit->psrr	= 0x18;	/* PIACK and PIRQ fucntions enabled */
+    pit->pacr	= 0x00;	/* Sub Mode 00, H2 i/p, no DMA */
+    pit->padr	= 0x00;	/* Just to be tidy! */
+    pit->paddr	= 0x00;	/* All inputs for now (safest) */
+    pit->pbcr	= 0x80;	/* Sub Mode 1x, H4 i/p, no DMA */
+    pit->pbdr	= 0xbc | (*config_reg_ptr & BVME_CONFIG_SW1 ? 0 : 0x40);
+			/* PRI, SYSCON?, Level3, SCC clks from xtal */
+    pit->pbddr	= 0xf3;	/* Mostly outputs */
+    pit->pcdr	= 0x01;	/* PA transceiver disabled */
+    pit->pcddr	= 0x03;	/* WDOG disable */
+}
+
+
+void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+        unsigned long *new = (unsigned long *)vectors;
+        unsigned long *old = (unsigned long *)0xf8000000;;
+
+        /* Wait for button release */
+	while (*config_reg_ptr & BVME_ABORT_STATUS)
+		;
+
+        *(new+4) = *(old+4);            /* Illegal instruction */
+        *(new+9) = *(old+9);            /* Trace */
+        *(new+47) = *(old+47);          /* Trap #15 */
+        *(new+0x1f) = *(old+0x1f);      /* ABORT switch */
+}
+
+
+static void bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+
+    rtc->msr = msr | 0x20;		/* Ack the interrupt */
+
+    tick_handler(irq, dev_id, fp);
+}
+
+/*
+ * Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms
+ * (40000 x 125ns).  It will interrupt every 10ms, when T1 goes low.
+ * So, when reading the elapsed time, you should read timer1,
+ * subtract it from 39999, and then add 40000 if T1 is high.
+ * That gives you the number of 125ns ticks in to the 10ms period,
+ * so divide by 8 to get the microsecond result.
+ */
+
+void bvme6000_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+
+    rtc->msr = 0;	/* Ensure timer registers accessible */
+
+    tick_handler = timer_routine;
+    if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
+				"timer", bvme6000_timer_int))
+	panic ("Couldn't register timer int");
+
+    rtc->t1cr_omr = 0x04;	/* Mode 2, ext clk */
+    rtc->t1msb = 39999 >> 8;
+    rtc->t1lsb = 39999 & 0xff;
+    rtc->irr_icr1 &= 0xef;	/* Route timer 1 to INTR pin */
+    rtc->msr = 0x40;		/* Access int.cntrl, etc */
+    rtc->pfr_icr0 = 0x80;	/* Just timer 1 ints enabled */
+    rtc->irr_icr1 = 0;
+    rtc->t1cr_omr = 0x0a;	/* INTR+T1 active lo, push-pull */
+    rtc->t0cr_rtmr &= 0xdf;	/* Stop timers in standby */
+    rtc->msr = 0;		/* Access timer 1 control */
+    rtc->t1cr_omr = 0x05;	/* Mode 2, ext clk, GO */
+
+    rtc->msr = msr;
+
+    if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0,
+				"abort", bvme6000_abort_int))
+	panic ("Couldn't register abort int");
+}
+
+
+/* This is always executed with interrupts disabled.  */
+
+/*
+ * NOTE:  Don't accept any readings within 5us of rollover, as
+ * the T1INT bit may be a little slow getting set.  There is also
+ * a fault in the chip, meaning that reads may produce invalid
+ * results...
+ */
+
+unsigned long bvme6000_gettimeoffset (void)
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+    unsigned char t1int, t1op;
+    unsigned long v = 800000, ov;
+
+    rtc->msr = 0;	/* Ensure timer registers accessible */
+
+    do {
+	ov = v;
+	t1int = rtc->msr & 0x20;
+	t1op  = pit->pcdr & 0x04;
+	rtc->t1cr_omr |= 0x40;		/* Latch timer1 */
+	v = rtc->t1msb << 8;		/* Read timer1 */
+	v |= rtc->t1lsb;		/* Read timer1 */
+    } while (t1int != (rtc->msr & 0x20) ||
+		t1op != (pit->pcdr & 0x04) ||
+			abs(ov-v) > 80 ||
+				v > 39960);
+
+    v = 39999 - v;
+    if (!t1op)				/* If in second half cycle.. */
+	v += 40000;
+    v /= 8;				/* Convert ticks to microseconds */
+    if (t1int)
+	v += 10000;			/* Int pending, + 10ms */
+    rtc->msr = msr;
+
+    return v;
+}
+
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+	unsigned char msr = rtc->msr & 0xc0;
+
+	rtc->msr = 0;		/* Ensure clock accessible */
+
+	do {	/* Loop until we get a reading with a stable seconds field */
+		*sec = bcd2bin (rtc->bcd_sec);
+		*min = bcd2bin (rtc->bcd_min);
+		*hour = bcd2bin (rtc->bcd_hr);
+		*day = bcd2bin (rtc->bcd_dom);
+		*mon = bcd2bin (rtc->bcd_mth);
+		*year = bcd2bin (rtc->bcd_year);
+	} while (bcd2bin (rtc->bcd_sec) != *sec);
+
+	rtc->msr = msr;
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+	return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ *  struct hwclk_time {
+ *         unsigned        sec;       0..59
+ *         unsigned        min;       0..59
+ *         unsigned        hour;      0..23
+ *         unsigned        day;       1..31
+ *         unsigned        mon;       0..11
+ *         unsigned        year;      00...
+ *         int             wday;      0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int bvme6000_hwclk(int op, struct hwclk_time *t)
+{
+	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+	unsigned char msr = rtc->msr & 0xc0;
+
+	rtc->msr = 0x40;	/* Ensure clock and real-time-mode-register
+				 * are accessible */
+	if (op)
+	{	/* Write.... */
+		rtc->t0cr_rtmr = t->year%4;
+		rtc->bcd_tenms = 0;
+		rtc->bcd_sec = bin2bcd(t->sec);
+		rtc->bcd_min = bin2bcd(t->min);
+		rtc->bcd_hr  = bin2bcd(t->hour);
+		rtc->bcd_dom = bin2bcd(t->day);
+		rtc->bcd_mth = bin2bcd(t->mon + 1);
+		rtc->bcd_year = bin2bcd(t->year%100);
+		if (t->wday >= 0)
+			rtc->bcd_dow = bin2bcd(t->wday+1);
+		rtc->t0cr_rtmr = t->year%4 | 0x08;
+	}
+	else
+	{	/* Read....  */
+		do {
+			t->sec =  bcd2bin(rtc->bcd_sec);
+			t->min =  bcd2bin(rtc->bcd_min);
+			t->hour = bcd2bin(rtc->bcd_hr);
+			t->day =  bcd2bin(rtc->bcd_dom);
+			t->mon =  bcd2bin(rtc->bcd_mth)-1;
+			t->year = bcd2bin(rtc->bcd_year);
+			if (t->year < 70)
+				t->year += 100;
+			t->wday = bcd2bin(rtc->bcd_dow)-1;
+		} while (t->sec != bcd2bin(rtc->bcd_sec));
+	}
+
+	rtc->msr = msr;
+
+	return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
+ * clock is out by > 30 minutes.  Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int bvme6000_set_clock_mmss (unsigned long nowtime)
+{
+	int retval = 0;
+	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+	unsigned char rtc_minutes, rtc_tenms;
+	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+	unsigned char msr = rtc->msr & 0xc0;
+	unsigned long flags;
+	volatile int i;
+
+	rtc->msr = 0;		/* Ensure clock accessible */
+	rtc_minutes = bcd2bin (rtc->bcd_min);
+
+	if ((rtc_minutes < real_minutes
+		? real_minutes - rtc_minutes
+			: rtc_minutes - real_minutes) < 30)
+	{
+		save_flags(flags);
+		cli();
+		rtc_tenms = rtc->bcd_tenms;
+		while (rtc_tenms == rtc->bcd_tenms)
+			;
+		for (i = 0; i < 1000; i++)
+			;
+		rtc->bcd_min = bin2bcd(real_minutes);
+		rtc->bcd_sec = bin2bcd(real_seconds);
+		restore_flags(flags);
+	}
+	else
+		retval = -1;
+
+	rtc->msr = msr;
+
+	return retval;
+}
+
+
+int bvme6000_keyb_init (void)
+{
+	return 0;
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+static void bvme_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void bvme6000_init_console_port (struct console *co, int cflag)
+{
+        co->write = bvme_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+        int n;
+        char i;
+
+        for (n = 0; n < 20; n++)
+                i = *(volatile char *)0;
+}
+
+static void scc_write (char ch)
+{
+        volatile char *p = (volatile char *)BVME_SCC_A_ADDR;
+
+        do {
+                scc_delay();
+        }
+        while (!(*p & 4));
+        scc_delay();
+        *p = 8;
+        scc_delay();
+        *p = ch;
+}
+
+
+static void bvme_scc_write (struct console *co, const char *str, unsigned count)
+{
+        unsigned long   flags;
+
+        save_flags(flags);
+        cli();
+
+        while (count--)
+        {
+                if (*str == '\n')
+                        scc_write ('\r');
+                scc_write (*str++);
+        }
+        restore_flags(flags);
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/bvme6000/rtc.c linux/arch/m68k/bvme6000/rtc.c
--- v2.1.105/linux/arch/m68k/bvme6000/rtc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/bvme6000/rtc.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,175 @@
+/*
+ *	Real Time Clock interface for Linux on the BVME6000
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION		"1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h>	/* For struct rtc_time and ioctls, etc */
+#include <asm/bvme6000hw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+	unsigned char msr;
+	unsigned long flags;
+	struct rtc_time wtime; 
+
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		save_flags(flags);
+		cli();
+		/* Ensure clock and real-time-mode-register are accessible */
+		msr = rtc->msr & 0xc0;
+		rtc->msr = 0x40;
+		do {
+			wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
+			wtime.tm_min =  BCD2BIN(rtc->bcd_min);
+			wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+			wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
+			wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
+			wtime.tm_year = BCD2BIN(rtc->bcd_year);
+			if (wtime.tm_year < 70)
+				wtime.tm_year += 100;
+			wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+		} while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+		rtc->msr = msr;
+		restore_flags(flags);
+		return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+								-EFAULT : 0;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		unsigned char leap_yr;
+		struct rtc_time rtc_tm;
+
+		if (!suser())
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+		if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+			return -EINVAL;
+
+		if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+			return -EINVAL;
+			
+		if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+			return -EINVAL;
+
+		save_flags(flags);
+		cli();
+		/* Ensure clock and real-time-mode-register are accessible */
+		msr = rtc->msr & 0xc0;
+		rtc->msr = 0x40;
+
+		rtc->t0cr_rtmr = rtc_tm.tm_year%4;
+		rtc->bcd_tenms = 0;
+		rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+		rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+		rtc->bcd_hr  = BIN2BCD(rtc_tm.tm_hour);
+		rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+		rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+		rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+		if (rtc_tm.tm_wday >= 0)
+			rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+		rtc->t0cr_rtmr = rtc_tm.tm_year%4 | 0x08;
+
+		rtc->msr = msr;
+		restore_flags(flags);
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	if(rtc_status)
+		return -EBUSY;
+
+	rtc_status = 1;
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	rtc_status = 0;
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+	NULL,
+	NULL,
+	NULL,		/* No write */
+	NULL,		/* No readdir */
+	NULL,
+	rtc_ioctl,
+	NULL,		/* No mmap */
+	rtc_open,
+	rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+__initfunc(int rtc_DP8570A_init(void))
+{
+	if (!MACH_IS_BVME6000)
+		return -ENODEV;
+
+	printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
+	misc_register(&rtc_dev);
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.1.105/linux/arch/m68k/config.in	Sun Jun  7 11:16:27 1998
+++ linux/arch/m68k/config.in	Sat Jun 13 13:14:32 1998
@@ -19,7 +19,7 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Platform-dependent setup'
+comment 'Platform dependent setup'
 
 bool 'Amiga support' CONFIG_AMIGA
 bool 'Atari support' CONFIG_ATARI
@@ -30,13 +30,19 @@
   fi  
 fi
 bool 'Macintosh support' CONFIG_MAC
+if [ "$CONFIG_MAC" = "y" ]; then
+  define_bool CONFIG_NUBUS y
+fi
 bool 'Apollo support' CONFIG_APOLLO
 bool 'VME (Motorola and BVM) support' CONFIG_VME
 if [ "$CONFIG_VME" = "y" ]; then
   bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
-# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+  bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+fi
+bool 'HP9000/300 support' CONFIG_HP300
+if [ "$CONFIG_HP300" = "y" ]; then
+  bool 'DIO bus support' CONFIG_DIO
 fi
-
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
@@ -57,6 +63,7 @@
 bool 'Advanced processor options' CONFIG_ADVANCED_CPU
 if [ "$CONFIG_ADVANCED_CPU" = "y" ]; then
   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
+  bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
 fi
 endmenu
 
@@ -73,11 +80,6 @@
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
-#  bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP
-#  if [ "$CONFIG_AMIGA_GSP" = "y" ]; then
-#    bool 'DMI Resolver support' CONFIG_GSP_RESOLVER
-#    bool 'A2410 support' CONFIG_GSP_A2410
-#  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
@@ -85,73 +87,17 @@
 fi
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
   bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
-fi
-endmenu
-
-#
-# Block device driver configuration
-#
-mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
-
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
-fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY
-fi
-#Normal floppy disk support' CONFIG_BLK_DEV_FD
-
-tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
-if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
-  dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
-  dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
-  if [ "$CONFIG_AMIGA" = "y" ]; then
-    bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
-      bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
-    fi
-  fi
-  if [ "$CONFIG_ATARI" = "y" ]; then
-    bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
-  fi
-fi
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
-  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
-    comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
-    bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
-    dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
+else
+  if [ "$CONFIG_HP300" = "y" ]; then
+# We have a dedicated heartbeat LED. :-)
+  define_bool CONFIG_HEARTBEAT y
   fi
 fi
-
-comment 'Additional Block Devices'
-
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
-  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
-  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
-fi
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-  bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
-fi
+bool '/proc/hardware support' CONFIG_PROC_HARDWARE
 endmenu
 
+source drivers/block/Config.in
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
@@ -196,15 +142,21 @@
     bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
-    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
+#    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
+  if [ "$CONFIG_MAC" = "y" ]; then
+    bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
-  bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-  if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
-    bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+  if [ "$CONFIG_ATARI_SCSI" != "n" ]; then
+    bool '  Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    bool '  Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT
+    if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
+      bool '  Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+    fi
   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
@@ -216,6 +168,10 @@
   bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
 fi
 
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+  bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
+fi
+
 endmenu
 
 fi
@@ -264,6 +220,9 @@
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   bool 'MVME16x Ethernet support' CONFIG_APRICOT
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+  bool 'BVME6000 Ethernet support' CONFIG_APRICOT
+fi
 fi
 endmenu
 
@@ -322,20 +281,31 @@
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
   bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_MAC" = "y" ]; then
+  bool 'Mac SCC serial support' CONFIG_MAC_SCC
+fi
+if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
+  tristate 'HP DCA serial support' CONFIG_HPDCA
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
+     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
-       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
-       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
+       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
+       "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
+       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
+       "$CONFIG_HPDCA" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
   fi
 fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'Mac SCC serial support' CONFIG_MAC_SCC
-fi
 if [ "$CONFIG_VME" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
-  bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
-  bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+  if [ "$CONFIG_MVME16x" = "y" ]; then
+    bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+    bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+  fi
+  if [ "$CONFIG_BVME6000" = "y" ]; then
+    bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
+  fi
 fi
 if [ "$CONFIG_APOLLO" = "y" ]; then
   bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
@@ -348,7 +318,7 @@
   bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
 fi
 bool 'Support for user misc device modules' CONFIG_UMISC
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_MAC" = "y" ]; then
   define_bool CONFIG_ABSTRACT_CONSOLE y
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.1.105/linux/arch/m68k/defconfig	Tue Mar 17 22:18:14 1998
+++ linux/arch/m68k/defconfig	Sat Jun 13 13:14:32 1998
@@ -45,6 +45,8 @@
 # CONFIG_AMIGA_GSP is not set
 # CONFIG_GSP_RESOLVER is not set
 # CONFIG_GSP_A2410 is not set
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
 
 #
 # Block device driver configuration
@@ -133,6 +135,8 @@
 # CONFIG_A4091_SCSI is not set
 # CONFIG_WARPENGINE_SCSI is not set
 CONFIG_ATARI_SCSI=y
+# CONFIG_ATARI_SCSI_TOSHIBA_DELAY is not set
+# CONFIG_ATARI_SCSI_RESET_BOOT is not set
 
 #
 # Network device support
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/Makefile linux/arch/m68k/hp300/Makefile
--- v2.1.105/linux/arch/m68k/hp300/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/Makefile	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,13 @@
+#
+# Makefile for Linux arch/m68k/hp300 source directory
+#
+# 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 := hp300.o
+O_OBJS	 := ksyms.o config.o ints.o time.o reboot.o hil.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/README.hp300 linux/arch/m68k/hp300/README.hp300
--- v2.1.105/linux/arch/m68k/hp300/README.hp300	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/README.hp300	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,14 @@
+HP300 notes
+-----------
+
+The Linux/HP web page is at <http://www.tazenda.demon.co.uk/phil/linux-hp/>
+
+Currently only 9000/340 machines have been tested.  Any amount of RAM should
+work now but I've only tried 16MB and 12MB.
+
+The serial console is probably broken at the moment but the Topcat/HIL keyboard
+combination seems to work for me.  Your mileage may vary.
+
+The LANCE driver works after a fashion but only if you reset the chip before
+every packet.  This doesn't make for very speedy operation.
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/config.c linux/arch/m68k/hp300/config.c
--- v2.1.105/linux/arch/m68k/hp300/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/config.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,78 @@
+/*
+ *  linux/arch/m68k/hp300/config.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific initialisation code.  It gets
+ *  called by setup.c.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/machdep.h>
+#include <asm/blinken.h>
+#include <asm/io.h>                               /* readb() and writeb() */
+#include <asm/hwtest.h>                           /* hwreg_present() */
+
+#include "ints.h"
+#include "time.h"
+
+extern void hp300_reset(void);
+extern void hp300_hil_init(void);
+
+#ifdef CONFIG_HEARTBEAT
+static void hp300_pulse(int x)
+{
+   if (x)
+      blinken_leds(0xfe);
+   else
+      blinken_leds(0xff);
+}
+#endif
+
+static int hp300_kbdrate(struct kbd_repeat *k)
+{
+  return 0;
+}
+
+static void hp300_kbd_leds(unsigned int leds)
+{
+}
+
+__initfunc(void config_hp300(void))
+{
+  mach_sched_init      = hp300_sched_init;
+  mach_keyb_init       = hp300_hil_init;
+  mach_kbdrate         = hp300_kbdrate;
+  mach_kbd_leds        = hp300_kbd_leds;
+  mach_init_IRQ        = hp300_init_IRQ;
+  mach_request_irq     = hp300_request_irq;
+  mach_free_irq        = hp300_free_irq;
+#if 0
+  mach_get_model       = hp300_get_model;
+  mach_get_irq_list    = hp300_get_irq_list;
+#endif
+  mach_gettimeoffset   = hp300_gettimeoffset;
+#if 0
+  mach_gettod          = hp300_gettod;
+#endif
+  mach_reset           = hp300_reset;
+#ifdef CONFIG_HEARTBEAT
+  mach_heartbeat       = hp300_pulse;
+#endif
+#ifdef CONFIG_FB
+  conswitchp	       = &fb_con;
+#endif
+  mach_max_dma_address = 0xffffffff;
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/hil.c linux/arch/m68k/hp300/hil.c
--- v2.1.105/linux/arch/m68k/hp300/hil.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/hil.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,250 @@
+/*
+ *  linux/arch/m68k/hp300/hil.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  HP300 Human Interface Loop driver.  This handles the keyboard and mouse.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/keyboard.h>
+#include <linux/kbd_ll.h>
+#include <asm/io.h>
+#include <asm/hwtest.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define HILBASE			0xf0428000
+#define HIL_DATA			0x1
+#define HIL_CMD			0x3
+
+#define	HIL_BUSY		0x02
+#define	HIL_DATA_RDY		0x01
+
+#define hil_busy()		(readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()	(readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()		(readb(HILBASE + HIL_CMD))
+#define hil_command(x)		do { writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data()		(readb(HILBASE + HIL_DATA))
+#define hil_write_data(x)	do { writeb((x), HILBASE + HIL_DATA); } while (0)
+
+#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
+#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
+#define	HIL_SETTONE		0xA3		/* set tone generator */
+#define	HIL_CNMT		0xB2		/* clear nmi */
+#define	HIL_INTON		0x5C		/* Turn on interrupts. */
+#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
+#define	HIL_TRIGGER		0xC5		/* trigger command */
+#define	HIL_STARTCMD		0xE0		/* start loop command */
+#define	HIL_TIMEOUT		0xFE		/* timeout */
+#define	HIL_READTIME		0x13		/* Read real time register */
+
+#define	HIL_READBUSY		0x02		/* internal "busy" register */
+#define	HIL_READKBDLANG		0x12		/* read keyboard language code */
+#define	HIL_READKBDSADR	 	0xF9
+#define	HIL_WRITEKBDSADR 	0xE9
+#define	HIL_READLPSTAT  	0xFA
+#define	HIL_WRITELPSTAT 	0xEA
+#define	HIL_READLPCTRL  	0xFB
+#define	HIL_WRITELPCTRL 	0xEB
+
+#define HIL_IRQ			1
+
+static u_short hp_plain_map[NR_KEYS] __initdata = {
+	0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf702, 0xf036,
+	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+	0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+	0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+	0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+	0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+	0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+	0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_shift_map[NR_KEYS] __initdata = {
+	0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf002, 0xf036,
+	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+	0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+	0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+	0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+	0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+	0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+	0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_ctrl_map[NR_KEYS] __initdata = {
+	0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+	0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+	0xf00f, 0xf010, 0xf003, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+	0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+	0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+	0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+struct {
+  unsigned char s, c;
+  int valid;
+} hil_last;
+
+#define hil_getlast(s,c)  do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
+
+struct {
+  unsigned char data[16];
+  unsigned int ptr;
+} poll;
+
+unsigned char curdev = 0;
+
+static void poll_finished(void)
+{
+  switch (poll.data[0])
+  {
+  case 0x40:
+    {
+      unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+#if 0
+      if (scode & 0x80)
+	printk("[%02x]", scode & 0x7f);
+#endif
+      handle_scancode(scode);
+    }
+    break;
+  }
+  curdev = 0;
+}
+
+static inline void handle_status(unsigned char s, unsigned char c)
+{
+  if (c & 0x8) {
+    /* End of block */
+    if (c & 0x10)
+      poll_finished();
+  } else {
+    if (c & 0x10) {
+      if (curdev)
+	poll_finished();		/* just in case */
+      curdev = c & 7;
+      poll.ptr = 0;
+    }
+  }
+}
+
+static inline void handle_data(unsigned char s, unsigned char c)
+{
+  if (curdev)
+    poll.data[poll.ptr++] = c;
+}
+
+/* 
+ * Handle HIL interrupts.
+ */
+
+static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+{
+  unsigned char s, c;
+  s = hil_status(); c = hil_read_data();
+  switch (s >> 4)
+  {
+  case 0x5:
+    handle_status(s, c);
+    break;
+  case 0x6:
+    handle_data(s, c);
+    break;
+  case 0x4:
+    hil_last.s = s;
+    hil_last.c = c;
+    mb();
+    hil_last.valid = 1;
+    break;
+  }
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+  unsigned long flags;
+  save_flags(flags); cli();
+  while (hil_busy());
+  hil_command(cmd);
+  while (len--) {
+    while (hil_busy());
+    hil_write_data(*(data++));
+  }
+  restore_flags(flags);
+}
+
+/*
+ * Initialise HIL. 
+ */
+
+__initfunc(void hp300_hil_init(void))
+{
+  unsigned char s, c, kbid;
+  unsigned int n = 0;
+
+  memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
+  memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
+  memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
+
+  if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
+    return;		/* maybe this can happen */
+
+  request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
+
+  /* Turn on interrupts */
+  hil_do(HIL_INTON, NULL, 0);
+
+  /* Look for keyboards */
+  hil_do(HIL_READKBDSADR, NULL, 0);
+  while (!hil_last.valid) {
+    if (n++ > 1000) {
+      printk("HIL: timed out, assuming no keyboard present.\n");
+      return;
+    }
+    mb();
+  }
+  hil_getlast(s, c);
+  if (c == 0) {
+    printk("HIL: no keyboard present.\n");
+    return;
+  }
+  for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
+  printk("HIL: keyboard found at id %d\n", kbid);
+  /* set it to raw mode */
+  c = 0;
+  hil_do(HIL_WRITEKBDSADR, &c, 1);
+}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/ints.c linux/arch/m68k/hp300/ints.c
--- v2.1.105/linux/arch/m68k/hp300/ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/ints.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,48 @@
+/*
+ *  linux/arch/m68k/hp300/ints.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific interrupt handling.  There
+ *  isn't much here -- we only use the autovector interrupts and at the
+ *  moment everything difficult is handled by the generic code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+static void hp300_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+  extern void hp300_reset(void);
+  printk("RESET pressed - self destruct sequence initiated.\n");
+  hp300_reset();
+}
+
+int hp300_request_irq(unsigned int irq,
+		void (*handler) (int, void *, struct pt_regs *),
+		unsigned long flags, const char *devname, void *dev_id)
+{
+  return sys_request_irq(irq, handler, flags, devname, dev_id);
+}
+
+void hp300_free_irq(unsigned int irq, void *dev_id)
+{
+  sys_free_irq(irq, dev_id);
+}
+
+__initfunc(void hp300_init_IRQ(void))
+{
+  /* IPL6 - NMI (keyboard reset) */
+  sys_request_irq(7, hp300_nmi_handler, IRQ_FLG_STD, "NMI", hp300_nmi_handler);
+}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/ints.h linux/arch/m68k/hp300/ints.h
--- v2.1.105/linux/arch/m68k/hp300/ints.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/ints.h	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,6 @@
+extern void hp300_init_IRQ(void);
+extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
+extern void hp300_free_irq(unsigned int irq, void *dev_id);
+extern int hp300_request_irq(unsigned int irq,
+		void (*handler) (int, void *, struct pt_regs *),
+		unsigned long flags, const char *devname, void *dev_id);
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/ksyms.c linux/arch/m68k/hp300/ksyms.c
--- v2.1.105/linux/arch/m68k/hp300/ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/ksyms.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,9 @@
+/*
+ *  linux/arch/m68k/hp300/ksyms.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific kernel symbols.  None yet. :-)
+ */
+
+#include <linux/module.h>
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/reboot.S linux/arch/m68k/hp300/reboot.S
--- v2.1.105/linux/arch/m68k/hp300/reboot.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/reboot.S	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,35 @@
+/*
+ *  linux/arch/m68k/hp300/reboot.S
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  Do the dirty work of rebooting the machine.  Basically we need to undo all the
+ *  good stuff that head.S did when we started up.  The caches and MMU must be
+ *  disabled and then we jump back to the PROM.  This is a bit gruesome but we put
+ *  a brave face on it.
+ */
+
+/* XXX Doesn't work yet.  Not sure why and can't be bothered to fix it at the moment. */
+
+	.globl	hp300_reset
+hp300_reset:
+	.chip	68030
+	oriw    #0x0700,%sr			/* cli() */
+	movel	hp300_phys_ram_base, %d1
+	movel	#0, %d0
+	movec	%d0, %vbr			/* reset vector table */
+	lea	zero, %a0
+	lea	1f, %a1
+	add	%d1, %a0
+	add	%d1, %a1
+	pmove	%tc, %a0@
+	bclr	#7, %a0@
+	pmove	%a0@, %tc			/* goodbye MMU */
+	jmp	%a1@
+1:	movel	#0x808, %d0
+	movec	%d0, %cacr			/* cache off */
+	moveb	#0, 0x1ffff
+	movel	#0x1a4, %a0
+	jmp	%a0@
+
+zero:	.quad	0
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/time.c linux/arch/m68k/hp300/time.c
--- v2.1.105/linux/arch/m68k/hp300/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/time.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,63 @@
+/*
+ *  linux/arch/m68k/hp300/time.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific time handling code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+/* Clock hardware definitions */
+
+#define CLOCKBASE	0xf05f8000
+
+#define	CLKCR1		0x1
+#define	CLKCR2		0x3
+#define	CLKCR3		CLKCR1
+#define	CLKSR		CLKCR2
+#define	CLKMSB1		0x5
+#define	CLKMSB2		0x9
+#define	CLKMSB3		0xD
+
+unsigned long hp300_gettimeoffset (void)
+{
+	return 0L;
+}
+
+static void hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long tmp;
+  void (*vector)(int, void *, struct pt_regs *) = dev_id;
+  readb(CLOCKBASE + CLKSR);
+  asm volatile ("movpw %1@(5),%0" : "=r" (tmp) : "a" (CLOCKBASE));
+  vector(irq, NULL, regs);
+}
+
+__initfunc(void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+  unsigned int intval = (10000 / 4) - 1;
+
+  writeb(0x1, CLOCKBASE + CLKCR2);		/* select CR1 */
+  writeb(0x1, CLOCKBASE + CLKCR1);		/* reset */
+
+  asm volatile(" movpw %0,%1@(5)" : : "d" (intval), "a" (CLOCKBASE));
+
+  sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+
+  writeb(0x1, CLOCKBASE + CLKCR2);		/* select CR1 */
+  writeb(0x40, CLOCKBASE + CLKCR1);		/* enable irq */
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/hp300/time.h linux/arch/m68k/hp300/time.h
--- v2.1.105/linux/arch/m68k/hp300/time.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/hp300/time.h	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,4 @@
+extern void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *));
+extern unsigned long hp300_gettimeoffset (void);
+
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v2.1.105/linux/arch/m68k/kernel/bios32.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/bios32.c	Sat Jun 13 13:14:32 1998
@@ -33,7 +33,6 @@
  *    been removed in this version.
  */
 
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/malloc.h>
 #include <linux/mm.h>
@@ -49,7 +48,7 @@
 #define GB		(1024*MB)
 
 #define MAJOR_REV	0
-#define MINOR_REV	0
+#define MINOR_REV	1
 
 /*
  * Base addresses of the PCI memory and I/O areas on the Hades.
@@ -264,12 +263,14 @@
 
 #define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
 
-__initfunc(static void layout_dev(struct pci_dev *dev))
+__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base,
+								  unsigned long pci_io_base))
 {
 	struct pci_bus *bus;
 	unsigned short cmd;
 	unsigned int base, mask, size, reg;
 	unsigned int alignto;
+	int i;
 
 	/*
 	 * Skip video cards for the time being.
@@ -283,7 +284,7 @@
 	bus = dev->bus;
 	pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
-	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
+	for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
 	{
 		/*
 		 * Figure out how much space and of what type this
@@ -297,6 +298,7 @@
 		if (!base)
 		{
 			/* this base-address register is unused */
+			dev->base_address[i] = 0;
 			continue;
 		}
 
@@ -322,6 +324,7 @@
 			io_base = base + size;
 			pcibios_write_config_dword(bus->number, dev->devfn,
 						   reg, base | 0x1);
+			dev->base_address[i] = (pci_io_base + base) | 1;
 			DBG_DEVS(("layout_dev: IO address: %lX\n", base));
 		}
 		else
@@ -369,6 +372,7 @@
 			mem_base = base + size;
 			pcibios_write_config_dword(bus->number, dev->devfn,
 						   reg, base);
+			dev->base_address[i] = pci_mem_base + base;
 		}
 	}
 
@@ -396,7 +400,8 @@
 		  bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
 }
 
-__initfunc(static void layout_bus(struct pci_bus *bus))
+__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base,
+								  unsigned long pci_io_base))
 {
 	struct pci_dev *dev;
 
@@ -438,7 +443,7 @@
 	for (dev = bus->devices; dev; dev = dev->sibling)
 	{
 		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
-			layout_dev(dev);
+			layout_dev(dev, pci_mem_base, pci_io_base);
 	}
 }
 
@@ -507,8 +512,7 @@
 		return 0;
 }
 
-__initfunc(unsigned long pcibios_init(unsigned long mem_start,
-				      unsigned long mem_end))
+__initfunc(void pcibios_init(void))
 {
 	printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
 
@@ -516,7 +520,8 @@
 	printk("...NOT modifying existing PCI configuration\n");
 #endif
 
-	return mem_start;
+	pci_mem_base = 0x80000000;
+	pci_io_base = 0xB0000000;
 }
 
 /*
@@ -555,26 +560,35 @@
 	}
 }
 
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start,
-				       unsigned long mem_end))
+__initfunc(void pcibios_fixup(void))
 {
 #if PCI_MODIFY
+	unsigned long orig_mem_base, orig_io_base;
+
+	orig_mem_base = pci_mem_base;
+	orig_io_base = pci_io_base;
+	pci_mem_base = 0;
+	pci_io_base = 0;
+
 	/*
 	 * Scan the tree, allocating PCI memory and I/O space.
 	 */
 
-	layout_bus(&pci_root);
-#endif
+	layout_bus(&pci_root, orig_mem_base, orig_io_base);
 
-	pci_mem_base = 0x80000000;
-	pci_io_base = 0xB0000000;
+	pci_mem_base = orig_mem_base;
+	pci_io_base = orig_io_base;
+#endif
 
 	/*
 	 * Now is the time to do all those dirty little deeds...
 	 */
 
 	hades_fixup();
+}
 
-	return mem_start;
+__initfunc(char *pcibios_setup(char *str))
+{
+	return str;
 }
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.105/linux/arch/m68k/kernel/entry.S	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/entry.S	Sat Jun 13 13:14:32 1998
@@ -579,6 +579,9 @@
 	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
 	.long SYMBOL_NAME(sys_lchown);
+	.long SYMBOL_NAME(sys_getcwd)
+	.long SYMBOL_NAME(sys_capget)
+	.long SYMBOL_NAME(sys_capset)           /* 185 */
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.1.105/linux/arch/m68k/kernel/head.S	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/head.S	Sat Jun 13 13:14:32 1998
@@ -17,6 +17,7 @@
 ** 95/11/18 Richard Hirst: Added MVME166 support
 ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
 ** 			      Magnum- and FX-alternate ram
+** 98/04/25 Phil Blundell: added HP300 support
 **
 ** This file is subject to the terms and conditions of the GNU General Public
 ** License. See the file README.legal in the main directory of this archive
@@ -73,10 +74,25 @@
 #include <asm/pgtable.h>
 
 .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
+.globl SYMBOL_NAME(availmem)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
 
+#if defined(CONFIG_MVME16x)
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+
+/*
+ * Added m68k_supervisor_cachemode for 68060 boards where some drivers
+ * need writethrough caching for supervisor accesses.  Drivers known to
+ * be effected are 53c7xx.c and apricot.c (when used on VME boards).
+ * Richard Hirst.
+ */
+
+#ifdef CONFIG_060_WRITETHROUGH
+.globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#endif
+
 D6B_0460 = 16		/* indicates 680[46]0 in d6 */
 D6B_060  = 17		/* indicates 68060 in d6 */
 D6F_040  = 1<<D6B_0460
@@ -146,12 +162,23 @@
 #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
 #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
 #define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
+#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
+#define is_not_hp300(lab) moveq &MACH_HP300,%d7	;  cmpl %d4,%d7; jne lab
 
 #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
 #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
 #define is_060(lab) btst &D6B_060,%d6; jne lab
 #define is_not_060(lab) btst &D6B_060,%d6; jeq lab
 
+/* On the HP300 we use the on-board LEDs for debug output before
+   the console is running.  Writing a 1 bit turns the corresponding LED
+   _off_ - on the 340 bit 7 is towards the back panel of the machine.  */
+#ifdef CONFIG_HP300
+#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
+#else
+#define leds(x)
+#endif
+
 .text
 ENTRY(_stext)
 /*
@@ -164,6 +191,7 @@
 	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
 	.long	MACH_MVME16x, MVME16x_BOOTI_VERSION
+	.long	MACH_BVME6000, BVME6000_BOOTI_VERSION
 	.long	0
 1:	jra	SYMBOL_NAME(_start)
 
@@ -224,6 +252,22 @@
 	movew	%d6,%d0
 	movel	%d0,%a0@		/* save cache mode for page tables */
 
+	/*
+	 * If this is a 68060 board using drivers with cache coherency
+	 * problems, then supervisor memory accesses need to be write-through
+         * also; otherwise, we want copyback.
+	 */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+	is_not_060(Lset_norm)
+	jra	1f
+Lset_norm:
+	move.w	#_PAGE_CACHE040,%d0
+1:
+  	lea	%pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+	movel	%d0,%a0@
+#endif
+
 /*
  * raise interrupt level
  */
@@ -386,7 +430,12 @@
 
 	movel	%a3,%a0
 	movel	%d5,%a1
-	addw	#_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#if defined(CONFIG_060_WRITETHROUGH)
+	addw	#_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+	addl	m68k_supervisor_cachemode,%a1
+#else
+	addw    #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#endif
 	movew	#(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
 	movel	#PAGESIZE,%d2
 1:	movel	%a1,%a0@+
@@ -424,6 +473,9 @@
 	 * of %a2 are forgotten.
 	 */
 Lnot040:
+
+	leds(0x4)
+	
 /*
  * Do any machine specific page table initializations.
  */
@@ -615,6 +667,21 @@
 Lnotatari:
 #endif
 
+#ifdef CONFIG_HP300
+	is_not_hp300(Lnothp300)
+
+/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
+   by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early 
+   termination page descriptor.  The ROM mapping is needed because the LEDs 
+   are mapped there too.  */
+
+	movel	#_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
+	movel	%d0,%a5@(0x78<<2)
+
+Lnothp300:
+	
+#endif
+
 #if defined(CONFIG_MVME16x)
 	is_not_mvme16x(Lnot16x)
 
@@ -639,6 +706,25 @@
 Lnot16x:
 #endif
 
+#if defined(CONFIG_BVME6000)
+	is_not_bvme6000(Lnotbvm)
+
+	/*
+	 * On BVME6000 we have already created kernel page tables for
+	 * 4MB of RAM at address 0, so now need to do a transparent
+	 * mapping of the top of memory space.  Make it 0.5GByte for now.
+	 */
+
+	movel	#0xe01f0000,%d2		/* logical address base */
+	orw	#0xa040,%d2		/* add in magic bits */
+	.long	0x4e7b2005		/* movec d2,ittr1 */
+	.long	0x4e7b2007		/* movec d2,dttr1 */
+	.long	0x4e7b2004		/* movec d2,ittr0 */
+	.long	0x4e7b2006		/* movec d2,dttr0 */
+
+Lnotbvm:
+#endif
+
 /*
  * Setup a transparent mapping of the physical memory we are executing in.
  *
@@ -647,6 +733,7 @@
  */
 Lmapphys:
 	putc('J')
+	leds(0x8)
 
 #ifdef CONFIG_AMIGA
 	is_not_amiga(Lmapphysnotamiga)
@@ -853,6 +940,80 @@
 
 #endif
 
+#if defined(CONFIG_HP300)
+	is_not_hp300(Lmapphysnothp300)
+
+/*
+ * Physical RAM is at 0xff000000.  We want to map the kernel at 0x00000000.
+ * In order to avoid disaster when we enable the MMU we need to make a
+ * transparent mapping of the RAM we're executing out of as well.
+ */
+	/*
+	 * save physaddr of phys mem in register a3
+	 */
+
+	.chip	68030
+	lea	%pc@(Lmmu),%a3
+	movel	%d5,%d0
+	andl	#0xff000000,%d0 /* logical address base */
+	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+	movel	%d0,%a3@
+	pmove	%a3@,%tt0
+	/* no limit, 4byte descriptors */
+	movel	#0x80000002,%a3@
+	movel	%a5,%a3@(4)
+	pmove	%a3@,%srp
+	pmove	%a3@,%crp
+	pflusha
+	/*
+	 * enable,super root enable,4096 byte pages,7 bit root index,
+	 * 7 bit pointer index, 6 bit page table index.
+	 */
+	movel	#0x82c07760,%a3@
+	pmove	%a3@,%tc	/* enable the MMU */
+	jmp	1f
+1:	
+	.chip	68k
+
+	/*
+	 * Fix up the custom register to point to the new location of the LEDs.
+	 */
+	lea	%pc@(Lcustom),%a1
+	movel	#0xf0000000,%a1@
+
+	/*
+	 * Energise the FPU and caches.
+	 */
+	orl	#0x64, 0xf05f400c 
+	
+Lmapphysnothp300:
+
+#endif
+
+#if defined(CONFIG_BVME6000)
+	is_not_bvme6000(Lmapphysnotbvm)
+	/*
+	 * save physaddr of phys mem in register a3
+	 */
+	moveq	#'L',%d7
+	jbsr	Lserial_putc
+
+	.word	0xf4d8		/* CINVA I/D    */
+	.word	0xf518		/* pflusha      */
+	.long	0x4e7bd807	/* movec a5,srp */
+	.long	0x4e7bd806	/* movec a5,urp */
+	movel	#(TC_ENABLE+TC_PAGE4K),%d0
+	/*
+	 * this value is also ok for the 68060, we don`t use the cache
+	 * mode/protection defaults
+	 */
+	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
+	jra	LdoneMMUenable	/* branch to continuation of startup */
+
+Lmapphysnotbvm:
+
+#endif
+
 LdoneMMUenable:
 
 /*
@@ -861,6 +1022,7 @@
  */
 
 	putc('M')
+	leds(0x10)
 
 	/*
 	 * d5 contains physaddr of kernel start
@@ -917,6 +1079,7 @@
 
 /* jump to the kernel start */
 	putr()
+	leds(0x55)
 
 	subl	%a6,%a6 /* clear a6 for gdb */
 	jbsr	SYMBOL_NAME(start_kernel)
@@ -998,6 +1161,11 @@
 #endif
 #endif
 
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
 /*
  * Serial port output support.
  */
@@ -1062,6 +1230,17 @@
 9:
 	rts
 
+#ifdef CONFIG_HP300
+/* Set LEDs to %d7 */
+	.even
+Lset_leds:
+	moveml	%a0/%a1,%sp@-
+	movel	%pc@(Lcustom),%a1
+	moveb	%d7,%a1@(0x1ffff)
+	moveml	%sp@+,%a0/%a1
+	rts
+#endif
+	
 /*
  * Output character in d7 on serial port.
  * d7 thrashed.
@@ -1073,6 +1252,16 @@
 	jne	2f
 	moveb	%d7,%sp@-
 	.long	0x4e4f0020
+	jra	9f
+2:
+#endif
+#ifdef CONFIG_BVME6000
+	cmpil	#MACH_BVME6000,%d4
+	jne	2f
+1:	btst	#2,BVME_SCC_CTRL_A
+	jeq	1b
+	moveb	%d7,BVME_SCC_DATA_A
+	jra	9f
 2:
 #endif
 #ifdef CONFIG_AMIGA
@@ -1199,5 +1388,11 @@
 	.long 0
 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
 	.long 0
+#ifdef CONFIG_060_WRITETHROUGH
+SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
+	.long 0
+#endif
+#if defined(CONFIG_MVME16x)
 SYMBOL_NAME_LABEL(mvme_bdid_ptr)
 	.long 0
+#endif
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.1.105/linux/arch/m68k/kernel/ints.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/ints.c	Sat Jun 13 13:14:32 1998
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -212,7 +213,7 @@
 
 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
 {
-	if (vec >= VEC_INT1 && vec <= VEC_INT7) {
+	if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
 		vec -= VEC_SPUR;
 		kstat.irqs[0][vec]++;
 		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.1.105/linux/arch/m68k/kernel/m68k_ksyms.c	Thu May 14 19:47:38 1998
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Sat Jun 13 13:14:32 1998
@@ -62,7 +62,3 @@
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.105/linux/arch/m68k/kernel/ptrace.c	Thu May  7 22:51:46 1998
+++ linux/arch/m68k/kernel/ptrace.c	Sat Jun 13 13:14:32 1998
@@ -347,9 +347,13 @@
 			goto out;
 		child->flags |= PF_PTRACED;
 		if (child->p_pptr != current) {
+			unsigned long flags;
+
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 		}
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
@@ -491,6 +495,7 @@
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
+			unsigned long flags;
 			long tmp;
 
 			ret = -EIO;
@@ -499,9 +504,11 @@
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = child->p_opptr;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 			/* make sure the single step bit is not set. */
 			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 			put_reg(child, PT_SR, tmp);
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.1.105/linux/arch/m68k/kernel/setup.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/setup.c	Sat Jun 13 13:14:32 1998
@@ -102,6 +102,8 @@
 extern void config_sun3(void);
 extern void config_apollo(void);
 extern void config_mvme16x(void);
+extern void config_bmve6000(void);
+extern void config_hp300(void);
 
 #define MASK_256K 0xfffc0000
 
@@ -249,6 +251,16 @@
 	    case MACH_MVME16x:
 	    	config_mvme16x();
 	    	break;
+#endif
+#ifdef CONFIG_BVME6000
+	    case MACH_BVME6000:
+	    	config_bvme6000();
+	    	break;
+#endif
+#ifdef CONFIG_HP300
+	    case MACH_HP300:
+		config_hp300();
+		break;
 #endif
 	    default:
 		panic ("No configuration setup");
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.1.105/linux/arch/m68k/kernel/signal.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/kernel/signal.c	Sat Jun 13 13:14:32 1998
@@ -875,6 +875,30 @@
 	do_exit(SIGSEGV);
 }
 
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+	switch (regs->d0) {
+	case -ERESTARTNOHAND:
+		if (!has_handler)
+			goto do_restart;
+		regs->d0 = -EINTR;
+		break;
+
+	case -ERESTARTSYS:
+		if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+			regs->d0 = -EINTR;
+			break;
+		}
+	/* fallthrough */
+	case -ERESTARTNOINTR:
+	do_restart:
+		regs->d0 = regs->orig_d0;
+		regs->pc -= 2;
+		break;
+	}
+}
+
 /*
  * OK, we're invoking a handler
  */
@@ -883,24 +907,9 @@
 	      sigset_t *oldset, struct pt_regs *regs)
 {
 	/* are we from a system call? */
-	if (regs->orig_d0 >= 0) {
+	if (regs->orig_d0 >= 0)
 		/* If so, check system call restarting.. */
-		switch (regs->d0) {
-			case -ERESTARTNOHAND:
-				regs->d0 = -EINTR;
-				break;
-
-			case -ERESTARTSYS:
-				if (!(ka->sa.sa_flags & SA_RESTART)) {
-					regs->d0 = -EINTR;
-					break;
-				}
-			/* fallthrough */
-			case -ERESTARTNOINTR:
-				regs->d0 = regs->orig_d0;
-				regs->pc -= 2;
-		}
-	}
+		handle_restart(regs, ka, 1);
 
 	/* set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
@@ -952,13 +961,14 @@
 
 			/* Did we come from a system call? */
 			if (regs->orig_d0 >= 0) {
-				/* Restart the system call */
-				if (regs->d0 == -ERESTARTNOHAND ||
-				    regs->d0 == -ERESTARTSYS ||
-				    regs->d0 == -ERESTARTNOINTR) {
-					regs->d0 = regs->orig_d0;
-					regs->pc -= 2;
-				}
+				/* Restart the system call the same way as
+				   if the process were not traced.  */
+				struct k_sigaction *ka =
+					&current->sig->action[signr-1];
+				int has_handler =
+					(ka->sa.sa_handler != SIG_IGN &&
+					 ka->sa.sa_handler != SIG_DFL);
+				handle_restart(regs, ka, has_handler);
 			}
 			notify_parent(current, SIGCHLD);
 			schedule();
@@ -1052,15 +1062,9 @@
 	}
 
 	/* Did we come from a system call? */
-	if (regs->orig_d0 >= 0) {
+	if (regs->orig_d0 >= 0)
 		/* Restart the system call - no handlers present */
-		if (regs->d0 == -ERESTARTNOHAND ||
-		    regs->d0 == -ERESTARTSYS ||
-		    regs->d0 == -ERESTARTNOINTR) {
-			regs->d0 = regs->orig_d0;
-			regs->pc -= 2;
-		}
-	}
+		handle_restart(regs, NULL, 0);
 
 	/* If we are about to discard some frame stuff we must copy
 	   over the remaining frame. */
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.105/linux/arch/m68k/kernel/sys_m68k.c	Thu May  7 22:51:46 1998
+++ linux/arch/m68k/kernel/sys_m68k.c	Sat Jun 13 13:14:32 1998
@@ -73,11 +73,14 @@
 
 	if (!(a.flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
-		if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+		file = fget(a.fd);
+		if (!file)
 			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+	if (file)
+		fput(file);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile
--- v2.1.105/linux/arch/m68k/mac/Makefile	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mac/Makefile	Sat Jun 13 13:14:32 1998
@@ -10,7 +10,8 @@
 EXTRA_CFLAGS := -Wa,-m68020
 
 O_TARGET := mac.o
-O_OBJS	 := config.o ksyms.o bootparse.o macints.o via6522.o \
+O_OBJS	 := config.o bootparse.o macints.o via6522.o \
 		mackeyb.o adb-bus.o macboing.o debug.o
+OX_OBJS  := mac_ksyms.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c
--- v2.1.105/linux/arch/m68k/mac/adb-bus.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/mac/adb-bus.c	Sat Jun 13 13:14:33 1998
@@ -93,6 +93,9 @@
 
 static int status = ST_IDLE|TREQ;
 static int last_status;
+
+static int driver_running = 0;
+
 /*static int adb_delay;*/
 int in_keybinit = 1;
 
@@ -106,11 +109,15 @@
 static void adb_hw_setup_IIsi(void);
 
 /*
- * Misc. defines for testing 
+ * debug level 10 required for ADB logging (should be && debug_adb, ideally)
  */
 
 extern int console_loglevel;
 
+/*
+ * Misc. defines for testing - should go to header :-(
+ */
+
 #define ADBDEBUG_STATUS		(1)
 #define ADBDEBUG_STATE		(2)
 #define ADBDEBUG_READ		(4)
@@ -128,7 +135,7 @@
 #define ADBDEBUG_IISI		(8192)
 
 
-#define DEBUG_ADB
+/*#define DEBUG_ADB*/
 
 #ifdef DEBUG_ADB
 #define ADBDEBUG	(ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
@@ -857,10 +864,22 @@
 void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
 	int x, adbdir;
+	unsigned long flags;
 	struct adb_request *req;
 
 	last_status = status;
 
+	/* prevent races due to SCSI enabling ints */
+	save_flags(flags);
+	cli();
+
+	if (driver_running) {
+		restore_flags(flags);
+		return;
+	}
+
+	driver_running = 1;
+	
 #ifdef USE_ORIG
 	status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
 #else
@@ -877,7 +896,6 @@
 			adb_state, status, last_status, adbdir);
 #endif
 
-
 	switch (adb_state) 
 	{
 		case idle:
@@ -1614,6 +1632,9 @@
 			printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
 #endif
 	}
+	/* reset mutex and interrupts */
+	driver_running = 0;
+	restore_flags(flags);
 }
 
 /*
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.1.105/linux/arch/m68k/mac/config.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/mac/config.c	Sat Jun 13 13:14:33 1998
@@ -38,17 +38,12 @@
 
 #include "via6522.h"
 
-/* old bootinfo stuff */
+/* Mac bootinfo struct */
 
 struct mac_booter_data mac_bi_data = {0,};
 int mac_bisize = sizeof mac_bi_data;
 
-struct compat_bootinfo compat_boot_info ={0,};
-int compat_bisize = sizeof compat_boot_info;
-
-int compat_bi = 0;
-
-/* New bootinfo stuff */
+/* New m68k bootinfo stuff and videobase */
 
 extern int m68k_num_memory;
 extern struct mem_info m68k_memory[NUM_MEMINFO];
@@ -59,7 +54,7 @@
 
 void *mac_env;		/* Loaded by the boot asm */
 
-/* The locgial video addr. determined by head.S - testing */
+/* The logical video addr. determined by head.S - testing */
 extern unsigned long mac_videobase;
 
 /* The phys. video addr. - might be bogus on some machines */
@@ -84,23 +79,22 @@
 extern void mac_debug_init(void);
 
 #ifdef CONFIG_MAGIC_SYSRQ
+
+/* XXX FIXME: Atari scancodes still */
 static char mac_sysrq_xlate[128] =
-	"\000\0331234567890-=\177\t"					/* 0x00 - 0x0f */
-	"qwertyuiop[]\r\000as"							/* 0x10 - 0x1f */
-	"dfghjkl;'`\000\\zxcv"							/* 0x20 - 0x2f */
-	"bnm,./\000\000\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\000\0331234567890-=\177\t"				/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"					/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"					/* 0x20 - 0x2f */
+	"bnm,./\000\000\000 \000\201\202\203\204\205"		/* 0x30 - 0x3f */
 	"\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
 	"\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-	"\000\000\000()/*789456123"						/* 0x60 - 0x6f */
+	"\000\000\000()/*789456123"				/* 0x60 - 0x6f */
 	"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
 #endif
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
-void mac_get_model(char *str)
-{
-	strcpy(str,"Macintosh");
-}
+static void mac_get_model(char *str);
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
 {
@@ -120,20 +114,21 @@
 
 extern int console_loglevel;
 
+/*
+ * This function translates the boot timeval into a proper date, to initialize
+ * the system time.
+ * Known problem: off by one after Feb. 27 on leap years
+ */
+
 void mac_gettod (int *yearp, int *monp, int *dayp,
 		 int *hourp, int *minp, int *secp)
 {
 	unsigned long time;
 	int leap, oldleap, isleap;
-	int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
+	int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
 
 	time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
 
-#if 0
-	printk("mac_gettod: boottime 0x%lx gmtbias %ld \n",
-		mac_bi_data.boottime, mac_bi_data.gmtbias);
-#endif	
-
 	*minp = time / 60;
 	*secp = time - (*minp * 60);
 	time  = *minp;				/* minutes now */
@@ -149,7 +144,7 @@
 	/* for leap day calculation */
 	*yearp = (time / 365) + 1970;		/* approx. year */
 
-	/* leap year calculation - there's an easier way, I bet */
+	/* leap year calculation - there's an easier way, I bet. And it's broken :-( */
 	/* calculate leap days up to previous year */
 	oldleap =  (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
 	/* calculate leap days incl. this year */
@@ -167,7 +162,7 @@
 	time = *dayp;
 	
 	if (isleap)				/* add leap day ?? */
-		mon_days[2] = 28;
+		mon_days[2] += 1;
 
 	/* count the months */
 	for (*monp = 1; time > mon_days[*monp]; (*monp)++) 
@@ -175,12 +170,6 @@
 
 	*dayp = time;
 
-#if 1
-	printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n",
-		*yearp, *monp, *dayp, *hourp, *minp, *secp, 
-		(signed long) mac_bi_data.gmtbias);
-#endif
-
 	return;
 }
 
@@ -189,13 +178,10 @@
 	;
 }
 
+extern struct consw fb_con;
+extern struct fb_info *mac_fb_init(long *);
 extern void mac_video_setup(char *, int *);
 
-void mac_debug_init (void)
-{
-	;
-}
-
 void (*mac_handlers[8])(int, void *, struct pt_regs *)=
 {
 	mac_default_handler,
@@ -222,6 +208,7 @@
 	    mac_bi_data.id = *data;
 	    break;
 	case BI_MAC_VADDR:
+	    /* save booter supplied videobase; use the one mapped in head.S! */
 	    mac_orig_videoaddr = *data;
 	    mac_bi_data.videoaddr = mac_videobase;
 	    break;
@@ -265,8 +252,6 @@
       printk("ERROR: no Mac, but config_mac() called!! \n");
     }
     
-    mac_debugging_penguin(5);
-
     mac_debug_init();
         
     mach_sched_init      = mac_sched_init;
@@ -289,9 +274,6 @@
     mach_mksound         = mac_mksound;
 #endif
     mach_reset           = mac_reset;
-#ifdef CONFIG_MAC_FLOPPY
-    mach_floppy_setup	 = mac_floppy_setup;
-#endif
     conswitchp	         = &fb_con;
     mach_max_dma_address = 0xffffffff;
 #if 0
@@ -330,12 +312,19 @@
 
     nubus_sweep_video();
 
-    mac_debugging_penguin(6);
 }	
 
 
 /*
- *	Macintosh Table
+ *	Macintosh Table: hardcoded model configuration data. 
+ *
+ *	Much of this was defined by Alan, based on who knows what docs. 
+ *	I've added a lot more, and some of that was pure guesswork based 
+ *	on hardware pages present on the Mac web site. Possibly wildly 
+ *	inaccurate, so look here if a new Mac model won't run. Example: if
+ *	a Mac crashes immediately after the VIA1 registers have been dumped
+ *	to the screen, it probably died attempting to read DirB on a RBV. 
+ *	Meaning it should have MAC_VIA_IIci here :-)
  */
  
 struct mac_model *macintosh_config;
@@ -359,10 +348,11 @@
 	 *
 	 *	The IIfx apparently has different ADB hardware, and stuff
 	 *	so zany nobody knows how to drive it.
+	 *	Even so, with Marten's help we'll try to deal with it :-)
 	 */
 
 	{	MAC_MODEL_IICI,	"IIci",	MAC_ADB_II,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_IIFX,	"IIfx",	MAC_ADB_NONE,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IIFX,	"IIfx",	MAC_ADB_II,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IISI, "IIsi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IIVI,	"IIvi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IIVX,	"IIvx",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -378,6 +368,7 @@
 	 *	Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
 	 */
 	
+	{	MAC_MODEL_LC,	"LC",	  MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_LCII,	"LC II",  MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 
@@ -389,32 +380,35 @@
 	 *	place to confuse us. The 840 seems to have a scsi location of its own
 	 */	 
 	 
-	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
- 	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+ 	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/*	The Q700 does have a NS Sonic */
-	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/* Does the 840 have ethernet ??? documents seem to indicate its not quite a
 	   Quadra in this respect ? */
-	{	MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	        MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,		MAC_NUBUS},
 	/* These might have IOP problems */
-	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 
 	/* 
 	 *	Performa - more LC type machines
 	 */
 
-	{	MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
-	{	MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_TV,   "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P460,  "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P475,  "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 #if 0	/* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
-	{	MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P630,  "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 #endif
 	/*
 	 *	Centris - just guessing again; maybe like Quadra
@@ -431,14 +425,14 @@
 	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	/*	The PB150 has IDE, and IIci style VIA */
-	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,	  MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,	 MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 
 	/*
@@ -446,7 +440,7 @@
 	 */
 
 	{	MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB280,  "PowerBook Duo 280",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -483,8 +477,6 @@
 	{
 		printk("\nUnknown macintosh model %d, probably unsupported.\n", 
 			model);
-		mac_debugging_long(1, (long) 0x55555555);
-		mac_debugging_long(1, (long) model);
 		model = MAC_MODEL_Q800;
 		printk("Defaulting to: Quadra800, model id %d\n", model);
 		printk("Please report this case to linux-mac68k@wave.lm.com\n");
@@ -502,7 +494,7 @@
 	/*
 	 * Report booter data:
 	 */
-	printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi);
+	printk (" Penguin bootinfo data:\n");
 	printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", 
 		mac_bi_data.videoaddr, mac_bi_data.videorow, 
 		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
@@ -534,6 +526,12 @@
 void mac_report_hardware(void)
 {
 	printk("Apple Macintosh %s\n", macintosh_config->name);
+}
+
+static void mac_get_model(char *str)
+{
+	strcpy(str,"Macintosh ");
+	strcat(str, macintosh_config->name);
 }
 
 /*
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.1.105/linux/arch/m68k/mac/debug.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/mac/debug.c	Sat Jun 13 13:14:33 1998
@@ -36,6 +36,9 @@
 extern unsigned long mac_videodepth;
 extern unsigned long mac_rowbytes;
 
+#define DEBUG_SCREEN
+#define DEBUG_SERIAL
+
 /*
  * These two auxiliary debug functions should go away ASAP. Only usage: 
  * before the console output is up (after head.S come some other crucial
@@ -46,21 +49,30 @@
  * The 'pos' argument now simply means 'linefeed after print' ...
  */
 
+#ifdef DEBUG_SCREEN
 static int peng=0, line=0;
+#endif
 
 void mac_debugging_short(int pos, short num)
 {
+#ifdef DEBUG_SCREEN
 	unsigned char *pengoffset;
 	unsigned char *pptr;
 	int i;
+#endif
+
+#ifdef DEBUG_SERIAL
+	printk("debug: %d !\n", num);
+#endif
 
+#ifdef DEBUG_SCREEN
 	if (!MACH_IS_MAC) {
 		/* printk("debug: %d !\n", num); */
 		return;
 	}
 
 	/* calculate current offset */
-	pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+	pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
 		    +80*peng;
 	
 	pptr=pengoffset;
@@ -77,20 +89,28 @@
 		line++;
 		peng = 0;
 	}
+#endif
 }
 
 void mac_debugging_long(int pos, long addr)
 {
+#ifdef DEBUG_SCREEN
 	unsigned char *pengoffset;
 	unsigned char *pptr;
 	int i;
+#endif
 
+#ifdef DEBUG_SERIAL
+	printk("debug: #%ld !\n", addr);
+#endif
+
+#ifdef DEBUG_SCREEN
 	if (!MACH_IS_MAC) {
 		/* printk("debug: #%ld !\n", addr); */
 		return;
 	}
 	
-	pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+	pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
 		    +80*peng;
 	
 	pptr=pengoffset;
@@ -106,6 +126,7 @@
 		line++;
 		peng = 0;
 	}
+#endif
 }
 
 /*
@@ -115,20 +136,29 @@
 #include "that_penguin.h"
 };
 
+#ifdef DEBUG_SCREEN
 /* 
  * B/W version of penguin, unfinished - any takers??
  */
 static char bw_penguin[]={
 #include "bw_penguin.h"
 };
+#endif
 
 void mac_debugging_penguin(int peng)
 {
+#ifdef DEBUG_SCREEN
 	unsigned char *pengoffset;
 	unsigned char *pptr;
 	unsigned char *bwpdptr=bw_penguin;
 	int i;
+#endif
 
+#ifdef DEBUG_SERIAL
+	printk("Penguin: #%d !\n", peng);
+#endif
+
+#ifdef DEBUG_SCREEN
 	if (!MACH_IS_MAC) 
 		return;
 
@@ -147,15 +177,19 @@
 		bwpdptr+=4;
 		pptr+=mac_rowbytes;
 	}
+#endif
 }
 
+#ifdef DEBUG_SCREEN
 /*
  * B/W version of flaming Mac, unfinished (see above).
  */
 static char bw_kaboom_map[]={
 #include "bw_mac.h"
 };
+#endif
 
+#ifdef DEBUG_SCREEN
 static void mac_boom_boom(void)
 {
 	static unsigned char *boomoffset=NULL;
@@ -163,6 +197,13 @@
 	unsigned char *bwpdptr=bw_kaboom_map;
 	int i;
 	
+#ifdef DEBUG_SERIAL
+	printk("BOOM !\n");
+#endif
+
+	if (!MACH_IS_MAC) 
+		return;
+
 	if(!boomoffset)
 		if (mac_videodepth == 1) {
 			boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
@@ -184,25 +225,43 @@
 		pptr+=mac_rowbytes;
 	}
 }
+#endif
 
 void mac_boom(int booms)
 {
+#ifdef DEBUG_SCREEN
 	int i;
+#endif
 
 	if (!MACH_IS_MAC) 
 		return;
 
+#ifdef DEBUG_SCREEN
 	for(i=0;i<booms;i++)
 		mac_boom_boom();
 	while(1);
+#endif
 }
 
 
-#if 0
+#ifdef DEBUG_SERIAL
 /*
  * TODO: serial debug code
  */
 
+#define SCC_BAS (0x50F04000)
+struct SCC
+ {
+  u_char cha_b_ctrl;
+  u_char char_dummy1;
+  u_char cha_a_ctrl;
+  u_char char_dummy2;
+  u_char cha_b_data;
+  u_char char_dummy3;
+  u_char cha_a_data;
+ };
+# define scc ((*(volatile struct SCC*)SCC_BAS))
+
 /* Flag that serial port is already initialized and used */
 int mac_SCC_init_done = 0;
 /* Can be set somewhere, if a SCC master reset has already be done and should
@@ -225,54 +284,113 @@
 
 static int scc_port;
 
-static inline void mac_scc_out (char c)
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
+
+#define US 1
+
+static inline void mac_sccb_out (char c)
 {
+    int i;
     do {
-	MFPDELAY();
+	for( i = US; i > 0; --i )
+		barrier();
     } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
-    MFPDELAY();
+    for( i = US; i > 0; --i )
+	barrier();
     scc.cha_b_data = c;
 }
 
-void mac_scc_console_write (struct console *co, const char *str,
+static inline void mac_scca_out (char c)
+{
+    int i;
+    do {
+	for( i = US; i > 0; --i )
+		barrier();
+    } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+    for( i = US; i > 0; --i )
+	barrier();
+    scc.cha_a_data = c;
+}
+
+void mac_sccb_console_write (struct console *co, const char *str,
 			      unsigned int count)
 {
     while (count--) {
 	if (*str == '\n')
-	    mac_scc_out( '\r' );
-	mac_scc_out( *str++ );
+	    mac_sccb_out( '\r' );
+	mac_sccb_out( *str++ );
+    }
+}
+
+void mac_scca_console_write (struct console *co, const char *str,
+			      unsigned int count)
+{
+    while (count--) {
+	if (*str == '\n')
+	    mac_scca_out( '\r' );
+	mac_scca_out( *str++ );
     }
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
-int mac_scc_console_wait_key(struct console *co)
+int mac_sccb_console_wait_key(struct console *co)
 {
+    int i;
     do {
-	MFPDELAY();
+	for( i = US; i > 0; --i )
+		barrier();
     } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
-    MFPDELAY();
+    for( i = US; i > 0; --i )
+	barrier();
     return( scc.cha_b_data );
 }
+
+int mac_scca_console_wait_key(struct console *co)
+{
+    int i;
+    do {
+	for( i = US; i > 0; --i )
+		barrier();
+    } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
+    for( i = US; i > 0; --i )
+	barrier();
+    return( scc.cha_a_data );
+}
 #endif
 
 /* The following two functions do a quick'n'dirty initialization of the MFP or
  * SCC serial ports. They're used by the debugging interface, kgdb, and the
  * serial console code. */
-#define SCC_WRITE(reg,val)				\
+#define SCCB_WRITE(reg,val)				\
     do {						\
+	int i;						\
 	scc.cha_b_ctrl = (reg);				\
-	MFPDELAY();					\
+	for( i = US; i > 0; --i )			\
+		barrier();				\
 	scc.cha_b_ctrl = (val);				\
-	MFPDELAY();					\
+	for( i = US; i > 0; --i )			\
+		barrier();				\
+    } while(0)
+
+#define SCCA_WRITE(reg,val)				\
+    do {						\
+	int i;						\
+	scc.cha_a_ctrl = (reg);				\
+	for( i = US; i > 0; --i )			\
+		barrier();				\
+	scc.cha_a_ctrl = (val);				\
+	for( i = US; i > 0; --i )			\
+		barrier();				\
     } while(0)
 
 /* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
  * delay of ~ 60us. */
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
 #define LONG_DELAY()				\
     do {					\
 	int i;					\
-	for( i = 100; i > 0; --i )		\
-	    MFPDELAY();				\
+	for( i = 60*US; i > 0; --i )		\
+	    barrier();				\
     } while(0)
     
 #ifndef CONFIG_SERIAL_CONSOLE
@@ -310,30 +428,56 @@
 
     reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
     reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
-    
-    (void)scc.cha_b_ctrl;	/* reset reg pointer */
-    SCC_WRITE( 9, 0xc0 );	/* reset */
-    LONG_DELAY();		/* extra delay after WR9 access */
-    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
-		  0x04 /* 1 stopbit */ |
-		  clkmode );
-    SCC_WRITE( 3, reg3 );
-    SCC_WRITE( 5, reg5 );
-    SCC_WRITE( 9, 0 );		/* no interrupts */
-    LONG_DELAY();		/* extra delay after WR9 access */
-    SCC_WRITE( 10, 0 );		/* NRZ mode */
-    SCC_WRITE( 11, clksrc );	/* main clock source */
-    SCC_WRITE( 12, div );	/* BRG value */
-    SCC_WRITE( 13, 0 );		/* BRG high byte */
-    SCC_WRITE( 14, brgsrc_table[baud] );
-    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
-    SCC_WRITE( 3, reg3 | 1 );
-    SCC_WRITE( 5, reg5 | 8 );
-    
+
+#if 0    
+    if (port) {
+#endif
+	    (void)scc.cha_b_ctrl;	/* reset reg pointer */
+	    SCCB_WRITE( 9, 0xc0 );	/* reset */
+	    LONG_DELAY();		/* extra delay after WR9 access */
+	    SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+			  0x04 /* 1 stopbit */ |
+			  clkmode );
+	    SCCB_WRITE( 3, reg3 );
+	    SCCB_WRITE( 5, reg5 );
+	    SCCB_WRITE( 9, 0 );		/* no interrupts */
+	    LONG_DELAY();		/* extra delay after WR9 access */
+	    SCCB_WRITE( 10, 0 );		/* NRZ mode */
+	    SCCB_WRITE( 11, clksrc );	/* main clock source */
+	    SCCB_WRITE( 12, div );	/* BRG value */
+	    SCCB_WRITE( 13, 0 );		/* BRG high byte */
+	    SCCB_WRITE( 14, brgsrc_table[baud] );
+	    SCCB_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+	    SCCB_WRITE( 3, reg3 | 1 );
+	    SCCB_WRITE( 5, reg5 | 8 );
+#if 0
+    } else {
+#endif
+	    (void)scc.cha_a_ctrl;	/* reset reg pointer */
+	    SCCA_WRITE( 9, 0xc0 );	/* reset */
+	    LONG_DELAY();		/* extra delay after WR9 access */
+	    SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+			  0x04 /* 1 stopbit */ |
+			  clkmode );
+	    SCCA_WRITE( 3, reg3 );
+	    SCCA_WRITE( 5, reg5 );
+	    SCCA_WRITE( 9, 0 );		/* no interrupts */
+	    LONG_DELAY();		/* extra delay after WR9 access */
+	    SCCA_WRITE( 10, 0 );		/* NRZ mode */
+	    SCCA_WRITE( 11, clksrc );	/* main clock source */
+	    SCCA_WRITE( 12, div );	/* BRG value */
+	    SCCA_WRITE( 13, 0 );		/* BRG high byte */
+	    SCCA_WRITE( 14, brgsrc_table[baud] );
+	    SCCA_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+	    SCCA_WRITE( 3, reg3 | 1 );
+	    SCCA_WRITE( 5, reg5 | 8 );
+#if 0
+    }
+#endif
     mac_SCC_reset_done = 1;
     mac_SCC_init_done = 1;
 }
-
+#endif /* DEBUG_SERIAL */
 
 __initfunc(void mac_debug_init(void))
 {
@@ -341,23 +485,24 @@
     /* the m68k_debug_device is used by the GDB stub, do nothing here */
     return;
 #endif
+#ifdef DEBUG_SERIAL
     if (!strcmp( m68k_debug_device, "ser" )) {
 	strcpy( m68k_debug_device, "ser1" );
     }
     if (!strcmp( m68k_debug_device, "ser1" )) {
 	/* ST-MFP Modem1 serial port */
 	mac_init_scc_port( B9600|CS8, 0 );
-	mac_console_driver.write = mac_scc_console_write;
+	mac_console_driver.write = mac_scca_console_write;
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
 	/* SCC Modem2 serial port */
 	mac_init_scc_port( B9600|CS8, 1 );
-	mac_console_driver.write = mac_scc_console_write;
+	mac_console_driver.write = mac_sccb_console_write;
     }
     if (mac_console_driver.write)
 	register_console(&mac_console_driver);
-}
 #endif
+}
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/ksyms.c linux/arch/m68k/mac/ksyms.c
--- v2.1.105/linux/arch/m68k/mac/ksyms.c	Wed Apr  8 19:36:25 1998
+++ linux/arch/m68k/mac/ksyms.c	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-/* Hook for mouse driver */
-extern void (*mac_mouse_interrupt_hook) (char *);
-
-EXPORT_SYMBOL(mac_mouse_interrupt_hook);
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/mac_ksyms.c linux/arch/m68k/mac/mac_ksyms.c
--- v2.1.105/linux/arch/m68k/mac/mac_ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/mac_ksyms.c	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+/* Hook for mouse driver */
+extern void (*mac_mouse_interrupt_hook) (char *);
+
+EXPORT_SYMBOL(mac_mouse_interrupt_hook);
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.1.105/linux/arch/m68k/mac/macints.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/mac/macints.c	Sat Jun 13 13:14:33 1998
@@ -28,6 +28,12 @@
  *
  *	7	- Debug output
  *
+ * AV Macs only, handled by PSC:
+ *
+ *	3	- MACE ethernet IRQ (DMA complete on level 4)
+ *
+ *	5	- DSP ?? 
+ *
  * Using the autovector irq numbers for Linux/m68k hardware interrupts without
  * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt 
  * handling in kernel versions 2.0.x, so the following strategy is used:
@@ -57,6 +63,10 @@
  *   should be sufficient to use the same numbers (everything > 7 is assumed 
  *   to be machspec, according to Jes!).
  *
+ *   TODO:
+ * - integrate Nubus interrupts in request/free_irq
+ *
+ * - 
  */
 
 #include <linux/types.h>
@@ -64,6 +74,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h> /* for intr_count */
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -98,7 +109,10 @@
 static struct irqhandler  via1_handler[8];
 static struct irqhandler  via2_handler[8];
 static struct irqhandler   rbv_handler[8];
+static struct irqhandler  psc3_handler[8];
 static struct irqhandler   scc_handler[8];
+static struct irqhandler  psc5_handler[8];
+static struct irqhandler  psc6_handler[8];
 static struct irqhandler nubus_handler[8];
 
 static struct irqhandler *handler_table[8];
@@ -111,7 +125,10 @@
 static struct irqparam  via1_param[8];
 static struct irqparam  via2_param[8];
 static struct irqparam   rbv_param[8];
+static struct irqparam  psc3_param[8];
 static struct irqparam   scc_param[8];
+static struct irqparam  psc5_param[8];
+static struct irqparam  psc6_param[8];
 static struct irqparam nubus_param[8];
 
 static struct irqparam *param_table[8];
@@ -125,27 +142,51 @@
 
 /*
  * This array holds the pointers to the various VIA or other interrupt 
- * controllers
+ * controllers, indexed by interrupt level
  */
 
 static volatile unsigned char *via_table[8];
 
-#ifdef VIABASE_WEIRDNESS
 /*
- * VIA2 / RBV default base address 
+ * Arrays with irq statistics
  */
+static unsigned long via1_irqs[8];
+static unsigned long via2_irqs[8];
+static unsigned long rbv_irqs[8];
+static unsigned long psc3_irqs[8];
+static unsigned long scc_irqs[8];
+static unsigned long psc5_irqs[8];
+static unsigned long psc6_irqs[8];
+static unsigned long nubus_irqs[8];
 
-volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS);
-volatile unsigned char *rbv_regp  = ((volatile unsigned char *)VIA2_BAS_IIci);
-#endif
+static unsigned long *mac_irqs[8];
+
+/*
+ * VIA2 / RBV register base pointers
+ */
+
+volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
+volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci;
+volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS;
+volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS;
 
 /*
  * Flags to control via2 / rbv behaviour
  */ 
 
 static int via2_is_rbv = 0;
+static int via2_is_oss = 0;
 static int rbv_clear = 0;
 
+/* fake VIA2 to OSS bit mapping */
+static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5};
+
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs);
+
+/* PSC ints */
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs);
+
 /*
  * console_loglevel determines NMI handler function
  */
@@ -177,6 +218,10 @@
 #ifdef DEBUG_MACINTS
 	printk("Mac interrupt stuff initializing ...\n");
 #endif
+
+	via2_regp = (unsigned char *)VIA2_BAS;
+	rbv_regp  = (unsigned char *)VIA2_BAS_IIci;
+
         /* initialize the hardwired (primary, autovector) IRQs */
 
 	/* level 1 IRQ: VIA1, always present */
@@ -184,17 +229,34 @@
 
 	/* via2 or rbv?? */
 	if (macintosh_config->via_type == MAC_VIA_IIci) {
-		/* VIA2 is part of the RBV: different base, other offsets */
-		via2_is_rbv = 1;
-		/* LC III weirdness: IFR seems to behave like VIA2 */
-		/* FIXME: maybe also for LC II ?? */ 
-		if (macintosh_config->ident == MAC_MODEL_LCIII) {
-			rbv_clear = 0x0;
+		/*
+		 * A word of caution: the definitions here only affect interrupt
+		 * handling, see via6522.c for yet another file to change
+		 * base addresses and RBV flags
+		 */
+
+		/* yes, this is messy - the IIfx deserves a class of his own */
+		if (macintosh_config->ident == MAC_MODEL_IIFX) {
+			/* no real VIA2, the OSS seems _very_different */	
+			via2_is_oss = 1;
+			/* IIfx has OSS, at a different base address than RBV */
+			if (macintosh_config->ident == MAC_MODEL_IIFX)
+				rbv_regp = (unsigned char *) OSS_BAS;
+			sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq);
 		} else {
-			rbv_clear = 0x80;
+			/* VIA2 is part of the RBV: different base, other offsets */
+			via2_is_rbv = 1;
+
+			/* LC III weirdness: IFR seems to behave like VIA2 */
+			/* FIXME: maybe also for LC II ?? */ 
+			if (macintosh_config->ident == MAC_MODEL_LCIII) {
+				rbv_clear = 0x0;
+			} else {
+				rbv_clear = 0x80;
+			}
+			/* level 2 IRQ: RBV/OSS; we only care about RBV for now */
+			sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
 		}
-		/* level 2 IRQ: RBV/OSS; we only care about RBV for now */
-		sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
 	} else
 		/* level 2 IRQ: VIA2 */
 		sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
@@ -205,7 +267,7 @@
 	 *		Currently, one interrupt per channel is used, solely
 	 *		to pass the correct async_info as parameter!
 	 */
-#if 0	/* doesn't seem to work yet */
+#if 0	/* want to install debug/SCC shutup routine until SCC init */
 	sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler);
 #else
 	sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
@@ -253,24 +315,64 @@
 	via_table[0]     =  via1_regp;
 	handler_table[0] =  &via1_handler[0];
 	param_table[0]   =  &via1_param[0];
+	mac_irqs[0]	 =  &via1_irqs[0];
 
 	if (via2_is_rbv) {
 		via_table[1]     =  rbv_regp;
 		handler_table[1] =  &rbv_handler[0];
 		param_table[1]   =  &rbv_param[0];
+		mac_irqs[1]	 =  &rbv_irqs[0];
 	} else {
 		via_table[1]     =  via2_regp;
 		handler_table[1] =  &via2_handler[0];
 		param_table[1]   =  &via2_param[0];
+		mac_irqs[1]	 =  &via2_irqs[0];
 	}
 	via_table[2]     =  NULL;
 	via_table[3]     =  NULL;
 	
 	handler_table[2] =   &rbv_handler[0];
-	handler_table[3] = &nubus_handler[0];
+	handler_table[3] =  &scc_handler[0];
+	handler_table[4] =  NULL;
+	handler_table[5] =  NULL;
+	handler_table[6] =  NULL;
+	handler_table[7] = &nubus_handler[0];
 
 	param_table[2]   =   &rbv_param[0];
-	param_table[3]   = &nubus_param[0];
+	param_table[3]   =  &scc_param[0];
+	param_table[7]   = &nubus_param[0];
+
+	mac_irqs[2]	 =  &rbv_irqs[0];
+	mac_irqs[3]	 =  &scc_irqs[0];
+	mac_irqs[7]	 =  &nubus_irqs[0];
+
+	/*
+	 *	AV Macs: shutup the PSC ints
+	 */
+	if (macintosh_config->ident == MAC_MODEL_C660
+	 || macintosh_config->ident == MAC_MODEL_Q840) {
+		psc_init();
+
+		handler_table[2] = &psc3_handler[0];
+		/* handler_table[3] = &psc4_handler[0]; */
+		handler_table[4] = &psc5_handler[0];
+		handler_table[5] = &psc6_handler[0];
+
+		param_table[2]   = &psc3_param[0];
+		/* param_table[3]   = &psc4_param[0]; */
+		param_table[4]   = &psc5_param[0];
+		param_table[5]   = &psc6_param[0];
+
+		mac_irqs[2]	 = &psc3_irqs[0]; 
+		/* mac_irqs[3]	 = &psc4_irqs[0]; */
+		mac_irqs[4]	 = &psc5_irqs[0];
+		mac_irqs[5]	 = &psc6_irqs[0];
+
+		sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq);
+		sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq);
+		sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq);
+		sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq);
+	}
 
 #ifdef DEBUG_MACINTS
 	printk("Mac interrupt init done!\n");
@@ -281,7 +383,7 @@
  *	We have no machine specific interrupts on a macintoy
  *      Yet, we need to register/unregister interrupts ... :-)
  *      Currently unimplemented: Test for valid irq number, chained irqs,
- *      Nubus interrupts.
+ *      Nubus interrupts (use nubus_request_irq!).
  */
  
 int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -312,8 +414,8 @@
 		return -EINVAL;
 	} 
 
-	/* figure out if SCC pseudo-irq */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+	/* figure out if SCC pseudo-irq (redundant ??) */
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
 		/* set specific SCC handler */
 		scc_handler[irqidx].handler = handler;
 		scc_handler[irqidx].dev_id  = dev_id;
@@ -323,6 +425,8 @@
 		return 0;
 	} 
 
+	/* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
+
 	via         = (volatile unsigned char *) via_table[srcidx];
 	if (!via) 
 		return -EINVAL;
@@ -338,9 +442,11 @@
 	via_param[irqidx].flags     = flags;
 	via_param[irqidx].devname   = devname;
 
-	/* and turn it on ... */
+	/* and turn it on ... careful, that's VIA only ... */
 	if (srcidx == SRC_VIA2 && via2_is_rbv)
 		via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+	else if (srcidx == SRC_VIA2 && via2_is_oss)
+		via_write(oss_regp, oss_map[irqidx]+8, 2);
 	else
 		via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
 
@@ -348,8 +454,18 @@
 	if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
 		/*
 		 * Set vPCR for SCSI interrupts. (what about RBV here?)
+		 * 980429 MS: RBV is ok, OSS seems to be differentt
 		 */
-		via_write(via, vPCR, 0x66);
+		if (!via2_is_oss)
+			/* CB2 (IRQ) indep. interrupt input, positive edge */
+			/* CA2 (DRQ) indep. interrupt input, positive edge */
+			via_write(via, vPCR, 0x66);
+#if 0
+		else
+			/* CB2 (IRQ) indep. interrupt input, negative edge */
+			/* CA2 (DRQ) indep. interrupt input, negative edge */
+			via_write(via, vPCR, 0x22);
+#endif
 	}
 
 	return 0;
@@ -379,7 +495,7 @@
 	cli();
 
 	/* figure out if SCC pseudo-irq */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
 		/* clear specific SCC handler */
 		scc_handler[irqidx].handler = mac_default_handler;
 		scc_handler[irqidx].dev_id  = NULL;
@@ -408,6 +524,8 @@
 	/* and turn it off */
 	if (srcidx == SRC_VIA2 && via2_is_rbv)
 		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+	else if (srcidx == SRC_VIA2 && via2_is_oss)
+		via_write(oss_regp, oss_map[irqidx]+8, 0);
 	else
 		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
 
@@ -450,8 +568,8 @@
 
 void mac_enable_irq (unsigned int irq)
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 
 	irq_flags[srcidx].disabled &= ~(1<<irqidx);
 	/*
@@ -465,8 +583,8 @@
 
 void mac_disable_irq (unsigned int irq)
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 
 	irq_flags[srcidx].disabled |= (1<<irqidx);
 }
@@ -478,8 +596,8 @@
 
 void mac_turnon_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 	volatile unsigned char *via;
 
 	via         = (volatile unsigned char *) via_table[srcidx];
@@ -488,6 +606,11 @@
 
 	if (srcidx == SRC_VIA2 && via2_is_rbv)
 	        via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+	else if (srcidx == SRC_VIA2 && via2_is_oss)
+		via_write(oss_regp, oss_map[irqidx]+8, 2);
+	else if (srcidx >= SRC_VIA2)
+	        via_write(via, (0x104 + 0x10*srcidx), 
+	        	via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
 	else
 	        via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
 
@@ -495,8 +618,8 @@
 
 void mac_turnoff_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 	volatile unsigned char *via;
 
 	via         = (volatile unsigned char *) via_table[srcidx];
@@ -505,6 +628,11 @@
 
 	if (srcidx == SRC_VIA2 && via2_is_rbv)
 		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+	else if (srcidx == SRC_VIA2 && via2_is_oss)
+		via_write(oss_regp, oss_map[irqidx]+8, 0);
+	else if (srcidx >= SRC_VIA2)
+	        via_write(via, (0x104 + 0x10*srcidx), 
+	        	via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
 	else
 		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
 }
@@ -519,23 +647,91 @@
 
 void mac_clear_pending_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 
 	irq_flags[srcidx].pending &= ~(1<<irqidx);
 }
 
 int  mac_irq_pending( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx = (irq & IRQ_IDX_MASK);
 
 	return (irq_flags[srcidx].pending & (1<<irqidx));
 }
 
 int mac_get_irq_list (char *buf)
 {
-	return 0;
+	int i, len = 0;
+	int srcidx, irqidx;
+
+	for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+		srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
+		irqidx = (i & IRQ_IDX_MASK);
+
+		/*
+		 * Not present: skip
+		 */
+
+		if (mac_irqs[srcidx] == NULL)
+			continue;
+
+		/* 
+		 * never used by VIAs, unused by others so far, counts 
+		 * the magic 'nothing pending' cases ...
+		 */
+		if (irqidx == 7 && mac_irqs[srcidx][irqidx]) {
+			len += sprintf(buf+len, "Level %01d: %10u (spurious) \n",
+				       srcidx, 
+				       mac_irqs[srcidx][irqidx]);
+			continue;
+		}
+
+		/*
+		 * Nothing registered for this IPL: skip
+		 */
+
+		if (handler_table[srcidx] == NULL)
+			continue;
+
+		/*
+		 * No handler installed: skip
+		 */ 
+
+		if (handler_table[srcidx][irqidx].handler == mac_default_handler ||
+		    handler_table[srcidx][irqidx].handler == nubus_wtf)
+			continue;
+
+
+		if (i < VIA2_SOURCE_BASE)
+			len += sprintf(buf+len, "via1  %01d: %10u ",
+				       irqidx,
+				       mac_irqs[srcidx][irqidx]);
+		else if (i < RBV_SOURCE_BASE)
+			len += sprintf(buf+len, "via2  %01d: %10u ",
+				       irqidx,
+				       mac_irqs[srcidx][irqidx]);
+		else if (i < MAC_SCC_SOURCE_BASE)
+			len += sprintf(buf+len, "rbv   %01d: %10u ",
+				       irqidx,
+				       mac_irqs[srcidx][irqidx]);
+		else if (i < NUBUS_SOURCE_BASE)
+			len += sprintf(buf+len, "scc   %01d: %10u ",
+				       irqidx,
+				       mac_irqs[srcidx][irqidx]);
+		else /* Nubus */
+			len += sprintf(buf+len, "nubus %01d: %10u ",
+				       irqidx,
+				       mac_irqs[srcidx][irqidx]);
+
+			len += sprintf(buf+len, "%s\n", 
+				       param_table[srcidx][irqidx].devname);
+
+	}
+	if (num_spurious)
+		len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+	return len;
 }
 
 void via_scsi_clear(void)
@@ -544,6 +740,9 @@
 	if (via2_is_rbv) {
 		via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
 		deep_magic = via_read(rbv_regp, rBufB);
+	} else if (via2_is_oss) {
+		/* nothing */
+		/* via_write(oss_regp, 9, 0) */;
 	} else
 		deep_magic = via_read(via2_regp, vBufB);
 	mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
@@ -567,12 +766,24 @@
 	}
 }
 
+void scsi_mac_debug(void);
+void scsi_mac_polled(void);
+
 void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
+	int i;
 	/* 
 	 * generate debug output on NMI switch if 'debug' kernel option given
 	 * (only works with Penguin!)
 	 */
+#if 0
+	scsi_mac_debug();
+	printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
+#endif
+	for (i=0; i<100; i++)
+		udelay(1000);
+	scsi_mac_polled();
+
 	if ( console_loglevel >= 8 ) {
 #if 0
 		show_state();
@@ -607,6 +818,7 @@
 	int ct = 0;
 	struct irqhandler *via_handler = handler_table[*viaidx];
 	struct irqparam   *via_param   = param_table[*viaidx];
+	unsigned long     *via_irqs    = mac_irqs[*viaidx];
 
 	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
 	 * flag bit, ack and call handler ...
@@ -623,7 +835,12 @@
 	 
 	if(events==0)
 	{
-		printk("via%d_irq: nothing pending!\n", *viaidx + 1);
+#ifdef DEBUG_VIA
+		/* should go away; mostly missing timer ticks and ADB events */
+		printk("via%d_irq: nothing pending, flags %x mask %x!\n",
+			*viaidx + 1, via_read(via, vIFR), via_read(via,vIER));
+#endif
+		via_irqs[7]++;
 		return;
 	}
 
@@ -658,9 +875,12 @@
 		        /* call corresponding handlers */
 		        if (events&(1<<i)) {
 			        if (irq_flags[*viaidx].disabled & (1<<i)) {
+					if (!irq_flags[*viaidx].pending&(1<<i))
+						via_irqs[i]++;
 				        /* irq disabled -> mark pending */
 				        irq_flags[*viaidx].pending |= (1<<i);
 				} else {
+					via_irqs[i]++;
 				        /* irq enabled -> call handler */
 				        (via_handler[i].handler)(irq, via, regs);
 				}
@@ -683,7 +903,9 @@
 		ct++;
 		if(events && ct>8)
 		{
+#ifdef DEBUG_VIA
 		        printk("via%d: stuck events %x\n", (*viaidx)+1, events);
+#endif
 		        break;
 		}
 	}
@@ -740,6 +962,23 @@
 	struct irqhandler *via_handler = handler_table[srcidx];
 	struct irqparam   *via_param   = param_table[srcidx];
 
+        /* shouldn't we disable interrupts here ?? */
+
+	
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+#ifdef DEBUG_VIA
+		printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+			via_read(via, rIFR), via_read(via,rIER));
+#endif
+		rbv_irqs[7]++;
+		return;
+	}
+
 #ifdef DEBUG_VIA	
 	/*
 	 * limited verbosity for RBV interrupts (add more if needed)
@@ -754,19 +993,6 @@
 	 * If ack for masked IRQ required: keep 'pending' info separate.
 	 */
 
-        /* shouldn't we disable interrupts here ?? */
-
-	
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-		printk("rbv_irq: nothing pending!\n");
-		return;
-	}
-	
 	do {
 		/*
 		 *	Clear the pending flag
@@ -784,12 +1010,16 @@
 			int irq = (srcidx+1)* 8 + i;
 		        /* call corresponding handlers */
 		        if (events&(1<<i)) {
-			        if (irq_flags[srcidx].disabled & (1<<i))
+			        if (irq_flags[srcidx].disabled & (1<<i)) {
+					if (!irq_flags[srcidx].pending&(1<<i))
+						rbv_irqs[i]++;
 				        /* irq disabled -> mark pending */
 				        irq_flags[srcidx].pending |= (1<<i);
-				else
+				} else {
+					rbv_irqs[i]++;
 				        /* irq enabled -> call handler */
 				        (via_handler[i].handler)(irq, via, regs);
+				}
 			}
 			/* and call handlers for pending irqs - first ?? */
 			if (    (irq_flags[srcidx].pending  & (1<<i))
@@ -800,7 +1030,7 @@
 				irq_flags[srcidx].pending  &= ~(1<<i);
 			}
 		}
-	
+
 		/*
 		 *	And done ... check for more punishment!
 		 */
@@ -840,24 +1070,277 @@
 #endif
 }
 
+/*
+ *	Nubus / SCSI interrupts; OSS style
+ *	The OSS is even more different than the RBV. OSS appears to stand for 
+ *	Obscenely Screwed Silicon ... 
+ *
+ *	Latest NetBSD sources suggest the OSS should behave like a RBV, but 
+ *	that's probably true for the 0x203 offset (Nubus/ADB-SWIM IOP) at best
+ */
+ 
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int srcidx = IRQ_IDX(irq) - 1;	/* MUST be 1 !! */
+	volatile unsigned char *via = oss_regp;
+	unsigned char events=(via_read(via, oIFR))&0x03;
+	unsigned char nub_ev=(via_read(via, nIFR))&0x4F;
+	unsigned char adb_ev;
+	int i;
+	int ct = 0;
+	struct irqhandler *via_handler = handler_table[srcidx];
+	struct irqparam   *via_param   = param_table[srcidx];
+
+        /* shouldn't we disable interrupts here ?? */
+
+	adb_ev = nub_ev & 0x40;
+	nub_ev &= 0x3F;
+
+	/*
+	 *	Shouldnt happen
+	 */
+
+	if (events==0 && adb_ev==0 && nub_ev==0)
+	{
+		printk("oss_irq: nothing pending, flags %x %x!\n",
+			via_read(via, oIFR), via_read(via, nIFR));
+		rbv_irqs[7]++;
+		return;
+	}
+
+#ifdef DEBUG_VIA	
+	/*
+	 * limited verbosity for RBV interrupts (add more if needed)
+	 */
+	if ( events != 1<<3 )		/* SCSI IRQ */
+		printk("oss_irq: irq %d events %x %x %x !\n", irq, srcidx+1, 
+			events, adb_ev, nub_ev);
+#endif
+
+	/* 
+	 * OSS priorities: call ADB handler first if registered, other events,
+	 * then Nubus 
+	 * ADB: yet to be implemented!
+	 */
+
+	/*
+	 * ADB: try to shutup the IOP 
+	 */
+	if (adb_ev) {
+		printk("Hands off ! Don't press this button ever again !!!\n");
+		via_write(via, 6, 0);
+	}
+
+	do {
+		/*
+		 *	Clear the pending flags
+		 *	How exactly is that supposed to work ??
+		 */
+
+		/*
+		 *	Now see what bits are raised
+		 */
+		 
+		for(i=0;i<7;i++)
+		{
+			/* HACK HACK: map to bit number in OSS register */
+			int irqidx = oss_map[i];
+			/* determine machspec. irq no. */
+			int irq = (srcidx+1)* 8 + i;
+		        /* call corresponding handlers */
+		        if ( (events&(1<<irqidx)) && 		/* bit set*/
+		             (via_read(via, irqidx+8)&0x7) ) {	/* irq enabled */
+			        if (irq_flags[srcidx].disabled & (1<<i)) {
+					if (!irq_flags[srcidx].pending&(1<<i))
+						rbv_irqs[i]++;
+				        /* irq disabled -> mark pending */
+				        irq_flags[srcidx].pending |= (1<<i);
+				} else {
+					rbv_irqs[i]++;
+				        /* irq enabled -> call handler */
+				        (via_handler[i].handler)(irq, via, regs);
+				}
+			}
+			/* and call handlers for pending irqs - first ?? */
+			if (    (irq_flags[srcidx].pending  & (1<<i))
+			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+				/* call handler for re-enabled irq */
+			        (via_handler[i].handler)(irq, via, regs);
+				/* and clear pending flag :-) */
+				irq_flags[srcidx].pending  &= ~(1<<i);
+			}
+		}
+	
+		/*
+		 *	And done ... check for more punishment!
+		 */
+
+		events=(via_read(via, oIFR)/*&via_read(via,rIER)*/)&0x03;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("oss: stuck events %x\n",events);
+			for(i=0;i<7;i++)
+			{
+				if(events&(1<<i))
+				{
+					printk("oss - bashing source %d\n",
+						i);
+					/* that should disable it */
+					via_write(via, 8+i, 0);
+				}
+			}
+		        break;
+		}
+	}
+	while(events);
+#if 0
+	scsi_mac_polled();
+#endif
+
+	if (nub_ev)
+		oss_do_nubus(irq, via, regs);
+
+}
+
+/*
+ *	Unexpected slot interrupt
+ */
+ 
 void nubus_wtf(int slot, void *via, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA
+#ifdef DEBUG_VIA_NUBUS
 	printk("Unexpected interrupt on nubus slot %d\n",slot);
 #endif
 }
 
+/*
+ *	SCC master interrupt handler; sole purpose: pass the registered 
+ *	async struct to the SCC handler proper.
+ */
+
 void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int i;
-
-	for (i = 0; i < 8; i++) 
+				/* 1+2: compatibility with PSC ! */
+	for (i = 1; i < 3; i++) /* currently only these two used */
 		if (scc_handler[i].handler != mac_default_handler)
 			(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
 
 }
 
 /*
+ *	PSC interrupt handler
+ */
+
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int srcidx = IRQ_IDX(irq) - 1;
+	volatile unsigned char *via = psc_regp;
+	unsigned int pIFR = 0x100 + 0x10*srcidx;
+	unsigned int pIER = 0x104 + 0x10*srcidx;
+	unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF;
+	int i;
+	int ct = 0;
+	struct irqhandler *via_handler = handler_table[srcidx];
+	struct irqparam   *via_param   = param_table[srcidx];
+
+        /* shouldn't we disable interrupts here ?? */
+
+	
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+#ifdef DEBUG_VIA
+		printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+			via_read(via, pIFR), via_read(via,pIER));
+#endif
+		mac_irqs[srcidx][7]++;
+		return;
+	}
+
+#ifdef DEBUG_VIA	
+	/*
+	 * limited verbosity for RBV interrupts (add more if needed)
+	 */
+	if ( srcidx == 1 && events != 1<<3 && events != 1<<1 )		/* SCSI IRQ */
+		printk("psc_irq: irq %d events %x !\n", irq, srcidx+1, events);
+#endif
+
+	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
+	 * flag bit, ack and call handler ...
+         * Currently: all pending irqs ack'ed en bloc.
+	 * If ack for masked IRQ required: keep 'pending' info separate.
+	 */
+
+	do {
+		/*
+		 *	Clear the pending flag
+		 */
+		 
+		/* via_write(via, pIFR, events); */
+		 
+		/*
+		 *	Now see what bits are raised
+		 */
+		 
+		for(i=0;i<7;i++)
+		{
+			/* determine machspec. irq no. */
+			int irq = (srcidx+1)* 8 + i;
+		        /* call corresponding handlers */
+		        if (events&(1<<i)) {
+			        if (irq_flags[srcidx].disabled & (1<<i)) {
+					if (!irq_flags[srcidx].pending&(1<<i))
+						mac_irqs[srcidx][i]++;
+				        /* irq disabled -> mark pending */
+				        irq_flags[srcidx].pending |= (1<<i);
+				} else {
+					mac_irqs[srcidx][i]++;
+				        /* irq enabled -> call handler */
+				        (via_handler[i].handler)(irq, via, regs);
+				}
+			}
+			/* and call handlers for pending irqs - first ?? */
+			if (    (irq_flags[srcidx].pending  & (1<<i))
+			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+				/* call handler for re-enabled irq */
+			        (via_handler[i].handler)(irq, via, regs);
+				/* and clear pending flag :-) */
+				irq_flags[srcidx].pending  &= ~(1<<i);
+			}
+		}
+
+		/*
+		 *	And done ... check for more punishment!
+		 */
+
+		events=(via_read(via,pIFR)&via_read(via,pIER))&0x7F;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("psc: stuck events %x\n",events);
+			for(i=0;i<7;i++)
+			{
+				if(events&(1<<i))
+				{
+					printk("psc - bashing source %d\n",
+						i);
+					via_write(via, pIER, 1<<i);
+					/* via_write(via, pIFR, (1<<i)); */
+				}
+			}
+		        break;
+		}
+	}
+	while(events);
+}
+
+
+/*
  *	Nubus handling
  *      Caution: slot numbers are currently 'hardcoded' to the range 9-15!
  *      In general, the same request_irq() functions as above can be used if
@@ -875,16 +1358,17 @@
 	nubus_handler[slot].handler=handler;
 	nubus_handler[slot].dev_id =dev_id;
 	nubus_param[slot].flags    = IRQ_FLG_LOCK;
-	nubus_param[slot].devname  = "nubus";
+	nubus_param[slot].devname  = "nubus slot";
 
 	/* 
 	 * if no nubus int. was active previously: register the main nubus irq
 	 * handler now!
 	 */
 
-	if (!nubus_active)
-	  request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
-		      "nubus dispatch", via_do_nubus);
+	if (!nubus_active && !via2_is_oss) {
+		request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
+			    "nubus dispatch", via_do_nubus);
+	}
 
 	nubus_active|=1<<slot;
 /*	printk("program slot %d\n",slot);*/
@@ -894,7 +1378,9 @@
 		via_read(via2, vDirA)|(1<<slot));
 	via_write(via2, vBufA, 0);
 #endif		
-	if (!via2_is_rbv) {
+	if (via2_is_oss)
+		via_write(oss_regp, slot, 2);
+	else if (!via2_is_rbv) {
 		/* Make sure the bit is an input */
 		via_write(via2_regp, vDirA, 
 			via_read(via2_regp, vDirA)&~(1<<slot));
@@ -914,6 +1400,8 @@
 
 	if (via2_is_rbv)
 		via_write(rbv_regp, rBufA, 1<<slot);
+	else if (via2_is_oss)
+		via_write(oss_regp, slot, 0);
 	else {
 		via_write(via2_regp, vDirA, 
 			via_read(via2_regp, vDirA)|(1<<slot));
@@ -924,6 +1412,16 @@
 	return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+/*
+ * IDE interrupt hook
+ */
+extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+#endif
+
+/*
+ * Nubus dispatch handler - VIA/RBV style
+ */
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
 {
 	unsigned char map;
@@ -938,6 +1436,14 @@
 	else
 		via_write(via2_regp, vIFR, 0x82);
 	
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+	/* IDE hack */
+	if (mac_ide_intr_hook)
+		/* 'slot' is lacking the machspec bit in 2.0 */
+		/* need to pass proper dev_id = hwgroup here */
+		mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+#endif
+
 	while(1)
 	{
 		if (via2_is_rbv)
@@ -945,15 +1451,23 @@
 		else
 			map = ~via_read(via2_regp, vBufA);
 		
-#ifdef DEBUG_VIA
-		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+		if( (map = (map&nubus_active)) ==0 ) {
+#ifdef DEBUG_NUBUS_INT
+			printk("nubus_irq: nothing pending, map %x mask %x\n", 
+				map, nubus_active);
 #endif
-		if( (map = (map&nubus_active)) ==0 )
+			nubus_irqs[7]++;
 			break;
+		}
+#ifdef DEBUG_NUBUS_INT
+		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
 
 		if(ct++>2)
 		{
+#ifdef DEBUG_NUBUS_INT
 			printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
 			return;
 		}
 
@@ -961,6 +1475,7 @@
 		{
 			if(map&(1<<i))
 			{
+				nubus_irqs[i]++;
 				(nubus_handler[i].handler)(i+9, nubus_handler[i].dev_id, regs);
 			}
 		}
@@ -970,6 +1485,75 @@
 		else
 			via_write(via2_regp, vIFR, 0x02);
 
+	}
+	
+	/* And done */
+}
+
+/*
+ * Nubus dispatch handler - OSS style
+ */
+static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
+{
+	unsigned char map;
+	int i;
+	int ct=0;
+
+/*	printk("nubus interrupt\n");*/
+		
+#if 0
+	/* lock the nubus interrupt */
+	if (via2_is_rbv) 
+		via_write(rbv_regp, rIFR, 0x82);
+	else
+		via_write(via2_regp, vIFR, 0x82);
+#endif
+
+	/* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */
+	if (mac_ide_intr_hook)
+		mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+	
+	while(1)
+	{
+		/* pending events */
+		map=(via_read(via, nIFR))&0x3F;
+		
+#ifdef DEBUG_VIA_NUBUS
+		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
+		if( (map = (map&nubus_active)) ==0 ) {
+			if (!mac_ide_intr_hook)
+				printk("nubus_irq: nothing pending, map %x mask %x\n", 
+					map, nubus_active);
+			nubus_irqs[7]++;
+			break;
+		}
+
+		if(ct++>2)
+		{
+#if 0
+			printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
+			return;
+		}
+
+		for(i=0;i<7;i++)
+		{
+			if(map&(1<<i))
+			{
+				nubus_irqs[i]++;
+				/* call handler */
+				(nubus_handler[i].handler)((i+9), nubus_handler[i].dev_id, regs);
+				/* clear interrupt ?? */
+#if 0
+				via_write(oss_regp, i, 0);
+#endif
+			}
+		}
+		/* clear it */ 
+#if 0
+		via_write(oss_regp, nIFR, map);
+#endif
 	}
 	
 	/* And done */
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c
--- v2.1.105/linux/arch/m68k/mac/mackeyb.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/mac/mackeyb.c	Sat Jun 13 13:14:33 1998
@@ -600,13 +600,13 @@
 	volatile int ct;
 
 	/* setup key map */
-	memcpy (plain_map, mac_plain_map, sizeof(plain_map));
-	memcpy(shift_map, mac_shift_map, sizeof(shift_map));
-	memcpy(altgr_map, mac_altgr_map, sizeof(altgr_map));
-	memcpy(ctrl_map, mac_ctrl_map, sizeof(ctrl_map));
-	memcpy(shift_ctrl_map, mac_shift_ctrl_map, sizeof(shift_ctrl_map));
-	memcpy(alt_map, mac_alt_map, sizeof(alt_map));
-	memcpy(ctrl_alt_map, mac_ctrl_alt_map, sizeof(ctrl_alt_map));
+	memcpy(key_maps[0], mac_plain_map, sizeof(plain_map));
+	memcpy(key_maps[1], mac_shift_map, sizeof(plain_map));
+	memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map));
+	memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map));
+	memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map));
+	memcpy(key_maps[8], mac_alt_map, sizeof(plain_map));
+	memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map));
 
 	/* initialize mouse interrupt hook */
 	mac_mouse_interrupt_hook = NULL;
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/psc.h linux/arch/m68k/mac/psc.h
--- v2.1.105/linux/arch/m68k/mac/psc.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/psc.h	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,18 @@
+/*
+ *	Apple Peripheral System Controller (PSC)
+ *
+ *	The PSC is used on the AV Macs to control IO functions not handled
+ *	by the VIAs (Ethernet, DSP, SCC).
+ */
+ 
+#define PSCBASE		0x50F31000
+
+#define pIFR3		0x130
+#define pIFR4		0x140
+#define pIFR5		0x150
+#define pIFR6		0x160
+
+#define pIER3		0x134
+#define pIER4		0x144
+#define pIER5		0x154
+#define pIER6		0x164
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c
--- v2.1.105/linux/arch/m68k/mac/via6522.c	Mon Feb 23 18:12:02 1998
+++ linux/arch/m68k/mac/via6522.c	Sat Jun 13 13:14:33 1998
@@ -1,4 +1,3 @@
-
 /*
  *	6522 Versatile Interface Adapter (VIA)
  *
@@ -6,6 +5,7 @@
  *	via them as are assorted bits and bobs - eg rtc, adb.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -13,75 +13,27 @@
 #include <asm/macintosh.h> 
 #include <asm/macints.h> 
 #include "via6522.h"
+#include "psc.h"
 
 volatile unsigned char *via1=(unsigned char *)VIABASE;
 volatile unsigned char *via2=(unsigned char *)VIABASE2;
+volatile unsigned char *psc=(unsigned char *)PSCBASE;
 
 unsigned char via1_clock, via1_datab;
 
 static int rbv=0;
+static int oss=0;
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
 
 /*
- * Debugging the VBL ints
+ * hardware reset vector
  */
-
-extern int console_loglevel;
+static void (*rom_reset)(void);
 
 /*
- *	VIA1 - hardwired vectors
+ * Timer defs.
  */
-
-#if 0 /* gone to macints.[ch] */
-extern void via_wtf(int slot, void *via, struct pt_regs *regs);
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs);
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
-static struct via_irq_tab via1_func_tab=
-{
-	{
-		via_wtf,	/* One second interrupt */
-		via_wtf,	/* Vblank */
-		via_wtf,       	/* ADB data ready */
-		via_wtf,	/* ADB data */
-		via_wtf,	/* ADB clock */
-		via_wtf,
-		via_wtf,	/* Slot 6 is replaced by the timer */
-		via_wtf
-	}
-};
-
-static struct via_irq_tab via2_func_tab=
-{
-	{
-		via_wtf,
-		via_do_nubus,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf
-	}
-};
-
-static struct via_irq_tab nubus_func_tab=
-{
-	{
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf,
-		via_wtf
-	}
-};
-#endif
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
 #define MAC_CLOCK_TICK		(783300/HZ)	/* ticks per HZ */
 #define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
@@ -91,8 +43,6 @@
 {
 	unsigned char c;
 
-/*	mac_debugging_penguin(6);*/
-	
 	switch(macintosh_config->via_type)
 	{
 		/*
@@ -102,6 +52,10 @@
 			via1=(void *)0x50F00000;
 			via2=(void *)0x50F26000;
 			rbv=1;
+			if (macintosh_config->ident == MAC_MODEL_IIFX) {
+				via2=(void *)0x50F1A000;
+				oss=1;
+			}
 			break;
 		/*
 		 *      Quadra and early MacIIs agree on the VIA locations
@@ -162,7 +116,7 @@
 		via_write(via2,vT2CH,0);
 		via_write(via2,vIER, 0x7F);	 
 	}
-	else
+	else if (oss==0)
 	{
 		/*
 		 *	Init the RBV chip a bit
@@ -201,30 +155,18 @@
 	
 	request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
 
-/*	mac_debugging_penguin(7);*/
-
 	/* 
 	 * SE/30: disable video int. 
 	 * XXX: testing for SE/30 VBL
 	 */
 
-	if (macintosh_config->ident == MAC_MODEL_SE30 
-	    && console_loglevel != 10) {
+	if (macintosh_config->ident == MAC_MODEL_SE30) {
 		c = via_read(via1, vBufB);
 		via_write(via1, vBufB, c|(0x40));
 		c = via_read(via1, vDirB);
 		via_write(via1, vDirB, c|(0x40));
 	} 
 
-	/*
-	 * XXX: use positive edge
-	 */
-
-	if (console_loglevel == 10) {
-		c = via_read(via1, vPCR);
-		via_write(via1, vPCR, c|(0x1));
-	}
-
 #if 0 /* gone to mac_init_IRQ */
 	/*
 	 * Set vPCR for SCSI interrupts.
@@ -237,172 +179,29 @@
 
 }
 
-#if 0 /* moved to macints.c */
-
-static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
-	struct pt_regs *regs)
-{
-	unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-	int i;
-	int ct=0;	
-
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-		printk("via_irq: nothing pending!\n");
-		return;
-	}
-
-	do {
-		/*
-		 *	Clear the pending flag
-		 */
-
-		/* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-	
-		/* events&=~(1<<4); */		 
-		via_write(via, vIFR, events);
-	 
-		/*
-		 *	Now see what bits are raised
-		 */
-	 
-		for(i=0;i<7;i++)
-		{
-			if(events&(1<<i))
-				(irqtab->vector[i])(i, via, regs);
-		}
-	
-		/*
-		 *	And done..
-		 */
-		events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-		ct++;
-		if(events && ct>8)
-		{
-		        printk("via: stuck events %x\n",events);
-		        break;
-		}
-	}
-	while(events);
-
-	scsi_mac_polled();
-}
-
-/*
- *
- *	The RBV is different. RBV appears to stand for randomly broken
- *	VIA.
- */
-
-static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
-	struct pt_regs *regs)
-{
-	unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-	int i;
-	int ct=0;	
-
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-		printk("rbv_irq: nothing pending!\n");
-		return;
-	}
-
-	do {
-		/*
-		 *	Clear the pending flag
-		 */
-
-		/* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-	
-		/* events&=~(1<<4); */		 
-		via_write(via, rIFR, events);
-	 
-		/*
-		 *	Now see what bits are raised
-		 */
-	 
-		for(i=0;i<7;i++)
-		{
-			if(events&(1<<i))
-				(irqtab->vector[i])(i, via, regs);
-		}
-	
-		/*
-		 *	And done..
-		 */
-		events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-		ct++;
-		if(events && ct>8)
-		{
-		        printk("rbv: stuck events %x\n",events);
-			for(i=0;i<7;i++)
-			{
-				if(events&(1<<i))
-				{
-					printk("rbv - bashing source %d\n",
-						i);
-					via_write(via, rIER, i);
-					via_write(via, rIFR, i);
-				}
-			}
-		        break;
-		}
-	}
-	while(events);
-}
-
 /*
- *	System interrupts
+ *	PSC (AV Macs; level 3-6): initialize interrupt enable registers
  */
 
-void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+void psc_init(void)
 {
-	via_irq(via1, &via1_func_tab, regs);
+	via_write(psc, pIER3, 0x01);
+	via_write(psc, pIER4, 0x09);
+	via_write(psc, pIER4, 0x86);
+	via_write(psc, pIER5, 0x03);
+	via_write(psc, pIER6, 0x07);
 }
 
 /*
- *	Nubus interrupts
- */
- 
-void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-/*	printk("via2 interrupt\n");*/
-	if(rbv)
-		rbv_irq(via2, &via2_func_tab, regs);
-	else
-		via_irq(via2, &via2_func_tab, regs);
-}
-
-/*
- *	Unexpected via interrupt
- */
- 
-void via_wtf(int slot, volatile void *via, struct pt_regs *regs)
-{
-	printk("Unexpected event %d on via %p\n",slot,via);
-}
-
-void nubus_wtf(int slot, volatile void *via, struct pt_regs *regs)
-{
-	printk("Unexpected interrupt on nubus slot %d\n",slot);
-}
-
-#endif
-
-/*
  *	The power switch - yes its software!
  */
  
-void mac_reset(void)
+void mac_poweroff(void)
 {
+#if 0
+	/*
+	 * Powerdown, for the Macs that support it
+	 */
 	if(rbv)	{
 		via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
 	} else {
@@ -411,7 +210,38 @@
 		/* Send a value of 0 on that line */
 		via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
 	}
+#endif
+	/* We should never make it this far... */
+	/* XXX - delay do we need to spin here ? */
+	while(1);	/* Just in case .. */
+}
+
+/* 
+ * Not all Macs support software power down; for the rest, just 
+ * try the ROM reset vector ...
+ */
+void mac_reset(void)
+{
+	unsigned long flags;
+	unsigned long *reset_hook;
+
+	save_flags(flags);
+	cli();
+
+#if 0	/* need ROMBASE in booter */
+#if 0	/* works on some */
+	rom_reset = (boot_info.bi_mac.rombase + 0xa);
+#else	/* testing, doesn't work on SE/30 either */
+	reset_hook = (unsigned long *) (boot_info.bi_mac.rombase + 0x4);
+	printk("ROM reset hook: %p\n", *reset_hook);
+	rom_reset = *reset_hook;
+#endif
+	rom_reset();
+#endif
+	restore_flags(flags);
+
 	/* We never make it this far... */
+	printk(" reboot failed, reboot manually!\n");
 	/* XXX - delay do we need to spin here ? */
 	while(1);	/* Just in case .. */
 }
@@ -442,140 +272,13 @@
 		via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
 }
 
-#if 0 /* moved to macints.c */
-
-
-/*
- *    Set up the SCSI
- */
-
-void via_scsi_disable(void)
-{
-	if (rbv)
-		via_write(via2, rIER, (1<<3)|(1<<0));
-	else
-		via_write(via2, vIER, (1<<3)|(1<<0));
-}
-
-void via_scsi_enable(void)
-{
-	if (rbv)
-		via_write(via2, rIER, (1<<3)|(1<<0)|0x80);
-	else
-		via_write(via2, vIER, (1<<3)|(1<<0)|0x80);
-}
-
-void via_scsi_clear(void)
-{
-        if (rbv) 
-		via_write(via2, rIFR, (1<<3)|(1<<0)|0x80);
-	volatile unsigned char deep_magic=via_read(via2, vBufB);
-	via_scsi_enable();
-}
- 
-void via_setup_scsi(void (*handler)(int,volatile void *,struct pt_regs *))
-{
-	via2_func_tab.vector[0]=handler;        /* SCSI DRQ */
-	via2_func_tab.vector[3]=handler;        /* SCSI IRQ */
-	via_write(via2, vPCR, 0x66);		/* Edge direction! */
-	via_scsi_enable();
-}
-
-/*
- *	Nubus handling
- */
- 
-static int nubus_active=0;
- 
-int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
-{
-	slot-=9;
-/*	printk("Nubus request irq for slot %d\n",slot);*/
-	if(nubus_func_tab.vector[slot]==nubus_wtf)
-		return -EBUSY;
-	nubus_func_tab.vector[slot]=handler;
-	nubus_active|=1<<slot;
-/*	printk("program slot %d\n",slot);*/
-/*	printk("via2=%p\n",via2);*/
-#if 0
-	via_write(via2, vDirA, 
-		via_read(via2, vDirA)|(1<<slot));
-	via_write(via2, vBufA, 0);
-#endif		
-	if (!rbv) {
-	/* Make sure the bit is an input */
-	via_write(via2, vDirA, 
-		via_read(via2, vDirA)&~(1<<slot));
-	}
-/*	printk("nubus irq on\n");*/
-	return 0;
-}
-
-int nubus_free_irq(int slot)
-{
-	slot-=9;
-	nubus_active&=~(1<<slot);
-	nubus_func_tab.vector[slot]=nubus_wtf;
-	if (rbv) {
-		via_write(via2, rBufA, 1<<slot);
-	} else {
-		via_write(via2, vDirA, 
-			via_read(via2, vDirA)|(1<<slot));
-		via_write(via2, vBufA, 1<<slot);
-		via_write(via2, vDirA, 
-			via_read(via2, vDirA)&~(1<<slot));
-	}
-	return 0;
-}
-
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs)
-{
-	unsigned char map;
-	int i;
-	int ct=0;
-
-/*	printk("nubus interrupt\n");*/
-		
-	if (rbv) {
-		via_write(via2, rIFR, 0x82);	/* lock the nubus interrupt */
-	} else {
-		via_write(via2, vIFR, 0x82);	/* lock the nubus interrupt */
-		
-	while(1)
-	{
-		if(rbv)
-			map=~via_read(via2, rBufA);
-		else
-			map=~via_read(via2, vBufA);
-		if((map=(map&nubus_active))==0)
-			break;
-		if(ct++>2)
-		{
-			printk("nubus stuck events - %d/%d\n", map, nubus_active);
-			return;
-		}
-		for(i=0;i<7;i++)
-		{
-			if(map&(1<<i))
-			{
-				(nubus_func_tab.vector[i])(i+9, via, regs);
-			}
-		}
-		if (rbv)
-			via_write(via2, rIFR, 0x02);	/* clear it */
-		else
-			via_write(via2, vIFR, 0x02);	/* clear it */
-	}
-	
-	/* And done */
-}
-#endif
-
 void nubus_init_via(void)
 {
 	if (rbv) {
-		via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
-		via_write(via2, rIER, 0x82);	/* Interrupts on */
+		if (oss==0) {
+			via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
+			via_write(via2, rIER, 0x82);	/* Interrupts on */
+		}
 	} else {
 		/* Assert the nubus active */
 		via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
@@ -584,7 +287,13 @@
 		/* via_write(via2, vDirA, 0xFF); */
 		via_write(via2, vIER, 0x82);	/* Interrupts on */
 	}
-	printk("BTW  boot via1 acr=%X datab=%X pcr=%X\n",
-		(int)via1_clock, (int)via1_datab, (int)via_read(via1, vPCR));
-}
 
+	printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n",
+		(int)via_read(via1, vACR), (int)via_read(via1, vBufB), 
+		(int)via_read(via1, vPCR));
+
+	if (rbv==0)
+		printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n",
+			(int)via_read(via2, vACR), (int)via_read(via2, vBufB), 
+			(int)via_read(via2, vPCR));
+}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile
--- v2.1.105/linux/arch/m68k/mm/Makefile	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mm/Makefile	Sat Jun 13 13:14:33 1998
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o memory.o kmap.o extable.o
+O_OBJS	 := init.o fault.o memory.o kmap.o extable.o hwtest.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.1.105/linux/arch/m68k/mm/fault.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mm/fault.c	Sat Jun 13 13:14:33 1998
@@ -48,6 +48,8 @@
 	vma = find_vma(mm, address);
 	if (!vma)
 	  goto bad_area;
+	if (vma->vm_flags & VM_IO)
+		goto bad_area;
 	if (vma->vm_start <= address)
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mm/hwtest.c linux/arch/m68k/mm/hwtest.c
--- v2.1.105/linux/arch/m68k/mm/hwtest.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mm/hwtest.c	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,81 @@
+/* Tests for presence or absence of hardware registers.
+ * This code was originally in atari/config.c, but I noticed
+ * that it was also in drivers/nubus/nubus.c and I wanted to
+ * use it in hp300/config.c, so it seemed sensible to pull it
+ * out into its own file.
+ * 
+ * The test is for use when trying to read a hardware register
+ * that isn't present would cause a bus error. We set up a 
+ * temporary handler so that this doesn't kill the kernel.
+ *
+ * There is a test-by-reading and a test-by-writing; I present
+ * them here complete with the comments from the original atari
+ * config.c...
+ *                -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998
+ */
+
+/* This function tests for the presence of an address, specially a
+ * hardware register address. It is called very early in the kernel
+ * initialization process, when the VBR register isn't set up yet. On
+ * an Atari, it still points to address 0, which is unmapped. So a bus
+ * error would cause another bus error while fetching the exception
+ * vector, and the CPU would do nothing at all. So we needed to set up
+ * a temporary VBR and a vector table for the duration of the test.
+ */
+
+int hwreg_present( volatile void *regp )
+{
+    int	ret = 0;
+    long	save_sp, save_vbr;
+    long	tmp_vectors[3];
+
+    __asm__ __volatile__
+	(	"movec	%/vbr,%2\n\t"
+		"movel	#Lberr1,%4@(8)\n\t"
+                "movec	%4,%/vbr\n\t"
+		"movel	%/sp,%1\n\t"
+		"moveq	#0,%0\n\t"
+		"tstb	%3@\n\t"  
+		"nop\n\t"
+		"moveq	#1,%0\n"
+                "Lberr1:\n\t"
+		"movel	%1,%/sp\n\t"
+		"movec	%2,%/vbr"
+		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+		: "a" (regp), "a" (tmp_vectors)
+                );
+
+    return( ret );
+}
+  
+/* Basically the same, but writes a value into a word register, protected
+ * by a bus error handler. Returns 1 if successful, 0 otherwise.
+ */
+
+int hwreg_write( volatile void *regp, unsigned short val )
+{
+	int		ret;
+	long	save_sp, save_vbr;
+	long	tmp_vectors[3];
+
+	__asm__ __volatile__
+	(	"movec	%/vbr,%2\n\t"
+		"movel	#Lberr2,%4@(8)\n\t"
+		"movec	%4,%/vbr\n\t"
+		"movel	%/sp,%1\n\t"
+		"moveq	#0,%0\n\t"
+		"movew	%5,%3@\n\t"  
+		"nop	\n\t"	/* If this nop isn't present, 'ret' may already be
+				 * loaded with 1 at the time the bus error
+				 * happens! */
+		"moveq	#1,%0\n"
+	"Lberr2:\n\t"
+		"movel	%1,%/sp\n\t"
+		"movec	%2,%/vbr"
+		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+		: "a" (regp), "a" (tmp_vectors), "g" (val)
+	);
+
+	return( ret );
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.105/linux/arch/m68k/mm/init.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/mm/init.c	Sat Jun 13 13:14:33 1998
@@ -30,40 +30,6 @@
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void init_kpointer_table(void);
 extern void show_net_buffers(void);
-extern const char PgtabStr_bad_pmd[];
-
-struct pgtable_cache_struct quicklists;
-
-void __bad_pte(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memset(pte, 0, PAGE_SIZE)
- 			flush_page_to_ram((unsigned long)pte);
-			flush_tlb_kernel_page((unsigned long)pte);
-			nocache_page((unsigned long)pte);
-			pmd_set(pmd, pte);
-			return pte + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -110,7 +76,7 @@
 	total++;
 	if (PageReserved(mem_map+i))
 	    reserved++;
-	else if (PageSwapCache(mem_map+i))
+	if (PageSwapCache(mem_map+i))
 	    cached++;
 	else if (!atomic_read(&mem_map[i].count))
 	    free++;
@@ -125,7 +91,6 @@
     printk("%d pages nonshared\n",nonshared);
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
-    printk("%d pages in page table cache\n",pgtable_cache_size);
     show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
@@ -266,7 +231,7 @@
 			 */
 			for (i = 0; i < 64; i++) {
 				pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
-					| _PAGE_CACHE040 | _PAGE_GLOBAL040
+				  | m68k_supervisor_cachemode | _PAGE_GLOBAL040
 					| _PAGE_ACCESSED;
 				physaddr += PAGE_SIZE;
 			}
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.1.105/linux/arch/m68k/mm/memory.c	Sun Jun  7 11:16:27 1998
+++ linux/arch/m68k/mm/memory.c	Sat Jun 13 13:14:33 1998
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995  Hamish Macdonald
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -16,7 +17,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/traps.h>
+#ifdef CONFIG_AMIGA
 #include <asm/amigahw.h>
+#endif
 
 /* Strings for `extern inline' functions in <asm/pgtable.h>.  If put
    directly into these functions, they are output for every file that
@@ -451,12 +454,14 @@
 	 *
 	 */
 
+#ifdef CONFIG_AMIGA
 	/*
 	 * if on an amiga and address is in first 16M, move it 
 	 * to the ZTWO_VADDR range
 	 */
 	if (MACH_IS_AMIGA && paddr < 16*1024*1024)
 		return ZTWO_VADDR(paddr);
+#endif
 	return paddr;
 }
 
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mvme16x/16xints.c linux/arch/m68k/mvme16x/16xints.c
--- v2.1.105/linux/arch/m68k/mvme16x/16xints.c	Mon Feb 23 18:12:02 1998
+++ linux/arch/m68k/mvme16x/16xints.c	Sat Jun 13 13:14:33 1998
@@ -127,7 +127,7 @@
 
 static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
 {
-	panic ("Unknown interrupt 0x%02x", irq);
+	printk ("Unknown interrupt 0x%02x\n", irq);
 }
 
 
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mvme16x/Makefile linux/arch/m68k/mvme16x/Makefile
--- v2.1.105/linux/arch/m68k/mvme16x/Makefile	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mvme16x/Makefile	Sat Jun 13 13:14:33 1998
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := mvme16x.o
-O_OBJS   := config.o 16xints.o
+O_OBJS   := config.o 16xints.o rtc.o
 #OX_OBJS = ksyms.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.1.105/linux/arch/m68k/mvme16x/config.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mvme16x/config.c	Sat Jun 13 13:14:33 1998
@@ -34,26 +34,10 @@
 #include <asm/machdep.h>
 #include <asm/mvme16xhw.h>
 
-typedef struct {
-	unsigned char
-		ctrl,
-		bcd_sec,
-		bcd_min,
-		bcd_hr,
-		bcd_dow,
-		bcd_dom,
-		bcd_mth,
-		bcd_year;
-} MK48T08;
-
-#define RTC_WRITE	0x80
-#define RTC_READ	0x40
-#define RTC_STOP	0x20
-
 int atari_SCC_reset_done = 1;		/* So SCC doesn't get reset */
 u_long atari_mch_cookie = 0;
 
-MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8;
+static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
 
 extern void mvme16x_process_int (int level, struct pt_regs *regs);
 extern void mvme16x_init_IRQ (void);
@@ -143,6 +127,11 @@
 }
 
 
+#define pcc2chip	((volatile u_char *)0xfff42000)
+#define PccSCCMICR	0x1d
+#define PccSCCTICR	0x1e
+#define PccSCCRICR	0x1f
+
 __initfunc(void config_mvme16x(void))
 {
     p_bdid p = (p_bdid)mvme_bdid_ptr;
@@ -197,7 +186,43 @@
 			rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
     }
     else
+    {
 	mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401;
+
+	/* Dont allow any interrupts from the CD2401 until the interrupt */
+	/* handlers are installed					 */
+
+	pcc2chip[PccSCCMICR] = 0x10;
+	pcc2chip[PccSCCTICR] = 0x10;
+	pcc2chip[PccSCCRICR] = 0x10;
+    }
+}
+
+static void mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+	p_bdid p = (p_bdid)mvme_bdid_ptr;
+	unsigned long *new = (unsigned long *)vectors;
+	unsigned long *old = (unsigned long *)0xffe00000;
+	volatile unsigned char uc, *ucp;
+
+	if (p->brdno == 0x0162 || p->brdno == 0x172)
+	{
+		ucp = (volatile unsigned char *)0xfff42043;
+		uc = *ucp | 8;
+		*ucp = uc;
+	}
+	else
+	{
+		*(volatile unsigned long *)0xfff40074 = 0x40000000;
+	}
+	*(new+4) = *(old+4);		/* Illegal instruction */
+	*(new+9) = *(old+9);		/* Trace */
+	*(new+47) = *(old+47);		/* Trap #15 */
+
+	if (p->brdno == 0x0162 || p->brdno == 0x172)
+		*(new+0x5e) = *(old+0x5e);	/* ABORT switch */
+	else
+		*(new+0x6e) = *(old+0x6e);	/* ABORT switch */
 }
 
 static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
@@ -208,15 +233,26 @@
 
 void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
 {
+    p_bdid p = (p_bdid)mvme_bdid_ptr;
+    int irq;
+
     tick_handler = timer_routine;
     /* Using PCCchip2 or MC2 chip tick timer 1 */
     *(volatile unsigned long *)0xfff42008 = 0;
     *(volatile unsigned long *)0xfff42004 = 10000;	/* 10ms */
     *(volatile unsigned char *)0xfff42017 |= 3;
     *(volatile unsigned char *)0xfff4201b = 0x16;
-    if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0,
+    if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
 				"timer", mvme16x_timer_int))
 	panic ("Couldn't register timer int");
+
+    if (p->brdno == 0x0162 || p->brdno == 0x172)
+	irq = MVME162_IRQ_ABORT;
+    else
+        irq = MVME167_IRQ_ABORT;
+    if (request_irq(irq, mvme16x_abort_int, 0,
+				"abort", mvme16x_abort_int))
+	panic ("Couldn't register abort int");
 }
 
 
@@ -254,76 +290,11 @@
 	return 0;
 }
 
-/*
- * console_map_init(), here to avoid having to modify drivers/block/genhd.c
- */
-
-void console_map_init(void)
-{
-}
-
-/*
- * fbmem_init(), here to avoid having to modify drivers/char/mem.c
- */
-
-void fbmem_init(void)
-{
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-unsigned long con_init(unsigned long kmem_start)
-{
-	return (kmem_start);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int vcs_init(void)
-{
-	return (0);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int kbd_init(void)
-{
-	return (0);
-}
-
-/* Avoid mods to init/main.c */
-
-void no_scroll(char *str, int *ints)
-{
-}
-
-/* Avoid mods to kernel/panic.c */
-
-void do_unblank_screen(void)
-{
-}
-
 int mvme16x_keyb_init (void)
 {
 	return 0;
 }
 
-void mvme16x_set_vectors (void)
-{
-	p_bdid p = (p_bdid)mvme_bdid_ptr;
-	unsigned long *new = (unsigned long *)vectors;
-	unsigned long *old = (unsigned long *)0xffe00000;;
-
-	*(new+4) = *(old+4);		/* Illegal instruction */
-	*(new+9) = *(old+9);		/* Trace */
-	*(new+47) = *(old+47);		/* Trap #15 */
-
-	if (p->brdno == 0x0162 || p->brdno == 0x172)
-		*(new+0x5e) = *(old+0x5e);	/* ABORT switch */
-	else
-		*(new+0x6e) = *(old+0x6e);	/* ABORT switch */
-}
-
 /*-------------------  Serial console stuff ------------------------*/
 
 extern void mvme167_serial_console_setup(int cflag);
@@ -372,7 +343,7 @@
 
 static void scc_write (char ch)
 {
-	volatile char *p = (volatile char *)SCC_A_ADDR;
+	volatile char *p = (volatile char *)MVME_SCC_A_ADDR;
 
 	do {
 		scc_delay();
diff -u --recursive --new-file v2.1.105/linux/arch/m68k/mvme16x/rtc.c linux/arch/m68k/mvme16x/rtc.c
--- v2.1.105/linux/arch/m68k/mvme16x/rtc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme16x/rtc.c	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,166 @@
+/*
+ *	Real Time Clock interface for Linux on the MVME16x
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION		"1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h>	/* For struct rtc_time and ioctls, etc */
+#include <asm/mvme16xhw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
+	unsigned long flags;
+	struct rtc_time wtime; 
+
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		save_flags(flags);
+		cli();
+		/* Ensure clock and real-time-mode-register are accessible */
+		rtc->ctrl = RTC_READ;
+		wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
+		wtime.tm_min =  BCD2BIN(rtc->bcd_min);
+		wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+		wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
+		wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
+		wtime.tm_year = BCD2BIN(rtc->bcd_year);
+		if (wtime.tm_year < 70)
+			wtime.tm_year += 100;
+		wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+		rtc->ctrl = 0;
+		restore_flags(flags);
+		return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+								-EFAULT : 0;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		unsigned char leap_yr;
+		struct rtc_time rtc_tm;
+
+		if (!suser())
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+		if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+			return -EINVAL;
+
+		if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+			return -EINVAL;
+			
+		if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+			return -EINVAL;
+
+		save_flags(flags);
+		cli();
+		rtc->ctrl = RTC_WRITE;
+
+		rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+		rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+		rtc->bcd_hr  = BIN2BCD(rtc_tm.tm_hour);
+		rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+		rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+		rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+		if (rtc_tm.tm_wday >= 0)
+			rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+
+		rtc->ctrl = 0;
+		restore_flags(flags);
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	if(rtc_status)
+		return -EBUSY;
+
+	rtc_status = 1;
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	rtc_status = 0;
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+	NULL,
+	NULL,
+	NULL,		/* No write */
+	NULL,		/* No readdir */
+	NULL,
+	rtc_ioctl,
+	NULL,		/* No mmap */
+	rtc_open,
+	rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+__initfunc(int rtc_MK48T08_init(void))
+{
+	if (!MACH_IS_MVME16x)
+		return -ENODEV;
+
+	printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
+	misc_register(&rtc_dev);
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.105/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.1.105/linux/arch/sparc/kernel/sys_sparc.c	Thu Apr 23 20:21:30 1998
+++ linux/arch/sparc/kernel/sys_sparc.c	Sat Jun 13 11:36:52 1998
@@ -334,15 +334,23 @@
 
 asmlinkage int sys_getdomainname(char *name, int len)
 {
-	int nlen = strlen(system_utsname.domainname);
+	int nlen;
+	int err = -EFAULT;
+	
+	down(&uts_sem);
+	
+	nlen = strlen(system_utsname.domainname);
 
 	if (nlen < len)
 		len = nlen;
 	if(len > __NEW_UTS_LEN)
-		return -EFAULT;
+		goto done
 	if(copy_to_user(name, system_utsname.domainname, len))
-		return -EFAULT;
-	return 0;
+		goto done;
+	err=0;
+done:	
+	up(&uts_sem);	
+	return err;
 }
 
 
diff -u --recursive --new-file v2.1.105/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.1.105/linux/drivers/block/amiflop.c	Thu Mar 26 15:57:02 1998
+++ linux/drivers/block/amiflop.c	Mon Jun  8 11:03:49 1998
@@ -68,11 +68,11 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/amifdreg.h>
+#include <linux/amifd.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
-#include <asm/amifdreg.h>
-#include <asm/amifd.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.1.105/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.105/linux/drivers/block/floppy.c	Fri May  8 23:14:47 1998
+++ linux/drivers/block/floppy.c	Tue Jun  9 01:21:49 1998
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1993, 1994  Alain Knaff
+ *  Copyright (C) 1998 Alan Cox
  */
 /*
  * 02.12.91 - Changed to static variables to indicate need for reset
@@ -95,7 +96,11 @@
  * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
  * features to asm/floppy.h.
  */
-
+ 
+/*
+ * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
+ * failures.
+ */
 
 #define FLOPPY_SANITY_CHECK
 #undef  FLOPPY_SILENT_DCL_CLEAR
@@ -114,9 +119,11 @@
  * motor of these drives causes system hangs on some PCI computers. drive
  * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  * a drive is allowed. */
+ 
 static int FLOPPY_IRQ=6;
 static int FLOPPY_DMA=2;
 static int allowed_drive_mask = 0x33;
+static int irqdma_allocated = 0;
  
 
 #include <linux/sched.h>
@@ -759,6 +766,11 @@
 			UDRS->select_date = jiffies;
 		}
 	}
+	/*
+	 *	We should propogate failures to grab the resources back
+	 *	nicely from here. Actually we ought to rewrite the fd
+	 *	driver some day too.
+	 */
 	if (newdor & FLOPPY_MOTOR_MASK)
 		floppy_grab_irq_and_dma();
 	if (olddor & FLOPPY_MOTOR_MASK)
@@ -818,10 +830,11 @@
 	unsigned long flags;
 
 	if (!usage_count){
-		printk("trying to lock fdc while usage count=0\n");
+		printk(KERN_ERR "Trying to lock fdc while usage count=0\n");
 		return -1;
 	}
-	floppy_grab_irq_and_dma();
+	if(floppy_grab_irq_and_dma()==-1)
+		return -EBUSY;
 	INT_OFF;
 	while (fdc_busy && NO_SIGNAL)
 		interruptible_sleep_on(&fdc_wait);
@@ -4208,7 +4221,12 @@
 	for (fdc = 0; fdc < N_FDC; fdc++)
 		if (FDCS->address != -1)
 			fd_outb(FDCS->dor, FD_DOR);
+	/*
+	 *	The driver will try and free resources and relies on us
+	 *	to know if they were allocated or not.
+	 */
 	fdc = 0;
+	irqdma_allocated = 1;
 	return 0;
 }
 
@@ -4230,10 +4248,13 @@
 		return;
 	}
 	INT_ON;
-	fd_disable_dma();
-	fd_free_dma();
-	fd_free_irq();
-
+	if(irqdma_allocated)
+	{
+		fd_disable_dma();
+		fd_free_dma();
+		fd_free_irq();
+		irqdma_allocated=0;
+	}
 	set_dor(0, ~0, 8);
 #if N_FDC > 1
 	set_dor(1, ~8, 0);
@@ -4384,10 +4405,12 @@
 	int dummy;
 	if(have_no_fdc)
 		return;
-	floppy_grab_irq_and_dma();
-	lock_fdc(MAXTIMEOUT,0);
-	dummy=fd_eject(0);
-	process_fd_request();
-	floppy_release_irq_and_dma();
+	if(floppy_grab_irq_and_dma()==0)
+	{
+		lock_fdc(MAXTIMEOUT,0);
+		dummy=fd_eject(0);
+		process_fd_request();
+		floppy_release_irq_and_dma();
+	}
 }
 #endif
diff -u --recursive --new-file v2.1.105/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.105/linux/drivers/block/ll_rw_blk.c	Fri May  8 23:14:47 1998
+++ linux/drivers/block/ll_rw_blk.c	Sat Jun 13 12:59:16 1998
@@ -463,6 +463,7 @@
 	     case IDE4_MAJOR:
 	     case IDE5_MAJOR:
 	     case ACSI_MAJOR:
+	     case MFM_ACORN_MAJOR:
 		/*
 		 * The scsi disk and cdrom drivers completely remove the request
 		 * from the queue when they start processing an entry.  For this
@@ -816,6 +817,9 @@
 #endif
 #ifdef CONFIG_BLK_DEV_XD
 	xd_init();
+#endif
+#ifdef CONFIG_BLK_DEV_MFM
+	mfm_init();
 #endif
 #ifdef CONFIG_PARIDE
 	{ extern void paride_init(void); paride_init(); };
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- v2.1.105/linux/drivers/block/paride/Config.in	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/Config.in	Sat Jun 13 12:08:19 1998
@@ -6,12 +6,14 @@
 dep_tristate '  Parallel port ATAPI CD-ROMs' CONFIG_PARIDE_PCD $CONFIG_PARIDE
 dep_tristate '  Parallel port ATAPI disks' CONFIG_PARIDE_PF $CONFIG_PARIDE
 dep_tristate '  Parallel port ATAPI tapes' CONFIG_PARIDE_PT $CONFIG_PARIDE
+dep_tristate '  Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE
 comment 'Parallel IDE protocol modules'
 dep_tristate '    ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE
 dep_tristate '    MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
 dep_tristate '    DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
 dep_tristate '    DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
 dep_tristate '    FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE
+dep_tristate '    FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 dep_tristate '    Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
 dep_tristate '    FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile
--- v2.1.105/linux/drivers/block/paride/Makefile	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/Makefile	Sat Jun 13 12:08:19 1998
@@ -58,6 +58,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE_PG),y)
+  LX_OBJS += pg.o
+else
+  ifeq ($(CONFIG_PARIDE_PG),m)
+    MX_OBJS += pg.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE_ATEN),y)
   LX_OBJS += aten.o
 else
@@ -119,6 +127,14 @@
 else
   ifeq ($(CONFIG_PARIDE_FIT2),m)
     MX_OBJS += fit2.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_FIT3),y)
+  LX_OBJS += fit3.o
+else
+  ifeq ($(CONFIG_PARIDE_FIT3),m)
+    MX_OBJS += fit3.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/fit3.c linux/drivers/block/paride/fit3.c
--- v2.1.105/linux/drivers/block/paride/fit3.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/fit3.c	Sat Jun 13 12:08:19 1998
@@ -0,0 +1,221 @@
+/* 
+        fit3.c        (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+	fit3.c is a low-level protocol driver for newer models 
+        of the Fidelity International Technology parallel port adapter.  
+	This adapter is used in their TransDisk 3000 portable 
+	hard-drives, as well as CD-ROM, PD-CD and other devices.
+
+	The TD-2000 and certain older devices use a different protocol.
+	Try the fit2 protocol module with them.
+
+        NB:  The FIT adapters do not appear to support the control 
+	registers.  So, we map ALT_STATUS to STATUS and NO-OP writes 
+	to the device control register - this means that IDE reset 
+	will not work on these devices.
+
+*/
+
+#define FIT3_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)                (((a>>3)&0x0f)|((b<<1)&0xf0))
+
+#define w7(byte)                {out_p(7,byte);}
+#define r7()                    (in_p(7) & 0xff)
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+
+*/
+
+static void  fit3_write_regr( PIA *pi, int cont, int regr, int val)
+
+{	if (cont == 1) return;
+
+	switch (pi->mode) {
+
+	case 0:
+	case 1: w2(0xc); w0(regr); w2(0x8); w2(0xc); 
+		w0(val); w2(0xd); 
+		w0(0);   w2(0xc);
+		break;
+
+	case 2: w2(0xc); w0(regr); w2(0x8); w2(0xc);
+		w4(val); w4(0);
+		w2(0xc);
+		break;
+
+	}
+}
+
+static int fit3_read_regr( PIA *pi, int cont, int regr )
+
+{	int  a, b;
+
+	if (cont) {
+	  if (regr != 6) return 0xff;
+	  regr = 7;
+	} 
+
+	switch (pi->mode) {
+
+	case 0: w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc);
+		w2(0xd); a = r1();
+		w2(0xf); b = r1(); 
+		w2(0xc);
+		return j44(a,b);
+
+	case 1: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
+		w2(0xec); w2(0xee); w2(0xef); a = r0(); 
+		w2(0xc);
+		return a;
+
+	case 2: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 
+		w2(0xec); 
+		a = r4(); b = r4(); 
+		w2(0xc);
+		return a;
+
+	}
+	return -1; 
+
+}
+
+static void fit3_read_block( PIA *pi, char * buf, int count )
+
+{	int  k, a, b, c, d;
+
+	switch (pi->mode) {
+
+	case 0: w2(0xc); w0(0x10); w2(0x8); w2(0xc);
+		for (k=0;k<count/2;k++) {
+		    w2(0xd); a = r1();
+		    w2(0xf); b = r1();
+		    w2(0xc); c = r1();
+		    w2(0xe); d = r1();
+		    buf[2*k  ] = j44(a,b);
+		    buf[2*k+1] = j44(c,d);
+		}
+		w2(0xc);
+		break;
+
+	case 1: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 
+		w2(0xec); w2(0xee);
+		for (k=0;k<count/2;k++) {
+		    w2(0xef); a = r0();
+		    w2(0xee); b = r0();
+                    buf[2*k  ] = a;
+                    buf[2*k+1] = b;
+		}
+		w2(0xec); 
+		w2(0xc);
+		break;
+
+	case 2: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 
+                w2(0xec);
+		for (k=0;k<count;k++) buf[k] = r4();
+                w2(0xc);
+		break;
+
+	}
+}
+
+static void fit3_write_block( PIA *pi, char * buf, int count )
+
+{	int k;
+
+        switch (pi->mode) {
+
+	case 0:
+        case 1: w2(0xc); w0(0); w2(0x8); w2(0xc);
+                for (k=0;k<count/2;k++) {
+ 		    w0(buf[2*k  ]); w2(0xd);
+ 		    w0(buf[2*k+1]); w2(0xc);
+		}
+		break;
+
+        case 2: w2(0xc); w0(0); w2(0x8); w2(0xc); 
+                for (k=0;k<count;k++) w4(buf[k]);
+                w2(0xc);
+		break;
+	}
+}
+
+static void fit3_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+	w2(0xc); w0(0); w2(0xa);
+	if (pi->mode == 2) { 
+		w2(0xc); w0(0x9); w2(0x8); w2(0xc); 
+		}
+}
+
+static void fit3_disconnect ( PIA *pi )
+
+{       w2(0xc); w0(0xa); w2(0x8); w2(0xc);
+	w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void fit3_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[3] = {"4-bit","8-bit","EPP"};
+
+	printk("%s: fit3 %s, FIT 3000 adapter at 0x%x, "
+	       "mode %d (%s), delay %d\n",
+                pi->device,FIT3_VERSION,pi->port,
+		pi->mode,mode_string[pi->mode],pi->delay);
+
+}
+
+static void fit3_init_proto(PIA *pi)
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void fit3_release_proto(PIA *pi)
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol fit3 = {"fit3",0,3,2,1,1,
+                           fit3_write_regr,
+                           fit3_read_regr,
+                           fit3_write_block,
+                           fit3_read_block,
+                           fit3_connect,
+                           fit3_disconnect,
+                           0,
+                           0,
+                           0,
+                           fit3_log_adapter,
+                           fit3_init_proto,
+                           fit3_release_proto
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &fit3 ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &fit3 );
+}
+
+#endif
+
+/* end of fit3.c */
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/mkd linux/drivers/block/paride/mkd
--- v2.1.105/linux/drivers/block/paride/mkd	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/mkd	Sat Jun 13 12:08:19 1998
@@ -2,6 +2,9 @@
 #
 # mkd -- a script to create the device special files for the PARIDE subsystem
 #
+#  block devices:  	pd (45), pcd (46), pf (47)
+#  character devices:	pt (96), pg (97)
+#
 function mkdev {
   mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
 }
@@ -21,5 +24,7 @@
 for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
 for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
 for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done
 #
 # end of mkd
+
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.1.105/linux/drivers/block/paride/paride.c	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/paride.c	Sat Jun 13 12:08:19 1998
@@ -454,6 +454,11 @@
           pi_register(&fit2);
         };
 #endif
+#ifdef CONFIG_PARIDE_FIT3
+        { extern struct pi_protocol fit3;
+          pi_register(&fit3);
+        };
+#endif
 #ifdef CONFIG_PARIDE_KBIC
         { extern struct pi_protocol k951;
           extern struct pi_protocol k971;
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/paride.h linux/drivers/block/paride/paride.h
--- v2.1.105/linux/drivers/block/paride/paride.h	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/paride.h	Sat Jun 13 12:08:19 1998
@@ -23,6 +23,7 @@
 #define PI_PCD	1	/* ATAPI CDrom */
 #define PI_PF   2	/* ATAPI disk */
 #define PI_PT	3	/* ATAPI tape */
+#define PI_PG   4       /* ATAPI generic */
 
 /* The paride module contains no state, instead the drivers allocate
    a pi_adapter data structure and pass it to paride in every operation.
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.1.105/linux/drivers/block/paride/pg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/pg.c	Sat Jun 13 12:08:19 1998
@@ -0,0 +1,691 @@
+/* 
+        pg.c    (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+	The pg driver provides a simple character device interface for
+        sending ATAPI commands to a device.  With the exception of the
+	ATAPI reset operation, all operations are performed by a pair
+        of read and write operations to the appropriate /dev/pgN device.
+	A write operation delivers a command and any outbound data in
+        a single buffer.  Normally, the write will succeed unless the
+        device is offline or malfunctioning, or there is already another
+	command pending.  If the write succeeds, it should be followed
+        immediately by a read operation, to obtain any returned data and
+        status information.  A read will fail if there is no operation
+        in progress.
+
+	As a special case, the device can be reset with a write operation,
+        and in this case, no following read is expected, or permitted.
+
+	There are no ioctl() operations.  Any single operation
+	may transfer at most PG_MAX_DATA bytes.  Note that the driver must
+        copy the data through an internal buffer.  In keeping with all
+	current ATAPI devices, command packets are assumed to be exactly
+	12 bytes in length.
+
+	To permit future changes to this interface, the headers in the
+	read and write buffers contain a single character "magic" flag.
+        Currently this flag must be the character "P".
+
+        By default, the driver will autoprobe for a single parallel
+        port ATAPI device, but if their individual parameters are
+        specified, the driver can handle up to 4 devices.
+
+	To use this device, you must have the following device 
+	special files defined:
+
+		/dev/pg0 b 97 0
+		/dev/pg1 b 97 1
+		/dev/pg2 b 97 2
+		/dev/pg3 b 97 3
+
+	(You'll need to change the 97 to something else if you use
+	the 'major' parameter to install the driver on a different
+        major number.)
+
+        The behaviour of the pg driver can be altered by setting
+        some parameters from the insmod command line.  The following
+        parameters are adjustable:
+
+            drive0      These four arguments can be arrays of       
+            drive1      1-6 integers as follows:
+            drive2
+            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
+
+                        Where,
+
+                <prt>   is the base of the parallel port address for
+                        the corresponding drive.  (required)
+
+                <pro>   is the protocol number for the adapter that
+                        supports this drive.  These numbers are
+                        logged by 'paride' when the protocol modules
+                        are initialised.  (0 if not given)
+
+                <uni>   for those adapters that support chained
+                        devices, this is the unit selector for the
+                        chain of devices on the given port.  It should
+                        be zero for devices that don't support chaining.
+                        (0 if not given)
+
+                <mod>   this can be -1 to choose the best mode, or one
+                        of the mode numbers supported by the adapter.
+                        (-1 if not given)
+
+                <slv>   ATAPI devices can be jumpered to master or slave.
+                        Set this to 0 to choose the master drive, 1 to
+                        choose the slave, -1 (the default) to choose the
+                        first drive found.
+
+                <dly>   some parallel ports require the driver to 
+                        go more slowly.  -1 sets a default value that
+                        should work with the chosen protocol.  Otherwise,
+                        set this to a small integer, the larger it is
+                        the slower the port i/o.  In some cases, setting
+                        this to zero will speed up the device. (default -1)
+
+	    major	You may use this parameter to overide the
+			default major number (97) that this driver
+			will use.  Be sure to change the device
+			name as well.
+
+	    name	This parameter is a character string that
+			contains the name the kernel will use for this
+			device (in /proc output, for instance).
+			(default "pg").
+
+            verbose     This parameter controls the amount of logging
+                        that is done by the driver.  Set it to 0 for 
+			quiet operation, to 1 to enable progress
+			messages while the driver probes for devices,
+			or to 2 for full debug logging.  (default 0)
+
+        If this driver is built into the kernel, you can use 
+        the following command line parameters, with the same values
+        as the corresponding module parameters listed above:
+
+            pg.drive0
+            pg.drive1
+            pg.drive2
+            pg.drive3
+
+        In addition, you can use the parameter pg.disable to disable
+        the driver entirely.
+
+*/
+
+#define PG_VERSION      "1.0"
+#define PG_MAJOR	97
+#define PG_NAME		"pg"
+#define PG_UNITS	4
+
+/* Here are things one can override from the insmod command.
+   Most are autoprobed by paride unless set here.  Verbose is 0
+   by default.
+
+*/
+
+static int	verbose = 0;
+static int	major = PG_MAJOR;
+static char	*name = PG_NAME;
+static int      disable = 0;
+
+static int drive0[6] = {0,0,0,-1,-1,-1};
+static int drive1[6] = {0,0,0,-1,-1,-1};
+static int drive2[6] = {0,0,0,-1,-1,-1};
+static int drive3[6] = {0,0,0,-1,-1,-1};
+
+static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
+static int pg_drive_count;
+
+#define D_PRT   0
+#define D_PRO   1
+#define D_UNI   2
+#define D_MOD   3
+#define D_SLV   4
+#define D_DLY   5
+
+#define DU              (*drives[unit])
+
+/* end of parameters */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/mtio.h>
+#include <linux/pg.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pg_stt[5] = {{"drive0",6,drive0},
+                        {"drive1",6,drive1},
+                        {"drive2",6,drive2},
+                        {"drive3",6,drive3},
+			{"disable",1,&disable}};
+
+void pg_setup( char *str, int *ints)
+
+{       generic_setup(pg_stt,5,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(drive0,"1-6i");
+MODULE_PARM(drive1,"1-6i");
+MODULE_PARM(drive2,"1-6i");
+MODULE_PARM(drive3,"1-6i");
+
+#include "paride.h"
+
+#define PG_SPIN_DEL     50              /* spin delay in micro-seconds  */
+#define PG_SPIN         200
+#define PG_TMO		HZ
+
+#define STAT_ERR        0x01
+#define STAT_INDEX      0x02
+#define STAT_ECC        0x04
+#define STAT_DRQ        0x08
+#define STAT_SEEK       0x10
+#define STAT_WRERR      0x20
+#define STAT_READY      0x40
+#define STAT_BUSY       0x80
+
+#define ATAPI_IDENTIFY		0x12
+
+int pg_init(void);
+#ifdef MODULE
+void cleanup_module( void );
+#endif
+
+static int pg_open(struct inode *inode, struct file *file);
+static int pg_release (struct inode *inode, struct file *file);
+static ssize_t pg_read(struct file * filp, char * buf, 
+                       size_t count, loff_t *ppos);
+static ssize_t pg_write(struct file * filp, const char * buf, 
+                        size_t count, loff_t *ppos);
+static int pg_detect(void);
+
+static int pg_identify (int unit, int log);
+
+#define PG_NAMELEN      8
+
+struct pg_unit {
+	struct pi_adapter pia;    /* interface to paride layer */
+	struct pi_adapter *pi;
+	int busy;        	  /* write done, read expected */
+	int start;		  /* jiffies at command start */
+	int dlen;		  /* transfer size requested */
+	int timeout;		  /* timeout requested */
+	int status;		  /* last sense key */
+	int drive;		  /* drive */
+	int access;               /* count of active opens ... */
+	int present;		  /* device present ? */
+	char *bufptr;
+	char name[PG_NAMELEN];	  /* pg0, pg1, ... */
+	};
+
+struct pg_unit pg[PG_UNITS];
+
+/*  'unit' must be defined in all functions - either as a local or a param */
+
+#define PG pg[unit]
+#define PI PG.pi
+
+static char pg_scratch[512];            /* scratch block buffer */
+
+/* kernel glue structures */
+
+static struct file_operations pg_fops = {
+        NULL,                   /* lseek - default */
+        pg_read,                /* read */
+        pg_write,               /* write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* select */
+        NULL,                   /* ioctl */
+        NULL,                   /* mmap */
+        pg_open,                /* open */
+        pg_release,             /* release */
+        NULL,                   /* fsync */
+        NULL,                   /* fasync */
+        NULL,                   /* media change ? */
+        NULL                    /* revalidate new media */
+};
+
+void pg_init_units( void )
+
+{       int     unit, j;
+
+        pg_drive_count = 0;
+        for (unit=0;unit<PG_UNITS;unit++) {
+                PG.pi = & PG.pia;
+                PG.access = 0;
+                PG.busy = 0;
+                PG.present = 0;
+		PG.bufptr = NULL;
+		PG.drive = DU[D_SLV];
+                j = 0;
+                while ((j < PG_NAMELEN-2) && (PG.name[j]=name[j])) j++;
+                PG.name[j++] = '0' + unit;
+                PG.name[j] = 0;
+                if (DU[D_PRT]) pg_drive_count++;
+        }
+} 
+
+int pg_init (void)      /* preliminary initialisation */
+
+{       int unit;
+
+	if (disable) return -1;
+
+	pg_init_units();
+
+	if (pg_detect()) return -1;
+
+        if (register_chrdev(major,name,&pg_fops)) {
+                printk("pg_init: unable to get major number %d\n",
+                        major);
+	        for (unit=0;unit<PG_UNITS;unit++)
+        	  if (PG.present) pi_release(PI);
+                return -1;
+        }
+
+        return 0;
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+void    cleanup_module(void);
+
+int     init_module(void)
+
+{       int     err;
+        long    flags;
+
+        save_flags(flags);
+        cli();
+
+        err = pg_init();
+
+        restore_flags(flags);
+        return err;
+}
+
+void    cleanup_module(void)
+
+{       long flags;
+	int unit;
+
+        save_flags(flags);
+        cli();
+
+        unregister_chrdev(major,name);
+
+	for (unit=0;unit<PG_UNITS;unit++)
+	  if (PG.present) pi_release(PI);
+	
+        restore_flags(flags);
+}
+
+#endif
+
+#define	WR(c,r,v)	pi_write_regr(PI,c,r,v)
+#define	RR(c,r)		(pi_read_regr(PI,c,r))
+
+#define DRIVE           (0xa0+0x10*PG.drive)
+
+static void pg_sleep( int cs )
+
+{       current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + cs;
+        schedule();
+}
+
+static int pg_wait( int unit, int go, int stop, int tmo, char * msg )
+
+{       int j, r, e, s, p;
+
+	PG.status = 0;
+
+        j = 0;
+        while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(jiffies<tmo)) {
+                if (j++ < PG_SPIN) udelay(PG_SPIN_DEL);
+		else pg_sleep(1);
+	}
+
+        if ((r&(STAT_ERR&stop))||(jiffies>=tmo)) {
+           s = RR(0,7);
+           e = RR(0,1);
+           p = RR(0,2);
+           if (verbose > 1)
+	     printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
+                   PG.name,msg,s,e,p,(jiffies>=tmo)?" timeout":"");
+
+
+           if (jiffies>=tmo) e |= 0x100;
+	   PG.status = (e >> 4) & 0xff;
+           return -1;
+        }
+        return 0;
+}
+
+static int pg_command( int unit, char * cmd, int dlen, int tmo )
+
+{       int k;
+
+	pi_connect(PI);
+
+        WR(0,6,DRIVE);
+
+        if (pg_wait(unit,STAT_BUSY|STAT_DRQ,0,tmo,"before command")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        WR(0,4,dlen % 256);
+        WR(0,5,dlen / 256);
+        WR(0,7,0xa0);          /* ATAPI packet command */
+
+        if (pg_wait(unit,STAT_BUSY,STAT_DRQ,tmo,"command DRQ")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        if (RR(0,2) != 1) {
+           printk("%s: command phase error\n",PG.name);
+           pi_disconnect(PI);
+           return -1;
+        }
+
+        pi_write_block(PI,cmd,12);
+
+	if (verbose > 1) {
+		printk("%s: Command sent, dlen=%d packet= ", PG.name,dlen);
+		for (k=0;k<12;k++) printk("%02x ",cmd[k]&0xff);
+		printk("\n");
+	}
+        return 0;
+}
+
+static int pg_completion( int unit, char * buf, int tmo)
+
+{       int r, s, d, n, p;
+
+        r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
+			tmo,"completion");
+
+	PG.dlen = 0;
+
+        if (RR(0,7)&STAT_DRQ) { 
+           d = (RR(0,4)+256*RR(0,5));
+           n = ((d+3)&0xfffc);
+	   p = RR(0,2)&3;
+	   if (p == 0) pi_write_block(PI,buf,n);
+	   if (p == 2) pi_read_block(PI,buf,n);
+	   if (verbose > 1) printk("%s: %s %d bytes\n",PG.name,
+				    p?"Read":"Write",n);
+	   PG.dlen = (1-p)*d;
+        }
+
+        s = pg_wait(unit,STAT_BUSY,STAT_READY|STAT_ERR,tmo,"data done");
+
+        pi_disconnect(PI); 
+
+        return (r?r:s);
+}
+
+static int pg_reset( int unit )
+
+{	int	i, k, flg;
+	int	expect[5] = {1,1,1,0x14,0xeb};
+
+	pi_connect(PI);
+	WR(0,6,DRIVE);
+	WR(0,7,8);
+
+	pg_sleep(2);
+
+        k = 0;
+        while ((k++ < PG_TMO) && (RR(1,6)&STAT_BUSY))
+                pg_sleep(1);
+
+	flg = 1;
+	for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
+
+	if (verbose) {
+		printk("%s: Reset (%d) signature = ",PG.name,k);
+		for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
+		if (!flg) printk(" (incorrect)");
+		printk("\n");
+	}
+	
+	pi_disconnect(PI);
+	return flg-1;	
+}
+
+static void xs( char *buf, char *targ, int offs, int len )
+
+{	int	j,k,l;
+
+	j=0; l=0;
+	for (k=0;k<len;k++) 
+	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
+		l=targ[j++]=buf[k+offs];
+	if (l==0x20) j--; targ[j]=0;
+}
+
+static int pg_identify( int unit, int log )
+
+{	int 	s;
+	char	*ms[2] = {"master","slave"};
+	char	mf[10], id[18];
+	char    id_cmd[12] = { ATAPI_IDENTIFY,0,0,0,36,0,0,0,0,0,0,0};
+	char	buf[36];
+
+        s = pg_command(unit,id_cmd,36,jiffies+PG_TMO);
+	if (s) return -1;
+	s = pg_completion(unit,buf,jiffies+PG_TMO);
+	if (s) return -1;
+
+	if (log) {
+		xs(buf,mf,8,8);
+		xs(buf,id,16,16);
+        	printk("%s: %s %s, %s\n",PG.name,mf,id,ms[PG.drive]);
+	}
+
+	return 0;
+}
+
+static int pg_probe( int unit )
+
+/*	returns  0, with id set if drive is detected
+	        -1, if drive detection failed
+*/
+
+{	if (PG.drive == -1) {
+	   for (PG.drive=0;PG.drive<=1;PG.drive++)
+		if (!pg_reset(unit)) return pg_identify(unit,1);
+	} else {
+	   if (!pg_reset(unit)) return pg_identify(unit,1);
+	}
+        return -1; 
+}
+
+static int pg_detect( void )
+
+{	int	k, unit;
+
+	printk("%s: %s version %s, major %d\n",
+		name,name,PG_VERSION,major);
+
+	k = 0;
+	if (pg_drive_count == 0) {
+	    unit = 0;
+	    if (pi_init(PI,1,-1,-1,-1,-1,-1,pg_scratch,
+                        PI_PG,verbose,PG.name)) {
+	        if (!pg_probe(unit)) {
+			PG.present = 1;
+			k++;
+	        } else pi_release(PI);
+	    }
+
+	} else for (unit=0;unit<PG_UNITS;unit++) if (DU[D_PRT])
+	    if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+			DU[D_PRO],DU[D_DLY],pg_scratch,PI_PG,verbose,
+			PG.name)) { 
+                if (!pg_probe(unit)) {
+                        PG.present = 1;
+                        k++;
+                } else pi_release(PI);
+            }
+
+	if (k) return 0;
+
+	printk("%s: No ATAPI device detected\n",name);
+	return -1;
+}
+
+#define DEVICE_NR(dev)	(MINOR(dev) % 128)
+
+static int pg_open (struct inode *inode, struct file *file)
+
+{       int	unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PG_UNITS) || (!PG.present)) return -ENODEV;
+
+        PG.access++;
+
+	if (PG.access > 1) {
+		PG.access--;
+		return -EBUSY;
+	}
+
+        MOD_INC_USE_COUNT;
+
+	if (PG.busy) {
+		pg_reset(unit);
+		PG.busy = 0;
+	}
+
+	pg_identify(unit,(verbose>1));
+
+
+	PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL);
+	if (PG.bufptr == NULL) {
+		PG.access--;
+		MOD_DEC_USE_COUNT;
+		printk("%s: buffer allocation failed\n",PG.name);
+		return -ENOMEM;
+	}
+
+        return 0;
+}
+
+static int pg_release (struct inode *inode, struct file *file)
+{
+        int	unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PG_UNITS) || (PG.access <= 0)) 
+                return -EINVAL;
+
+	PG.access--;
+
+	kfree(PG.bufptr);
+	PG.bufptr = NULL;
+
+        MOD_DEC_USE_COUNT;
+
+	return 0;
+
+}
+
+static ssize_t pg_write(struct file * filp, const char * buf, 
+                        size_t count, loff_t *ppos)
+
+{       struct inode            *ino = filp->f_dentry->d_inode;
+        int                     unit = DEVICE_NR(ino->i_rdev);
+        struct pg_write_hdr     hdr;
+        int                     hs = sizeof(hdr);
+
+	if (PG.busy) return -EBUSY;
+	if (count < hs) return -EINVAL;
+	
+	copy_from_user((char *)&hdr,buf,hs);
+
+	if (hdr.magic != PG_MAGIC) return -EINVAL;
+	if (hdr.dlen > PG_MAX_DATA) return -EINVAL;
+	if ((count - hs) > PG_MAX_DATA) return -EINVAL;
+
+	if (hdr.func == PG_RESET) {
+		if (count != hs) return -EINVAL;
+		if (pg_reset(unit)) return -EIO;
+		return count;
+	}
+
+	if (hdr.func != PG_COMMAND) return -EINVAL;
+
+	PG.start = jiffies;
+	PG.timeout = hdr.timeout*HZ + HZ/2 + jiffies;
+
+	if (pg_command(unit,hdr.packet,hdr.dlen,jiffies+PG_TMO)) {
+		if (PG.status & 0x10) return -ETIME;
+		return -EIO;
+	}
+
+	PG.busy = 1;
+
+	copy_from_user(PG.bufptr,buf+hs,count-hs);
+
+	return count;
+}
+
+static ssize_t pg_read(struct file * filp, char * buf, 
+                       size_t count, loff_t *ppos)
+
+{  	struct inode 		*ino = filp->f_dentry->d_inode;
+	int			unit = DEVICE_NR(ino->i_rdev);
+	struct pg_read_hdr 	hdr;
+	int			hs = sizeof(hdr);
+	int			copy;
+
+	if (!PG.busy) return -EINVAL;
+	if (count < hs) return -EINVAL;
+
+	PG.busy = 0;
+
+	if (pg_completion(unit,PG.bufptr,PG.timeout))
+	  if (PG.status & 0x10) return -ETIME;
+
+	hdr.magic = PG_MAGIC;
+	hdr.dlen = PG.dlen;
+	copy = 0;
+
+	if (hdr.dlen < 0) {
+        	hdr.dlen = -1 * hdr.dlen;
+		copy = hdr.dlen;
+		if (copy > (count - hs)) copy = count - hs;
+	}
+
+	hdr.duration = (jiffies - PG.start + HZ/2) / HZ;
+	hdr.scsi = PG.status & 0x0f;
+
+	copy_to_user(buf,(char *)&hdr,hs);
+	if (copy > 0) copy_to_user(buf+hs,PG.bufptr,copy);
+	
+	return copy+hs;
+}
+
+/* end of pg.c */
+
diff -u --recursive --new-file v2.1.105/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.1.105/linux/drivers/block/paride/pseudo.h	Wed May 20 19:10:38 1998
+++ linux/drivers/block/paride/pseudo.h	Sat Jun 13 12:08:20 1998
@@ -45,7 +45,7 @@
 static int ps_timer_active = 0;
 static int ps_tq_active = 0;
 
-spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
 
 static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
 static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
diff -u --recursive --new-file v2.1.105/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.1.105/linux/drivers/cdrom/mcd.c	Thu Feb 12 20:56:05 1998
+++ linux/drivers/cdrom/mcd.c	Sat Jun 13 13:05:22 1998
@@ -157,6 +157,7 @@
 
 static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */
 static int   mcd_irq  = MCD_INTR_NR; /* must directly follow mcd_port */
+MODULE_PARM(mcd, "1-2i");
 
 static int McdTimeout, McdTries;
 static struct wait_queue *mcd_waitq = NULL;
diff -u --recursive --new-file v2.1.105/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.1.105/linux/drivers/char/adbmouse.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/adbmouse.c	Sat Jun 13 13:44:30 1998
@@ -0,0 +1,304 @@
+/*
+ * Macintosh ADB Mouse driver for Linux
+ *
+ * 27 Oct 1997 Michael Schmitz
+ * logitech fixes by anthony tong
+ *
+ * Apple mouse protocol according to:
+ *
+ * Device code shamelessly stolen from:
+ */
+/*
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/adb_mouse.h>
+#include <asm/segment.h>
+#include <asm/processor.h>
+
+static struct mouse_status mouse;
+static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2;
+static int adb_mouse_buttons = 0;
+
+extern void (*adb_mouse_interrupt_hook) (char *, int);
+
+extern int console_loglevel;
+
+/*
+ *	XXX: need to figure out what ADB mouse packets mean ... 
+ *	This is the stuff stolen from the Atari driver ...
+ */
+static void adb_mouse_interrupt(char *buf, int nb)
+{
+    static int buttons = 7;
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = ???? ???? (?)
+    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+    data[3] = bxxx xxxx First button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+
+    NOTE: data[0] is confirmed by the parent function and need not be
+    checked here.
+  */
+
+  /*
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = 0100 0000 Extended protocol register.
+	      Bits 6-7 are the device id, which should be 1.
+	      Bits 4-5 are resolution which is in "units/inch".
+	      The Logitech MouseMan returns these bits clear but it has
+	      200/300cpi resolution.
+	      Bits 0-3 are unique vendor id.
+    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+	      Bits 2-3 should be 8 + 4.
+		      Bits 4-7 should be 3 for a mouse device.
+    data[3] = bxxx xxxx Left button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+    data[5] = byyy bxxx Third button and fourth button.  
+    	      Y is additiona. high bits of y-axis motion.  
+    	      X is additional high bits of x-axis motion.
+
+    NOTE: data[0] and data[2] are confirmed by the parent function and
+    need not be checked here.
+  */
+
+    /*
+     * 'buttons' here means 'button down' states!
+     * Button 1 (left)  : bit 2, busmouse button 3
+     * Button 2 (right) : bit 0, busmouse button 1
+     * Button 3 (middle): bit 1, busmouse button 2
+     */
+
+    /* x/y and buttons swapped */
+    
+    if (nb > 0)	{				/* real packet : use buttons? */
+	if (console_loglevel >= 8)
+	    printk("adb_mouse: real data; "); 
+	/* button 1 (left, bit 2) : always significant ! */
+	buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+	/* button 2 (middle) */
+	buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
+	/* button 3 (right) present?
+	 *  on a logitech mouseman, the right and mid buttons sometimes behave
+	 *  strangely until they both have been pressed after booting. */
+	/* data valid only if extended mouse format ! (buf[3] = 0 else) */
+	if ( nb == 6 )
+	    buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+    } else {					/* fake packet : use 2+3 */
+	if (console_loglevel >= 8)
+	    printk("adb_mouse: fake data; "); 
+	/* we only see state changes here, but the fake driver takes care
+	 * to preserve state... button 1 state must stay unchanged! */
+	buttons = (buttons&4) | ((buf[2] & 0x80 ? 1 : 0) |
+		  (buf[3] & 0x80 ? 2 : 0));
+    }
+
+    add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+    mouse.buttons = buttons & 7;
+    mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
+    mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
+
+    if (console_loglevel >= 8)
+        printk(" %X %X %X buttons %x dx %d dy %d \n", 
+               buf[1], buf[2], buf[3], mouse.buttons, mouse.dx, mouse.dy);
+ 
+    mouse.ready = 1;
+    wake_up_interruptible(&mouse.wait);
+    if (mouse.fasyncptr)
+	kill_fasync(mouse.fasyncptr, SIGIO);
+
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(filp, on, &mouse.fasyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int release_mouse(struct inode *inode, struct file *file)
+{
+    fasync_mouse(file, 0);
+    if (--mouse.active)
+      return 0;
+
+    adb_mouse_interrupt_hook = NULL;
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int open_mouse(struct inode *inode, struct file *file)
+{
+    if (mouse.active++)
+	return 0;
+	
+    mouse.ready = 0;
+
+    mouse.dx = mouse.dy = 0;
+    adb_mouse_buttons = 0;
+    MOD_INC_USE_COUNT;
+    adb_mouse_interrupt_hook = adb_mouse_interrupt;
+    return 0;
+}
+
+static ssize_t write_mouse(struct file *file, const char *buffer,
+			   size_t count, loff_t *ppos)
+{
+    return -EINVAL;
+}
+
+static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
+			  loff_t *ppos)
+{
+    int dx, dy, buttons;
+
+    if (count < 3)
+	return -EINVAL;
+    if (!mouse.ready)
+	return -EAGAIN;
+    dx = mouse.dx;
+    dy = mouse.dy;
+    buttons = mouse.buttons;
+    if (dx > 127)
+      dx = 127;
+    else if (dx < -128)
+      dx = -128;
+    if (dy > 127)
+      dy = 127;
+    else if (dy < -128)
+      dy = -128;
+    mouse.dx -= dx;
+    mouse.dy -= dy;
+    if (mouse.dx == 0 && mouse.dy == 0)
+      mouse.ready = 0;
+    if (put_user(buttons | 0x80, buffer++) ||
+	put_user((char) dx, buffer++) ||
+	put_user((char) dy, buffer++))
+      return -EFAULT;
+    if (count > 3)
+      if (clear_user(buffer, count - 3))
+	return -EFAULT;
+    return count;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &mouse.wait, wait);
+	if (mouse.ready)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations adb_mouse_fops = {
+    NULL,		/* mouse_seek */
+    read_mouse,
+    write_mouse,
+    NULL,		/* mouse_readdir */
+    mouse_poll,
+    NULL,		/* mouse_ioctl */
+    NULL,		/* mouse_mmap */
+    open_mouse,
+    release_mouse,
+    NULL,
+    fasync_mouse,
+};
+
+#define ADB_MOUSE_MINOR	10
+
+static struct miscdevice adb_mouse = {
+    ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+};
+
+__initfunc(int adb_mouse_init(void))
+{
+    mouse.active = 0;
+    mouse.ready = 0;
+    mouse.wait = NULL;
+
+    if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+	    return -ENODEV;
+    printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+    misc_register(&adb_mouse);
+    return 0;
+}
+
+
+#define	MIN_THRESHOLD 1
+#define	MAX_THRESHOLD 20	/* more seems not reasonable... */
+
+__initfunc(void adb_mouse_setup(char *str, int *ints))
+{
+    if (ints[0] < 1) {
+	printk( "adb_mouse_setup: no arguments!\n" );
+	return;
+    }
+    else if (ints[0] > 2) {
+	printk( "adb_mouse_setup: too many arguments\n" );
+    }
+
+    if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+	printk( "adb_mouse_setup: bad threshold value (ignored)\n" );
+    else {
+	adb_mouse_x_threshold = ints[1];
+	adb_mouse_y_threshold = ints[1];
+	if (ints[0] > 1) {
+	    if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+		printk("adb_mouse_setup: bad threshold value (ignored)\n" );
+	    else
+		adb_mouse_y_threshold = ints[2];
+	}
+    }
+	
+}
+
+#ifdef MODULE
+#include <asm/setup.h>
+
+int init_module(void)
+{
+    return adb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+    misc_deregister(&adb_mouse);
+}
+#endif
diff -u --recursive --new-file v2.1.105/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.105/linux/drivers/char/bttv.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/char/bttv.c	Sat Jun 13 11:38:49 1998
@@ -1922,7 +1922,7 @@
 			}
 			btv->win.sheight=v.height;
 			btv->win.swidth=v.width;
-+			btv->win.bpp=((v.depth+1)&0x18)/8;
+			btv->win.bpp=((v.depth+1)&0x38)/8;
 			btv->win.depth=v.depth;
 			btv->win.bpl=v.bytesperline;
 			
@@ -2313,6 +2313,8 @@
 		"DEC DC21030", PCI_BASE_ADDRESS_0},
 	{ PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
 		"Matrox Millennium", PCI_BASE_ADDRESS_1},
+	{ PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2,
+		"Matrox Millennium II", PCI_BASE_ADDRESS_0},
 	{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
 	{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, 
 		"Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
diff -u --recursive --new-file v2.1.105/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.105/linux/drivers/char/console.c	Wed May 20 19:10:38 1998
+++ linux/drivers/char/console.c	Fri Jun 12 10:43:31 1998
@@ -1254,18 +1254,15 @@
 	}
 }
 
-static void insert_char(int currcons)
+static void insert_char(int currcons, unsigned int nr)
 {
-	unsigned int i = x;
-	unsigned short tmp, old = video_erase_char;
-	unsigned short * p = (unsigned short *) pos;
+	unsigned short *p, *q = (unsigned short *) pos;
 
-	while (i++ < video_num_columns) {
-		tmp = scr_readw(p);
-		scr_writew(old, p);
-		old = tmp;
-		p++;
-	}
+	p = q + video_num_columns - nr - x;
+	while (--p >= q)
+		scr_writew(scr_readw(p), p + nr);
+
+	memsetw(q, video_erase_char, nr*2);
 	need_wrap = 0;
 }
 
@@ -1275,16 +1272,16 @@
 	need_wrap = 0;
 }
 
-static void delete_char(int currcons)
+static void delete_char(int currcons, unsigned int nr)
 {
 	unsigned int i = x;
 	unsigned short * p = (unsigned short *) pos;
 
-	while (++i < video_num_columns) {
-		scr_writew(scr_readw(p+1), p);
+	while (++i <= video_num_columns - nr) {
+		scr_writew(scr_readw(p+nr), p);
 		p++;
 	}
-	scr_writew(video_erase_char, p);
+	memsetw(p, video_erase_char, nr*2);
 	need_wrap = 0;
 }
 
@@ -1300,8 +1297,7 @@
 		nr = video_num_columns;
 	else if (!nr)
 		nr = 1;
-	while (nr--)
-		insert_char(currcons);
+	insert_char(currcons, nr);
 }
 
 static void csi_L(int currcons, unsigned int nr)
@@ -1319,8 +1315,7 @@
 		nr = video_num_columns;
 	else if (!nr)
 		nr = 1;
-	while (nr--)
-		delete_char(currcons);
+	delete_char(currcons, nr);
 }
 
 static void csi_M(int currcons, unsigned int nr)
@@ -1583,7 +1578,7 @@
 				lf(currcons);
 			}
 			if (decim)
-				insert_char(currcons);
+				insert_char(currcons, 1);
 			scr_writew( video_mode_512ch ?
 			   ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
 			   (tc & 0x0ff) : (attr << 8) + tc,
diff -u --recursive --new-file v2.1.105/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v2.1.105/linux/drivers/char/lp_intern.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/lp_intern.c	Sat Jun 13 13:44:30 1998
@@ -35,6 +35,7 @@
 #include <linux/lp_intern.h>
 
 static int minor = -1;
+MODULE_PARM(minor,"i");
 
 static void lp_int_out(int, int);
 static int lp_int_busy(int);
diff -u --recursive --new-file v2.1.105/linux/drivers/char/mac_SCC.c linux/drivers/char/mac_SCC.c
--- v2.1.105/linux/drivers/char/mac_SCC.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/mac_SCC.c	Sat Jun 13 13:44:30 1998
@@ -0,0 +1,1543 @@
+/*
+ * mac_SCC.c: m68k version of
+ *
+ * macserial.c: Serial port driver for Power Macintoshes.
+ *		Extended for the 68K mac by Alan Cox.
+ *              Rewritten to m68k serial design by Michael Schmitz
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * Design note for the m68k rewrite:
+ * The structure of the m68k serial code requires separation of the low-level
+ * functions that talk directly to the hardware from the Linux serial driver 
+ * code interfacing to the tty layer. The reason for this separation is simply
+ * the fact that the m68k serial hardware is, unlike the i386, based on a 
+ * variety of chips, and the rs_* serial routines need to be shared.
+ *
+ * I've tried to make consistent use of the async_struct info populated in the
+ * midlevel code, and introduced an async_private struct to hold the Macintosh 
+ * SCC internals (this was added to the async_struct for the PowerMac driver).
+ * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
+ * is still filled in by the probe_sccs() routine, which provides some data 
+ * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so 
+ * the console/kgdb stuff probably won't work before proper serial init, and 
+ * I have to rely on keeping info and zs_soft consistent at least for the 
+ * console/kgdb port.
+ *
+ * Update (16-11-97): The SCC interrupt handling was suffering from the problem
+ * that the autovector SCC interrupt was registered only once, hence only one
+ * async_struct was passed to the interrupt function and only interrupts from 
+ * the corresponding channel could be handled (yes, major design flaw).
+ * The autovector interrupt is now registered by the main interrupt initfunc, 
+ * and uses a handler that will call the registered SCC specific interrupts in 
+ * turn. The SCC init has to register these as machspec interrupts now, as is 
+ * done for the VIA interrupts elsewhere.
+ */
+
+#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/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#ifndef CONFIG_MAC
+#include <asm/prom.h>
+#endif
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "mac_SCC.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL	2		/* Max number of ZS chips supported */
+#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
+
+#ifdef CONFIG_MAC
+/*
+ *	All the Macintosh 68K boxes that have an MMU also have hardware
+ *	recovery delays.
+ */
+#define RECOVERY_DELAY
+#else
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+   but we need the eieio to make sure that the accesses occur
+   in the order we want. */
+#define RECOVERY_DELAY	eieio()
+#endif
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct m68k_async_struct  zs_soft[NUM_CHANNELS];
+struct m68k_async_private zs_soft_private[NUM_CHANNELS];
+int zs_channels_found;
+struct m68k_async_struct *zs_chain;	/* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct m68k_async_struct  *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+static unsigned char kgdb_regs[16] = {
+	0, 0, 0,		/* write 0, 1, 2 */
+	(Rx8 | RxENABLE),	/* write 3 */
+	(X16CLK | SB1 | PAR_EVEN), /* write 4 */
+	(Tx8 | TxENAB),		/* write 5 */
+	0, 0, 0,		/* write 6, 7, 8 */
+	(NV),			/* write 9 */
+	(NRZ),			/* write 10 */
+	(TCBR | RCBR),		/* write 11 */
+	1, 0,			/* 38400 baud divisor, write 12 + 13 */
+	(BRENABL),		/* write 14 */
+	(DCDIE)			/* write 15 */
+};
+
+#define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+
+/***************************** Prototypes *****************************/
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
+#if 0
+#ifdef MODULE
+static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
+#endif
+#endif
+
+/* FIXME !!! Currently, only autovector interrupt used! */
+#if 0
+static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
+#endif
+
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
+                           *tty, struct file *file );
+static void SCC_init( struct m68k_async_struct *info );
+static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
+static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
+				    int divisor );
+static void SCC_change_speed( struct m68k_async_struct *info );
+#if 0
+static int SCC_clocksrc( unsigned baud_base, unsigned channel );
+#endif
+static void SCC_throttle( struct m68k_async_struct *info, int status );
+static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
+static void SCC_get_serial_info( struct m68k_async_struct *info, struct
+				serial_struct *retinfo );
+static unsigned int SCC_get_modem_info( struct m68k_async_struct *info );
+static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int
+			      new_rts );
+static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
+		     m68k_async_struct *info, unsigned int cmd, unsigned long arg );
+static void SCC_stop_receive (struct m68k_async_struct *info);
+static int SCC_trans_empty (struct m68k_async_struct *info);
+
+/************************* End of Prototypes **************************/
+
+
+static SERIALSWITCH SCC_switch = {
+	SCC_init, SCC_deinit, SCC_enab_tx_int,
+	SCC_check_custom_divisor, SCC_change_speed,
+	SCC_throttle, SCC_set_break,
+	SCC_get_serial_info, SCC_get_modem_info,
+	SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
+	SCC_check_open
+};
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 0 };
+
+/* 
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+				       unsigned char reg)
+{
+	unsigned char retval;
+
+	if (reg != 0) {
+		*channel->control = reg;
+		RECOVERY_DELAY;
+	}
+	retval = *channel->control;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+			       unsigned char reg, unsigned char value)
+{
+	if (reg != 0) {
+		*channel->control = reg;
+		RECOVERY_DELAY;
+	}
+	*channel->control = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+	unsigned char retval;
+
+	retval = *channel->data;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+				unsigned char value)
+{
+	*channel->data = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+			       unsigned char *regs)
+{
+	ZS_CLEARERR(channel);
+	ZS_CLEARFIFO(channel);
+	/* Load 'em up */
+	write_zsreg(channel, R4, regs[R4]);
+	write_zsreg(channel, R10, regs[R10]);
+	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+	write_zsreg(channel, R1, regs[R1]);
+	write_zsreg(channel, R9, regs[R9]);
+	write_zsreg(channel, R11, regs[R11]);
+	write_zsreg(channel, R12, regs[R12]);
+	write_zsreg(channel, R13, regs[R13]);
+	write_zsreg(channel, R14, regs[R14]);
+	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R3, regs[R3]);
+	write_zsreg(channel, R5, regs[R5]);
+	return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
+{
+	if (set)
+		ss->private->curregs[5] |= (RTS | DTR);
+	else
+		ss->private->curregs[5] &= ~(RTS | DTR);
+	write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
+	return;
+}
+
+static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
+{
+	int brg;
+
+	if (intson) {
+		kgdb_regs[R1] = INT_ALL_Rx;
+		kgdb_regs[R9] |= MIE;
+	} else {
+		kgdb_regs[R1] = 0;
+		kgdb_regs[R9] &= ~MIE;
+	}
+	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	kgdb_regs[R12] = brg;
+	kgdb_regs[R13] = brg >> 8;
+	load_zsregs(ss->private->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct m68k_async_struct *ss)
+{
+	struct mac_zschannel *channel = ss->private->zs_channel;
+	int brg;
+
+	/* The baud rate is split up between two 8-bit registers in
+	 * what is termed 'BRG time constant' format in my docs for
+	 * the chip, it is a function of the clk rate the chip is
+	 * receiving which happens to be constant.
+	 */
+	brg = (read_zsreg(channel, 13) << 8);
+	brg |= read_zsreg(channel, 12);
+	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void SCC_recv_clear(struct mac_zschannel *zsc)
+{
+	write_zsreg(zsc, 0, ERR_RES);
+	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
+				   struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, stat, flag;
+
+	while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+		stat = read_zsreg(info->private->zs_channel, R1);
+		ch = read_zsdata(info->private->zs_channel);
+
+#ifdef SCC_DEBUG
+		printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
+#endif
+
+#if 0	/* KGDB not yet supported */
+		/* Look for kgdb 'stop' character, consult the gdb documentation
+		 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+		 * to see how all this works.
+		 */
+		if ((info->kgdb_channel) && (ch =='\003')) {
+			breakpoint();
+			continue;
+		}
+#endif
+
+		if (!tty)
+			continue;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			tty_flip_buffer_push(tty);
+		
+		if (stat & Rx_OVR) {
+			flag = TTY_OVERRUN;
+			/* reset the error indication */
+			write_zsreg(info->private->zs_channel, 0, ERR_RES);
+		} else if (stat & FRM_ERR) {
+			/* this error is not sticky */
+			flag = TTY_FRAME;
+		} else if (stat & PAR_ERR) {
+			flag = TTY_PARITY;
+			/* reset the error indication */
+			write_zsreg(info->private->zs_channel, 0, ERR_RES);
+		} else
+			flag = 0;
+
+		if (tty->flip.buf_num 
+		    && tty->flip.count >= TTY_FLIPBUF_SIZE) {
+#ifdef SCC_DEBUG_OVERRUN
+			printk("mac_SCC: flip buffer overrun!\n");
+#endif
+			return;
+		}
+
+		if (!tty->flip.buf_num 
+		    && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
+			printk("mac_SCC: double flip buffer overrun!\n");
+			return;
+		}
+
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = flag;
+		*tty->flip.char_buf_ptr++ = ch;
+		info->icount.rx++;
+		tty_flip_buffer_push(tty);
+	}
+#if 0
+clear_and_exit:
+	SCC_recv_clear(info->private->zs_channel);
+#endif
+}
+
+/* that's SCC_enable_tx_int, basically */
+
+static void transmit_chars(struct m68k_async_struct *info)
+{
+	if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
+		return;
+	info->private->tx_active = 0;
+
+	if (info->x_char) {
+		/* Send next char */
+		write_zsdata(info->private->zs_channel, info->x_char);
+		info->x_char = 0;
+		info->private->tx_active = 1;
+		return;
+	}
+
+	if ((info->xmit_cnt <= 0) || info->tty->stopped 
+	     || info->private->tx_stopped) {
+		write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
+		return;
+	}
+
+	/* Send char */
+	write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->icount.tx++;
+	info->xmit_cnt--;
+	info->private->tx_active = 1;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
+{
+	unsigned char status;
+
+	/* Get status from Read Register 0 */
+	status = read_zsreg(info->private->zs_channel, 0);
+
+	/* Check for DCD transitions */
+	if (((status ^ info->private->read_reg_zero) & DCD) != 0
+	    && info->tty && C_CLOCAL(info->tty)) {
+		if (status & DCD) {
+			wake_up_interruptible(&info->open_wait);
+		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+			if (info->tty)
+				tty_hangup(info->tty);
+		}
+	}
+
+	/* Check for CTS transitions */
+	if (info->tty && C_CRTSCTS(info->tty)) {
+		/*
+		 * For some reason, on the Power Macintosh,
+		 * it seems that the CTS bit is 1 when CTS is
+		 * *negated* and 0 when it is asserted.
+		 * The DCD bit doesn't seem to be inverted
+		 * like this.
+		 */
+		if ((status & CTS) == 0) {
+			if (info->private->tx_stopped) {
+				info->private->tx_stopped = 0;
+				if (!info->private->tx_active)
+					transmit_chars(info);
+			}
+		} else {
+			info->private->tx_stopped = 1;
+		}
+	}
+
+	/* Clear status condition... */
+	write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
+	info->private->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
+	unsigned char zs_intreg;
+	int shift;
+
+	/* NOTE: The read register 3, which holds the irq status,
+	 *       does so for both channels on each chip.  Although
+	 *       the status value itself must be read from the A
+	 *       channel and is only valid when read from channel A.
+	 *       Yes... broken hardware...
+	 */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+#ifdef SCC_DEBUG
+	printk("mac_SCC: interrupt; port: %lx channel: %lx \n", 
+		info->port, info->private->zs_channel);
+#endif
+
+	if (info->private->zs_chan_a == info->private->zs_channel)
+		shift = 3;	/* Channel A */
+	else
+		shift = 0;	/* Channel B */
+
+	for (;;) {
+		zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
+#ifdef SCC_DEBUG
+		printk("mac_SCC: status %x shift %d shifted %x \n", 
+		zs_intreg, shift, zs_intreg >> shift);
+#endif
+		zs_intreg = zs_intreg >> shift;
+		if ((zs_intreg & CHAN_IRQMASK) == 0)
+			break;
+
+		if (zs_intreg & CHBRxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHBTxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHBEXT)
+			status_handle(info);
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
+{
+	unsigned long flags;
+
+	if (enab_flag) {
+#if 0
+		save_flags(flags); cli();
+		if (info->private->curregs[5] & TxENAB) {
+			info->private->curregs[5] &= ~TxENAB;
+			info->private->pendregs[5] &= ~TxENAB;
+			write_zsreg(info->private->zs_channel, 5, 
+				    info->private->curregs[5]);
+		}
+		restore_flags(flags);
+#endif
+	/* FIXME: should call transmit_chars here ??? */
+		transmit_chars(info);
+	} else {
+	save_flags(flags); cli();
+#if 0
+		if (  info->xmit_cnt && info->xmit_buf && 
+		    !(info->private->curregs[5] & TxENAB)) {
+			info->private->curregs[5] |= TxENAB;
+			info->private->pendregs[5] = info->private->curregs[5];
+			write_zsreg(info->private->zs_channel, 5, 
+				    info->private->curregs[5]);
+		}
+#else
+		if ( info->xmit_cnt && info->xmit_buf && 
+		    !info->private->tx_active) {
+			transmit_chars(info);
+		}
+#endif
+		restore_flags(flags);	
+	}
+
+}
+
+#if 0
+/*
+ * leftover from original driver ...
+ */
+static int SCC_startup(struct m68k_async_struct * info)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+	/*
+	 * Clear the receive FIFO.
+	 */
+	ZS_CLEARFIFO(info->private->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	write_zsreg(info->private->zs_channel, 0, ERR_RES);
+	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+	/*
+	 * Turn on RTS and DTR.
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
+				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	info->private->pendregs[1] = info->private->curregs[1];
+	info->private->curregs[3] |= (RxENABLE | Rx8);
+	info->private->pendregs[3] = info->private->curregs[3];
+	info->private->curregs[5] |= (TxENAB | Tx8);
+	info->private->pendregs[5] = info->private->curregs[5];
+	info->private->curregs[9] |= (NV | MIE);
+	info->private->pendregs[9] = info->private->curregs[9];
+	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+	/*
+	 * Set the speed of the serial port
+	 */
+	SCC_change_speed(info);
+
+	/* Save the current value of RR0 */
+	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+	restore_flags(flags);
+	return 0;
+}
+#endif
+
+/* FIXME: are these required ?? */
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
+			  struct file *file )
+{
+	/* check on the basis of info->whatever ?? */
+	if (info->private->kgdb_channel || info->private->is_cons)
+		return -EBUSY;
+	return( 0 );
+}
+
+static void SCC_init( struct m68k_async_struct *info )
+{
+	/* FIXME: init currently done in probe_sccs() */
+
+	/* BUT: startup part needs to be done here! */
+
+#ifdef SCC_DEBUG
+	printk("mac_SCC: init, info %lx, info->port %lx  \n", info, info->port);
+#endif
+	/*
+	 * Clear the receive FIFO.
+	 */
+	ZS_CLEARFIFO(info->private->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	write_zsreg(info->private->zs_channel, 0, ERR_RES);
+	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+	/*
+	 * Turn on RTS and DTR.
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
+				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	info->private->pendregs[1] = info->private->curregs[1];
+	info->private->curregs[3] |= (RxENABLE | Rx8);
+	info->private->pendregs[3] = info->private->curregs[3];
+	info->private->curregs[5] |= (TxENAB | Tx8);
+	info->private->pendregs[5] = info->private->curregs[5];
+	info->private->curregs[9] |= (NV | MIE);
+	info->private->pendregs[9] = info->private->curregs[9];
+	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+	/*
+	 * Set the speed of the serial port - done in startup() !!
+	 */
+#if 0
+	SCC_change_speed(info);
+#endif
+
+	/* Save the current value of RR0 */
+	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+}
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
+{
+	static int got_autovector = 0;
+
+#ifdef SCC_DEBUG
+	printk("mac_SCC: init_port, info %x \n", info);
+#endif
+	info->sw = &SCC_switch;
+	info->private = &zs_soft_private[channel];
+	info->private->zs_channel = &zs_channels[channel];
+	info->irq = IRQ4;
+	info->private->clk_divisor = 16;
+	info->private->zs_baud = get_zsbaud(info);
+	info->port = (int) info->private->zs_channel->control;
+
+	/*
+	 * MSch: Extended interrupt scheme:
+	 * The generic m68k interrupt code can't use multiple handlers for
+	 * the same interrupt source (no chained interrupts).
+	 * We have to plug in a 'master' interrupt handler instead, calling 
+	 * mac_SCC_interrupt with the proper arguments ...
+	 */
+
+	if (!got_autovector) {
+		if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
+			panic("macserial: can't get irq %d", IRQ4);
+#ifdef SCC_DEBUG
+		printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
+			IRQ4, channel, info);
+#endif
+		got_autovector = 1;
+	}
+
+	if (info->private->zs_chan_a == info->private->zs_channel) {
+		/* Channel A */
+		if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
+			panic("mac_SCC: can't get irq %d", IRQ_SCCA);
+#ifdef SCC_DEBUG
+		printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
+			IRQ_SCCA, channel, info);
+#endif
+	} else {
+		/* Channel B */
+		if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
+			panic("mac_SCC: can't get irq %d", IRQ_SCCB);
+#ifdef SCC_DEBUG
+		printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", 
+			IRQ_SCCB, channel, info);
+#endif
+	}
+
+	/* If console serial line, then enable interrupts. */
+	if (info->private->is_cons) {
+		printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+		write_zsreg(info->private->zs_channel, R1,
+			    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+		write_zsreg(info->private->zs_channel, R9, (NV | MIE));
+		write_zsreg(info->private->zs_channel, R10, (NRZ));
+		write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
+		write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
+	}
+	/* If this is the kgdb line, enable interrupts because we
+	 * now want to receive the 'control-c' character from the
+	 * client attached to us asynchronously.
+	 */
+	if (info->private->kgdb_channel) {
+		printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+		kgdb_chaninit(info, 1, info->private->zs_baud);
+	}
+	/* Report settings (in m68kserial.c) */
+#ifndef CONFIG_MAC
+	printk("ttyS%d at 0x%08x (irq = %d)", info->line, 
+		       info->port, info->irq);
+	printk(" is a Z8530 SCC\n");
+#endif
+
+}
+
+/*
+ * 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 SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
+{
+	unsigned long	flags;
+
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	info->private->pendregs[1] = info->private->curregs[1] = 0;
+	write_zsreg(info->private->zs_channel, 1, 0);	/* no interrupts */
+
+	info->private->curregs[3] &= ~RxENABLE;
+	info->private->pendregs[3] = info->private->curregs[3];
+	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+
+	info->private->curregs[5] &= ~TxENAB;
+
+	if (!leave_dtr)
+		info->private->curregs[5] &= ~(DTR | RTS);
+	else
+		info->private->curregs[5] &= ~(RTS);
+
+	info->private->pendregs[5] = info->private->curregs[5];
+	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+
+	restore_flags(flags);
+}
+
+/* FIXME !!! */
+static int SCC_check_custom_divisor( struct m68k_async_struct *info,
+				    int baud_base, int divisor )
+{
+	return 0;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void SCC_change_speed(struct m68k_async_struct *info)
+{
+	unsigned short port;
+	unsigned cflag;
+	int	i;
+	int	brg;
+	unsigned long flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+	i = cflag & CBAUD;
+
+	if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
+		/* speed == 0 -> drop DTR */
+		save_flags(flags);
+		cli();
+		info->private->curregs[5] &= ~(DTR | RTS);
+		write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+		restore_flags(flags);
+		return;
+	}
+
+
+	if (i & CBAUDEX) {
+		/* XXX CBAUDEX is not obeyed.
+		 * It is impossible at a 32bits PPC.  XXX??
+		 * But we have to report this to user ... someday.
+		 */
+		i = B9600;
+	}
+
+	save_flags(flags); cli();
+	info->private->zs_baud = baud_table[i];
+	info->private->clk_divisor = 16;
+
+	info->private->curregs[4] = X16CLK;
+	info->private->curregs[11] = TCBR | RCBR;
+	brg = BPS_TO_BRG(info->private->zs_baud, 
+			 ZS_CLOCK/info->private->clk_divisor);
+	info->private->curregs[12] = (brg & 255);
+	info->private->curregs[13] = ((brg >> 8) & 255);
+	info->private->curregs[14] = BRENABL;
+
+	/* byte size and parity */
+	info->private->curregs[3] &= ~RxNBITS_MASK;
+	info->private->curregs[5] &= ~TxNBITS_MASK;
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->private->curregs[3] |= Rx5;
+		info->private->curregs[5] |= Tx5;
+		break;
+	case CS6:
+		info->private->curregs[3] |= Rx6;
+		info->private->curregs[5] |= Tx6;
+		break;
+	case CS7:
+		info->private->curregs[3] |= Rx7;
+		info->private->curregs[5] |= Tx7;
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->private->curregs[3] |= Rx8;
+		info->private->curregs[5] |= Tx8;
+		break;
+	}
+	info->private->pendregs[3] = info->private->curregs[3];
+	info->private->pendregs[5] = info->private->curregs[5];
+
+	info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+	if (cflag & CSTOPB) {
+		info->private->curregs[4] |= SB2;
+	} else {
+		info->private->curregs[4] |= SB1;
+	}
+	if (cflag & PARENB) {
+		info->private->curregs[4] |= PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->private->curregs[4] |= PAR_EVEN;
+	}
+	info->private->pendregs[4] = info->private->curregs[4];
+
+	info->private->curregs[15] &= ~(DCDIE | CTSIE);
+	if (!(cflag & CLOCAL)) {
+		info->private->curregs[15] |= DCDIE;
+	}
+	if (cflag & CRTSCTS) {
+		info->private->curregs[15] |= CTSIE;
+		if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
+			info->private->tx_stopped = 1;
+	} else
+		info->private->tx_stopped = 0;
+	info->private->pendregs[15] = info->private->curregs[15];
+
+	/* Load up the new values */
+	load_zsregs(info->private->zs_channel, info->private->curregs);
+
+	restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void SCC_put_char(char ch)
+{
+	struct mac_zschannel *chan = zs_conschan;
+	int loops = 0;
+	unsigned long flags;
+
+	if(!chan)
+		return;
+
+	save_flags(flags); cli();
+	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
+		loops++;
+		udelay(5);
+	}
+	write_zsdata(chan, ch);
+	restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+	struct mac_zschannel *chan = zs_kgdbchan;
+
+	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+		udelay(5);
+	write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+	struct mac_zschannel *chan = zs_kgdbchan;
+
+	while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+		udelay(5);
+	return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void SCC_fair_output(void)
+{
+	int left;		/* Output no more than that */
+	unsigned long flags;
+	struct m68k_async_struct *info = zs_consinfo;
+	char c;
+
+	if (info == 0) return;
+	if (info->xmit_buf == 0) return;
+
+	save_flags(flags);  cli();
+	left = info->xmit_cnt;
+	while (left != 0) {
+		c = info->xmit_buf[info->xmit_tail];
+		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+		restore_flags(flags);
+
+		SCC_put_char(c);
+
+		save_flags(flags);  cli();
+		left = MIN(info->xmit_cnt, left-1);
+	}
+
+	restore_flags(flags);
+	return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+	char c;
+
+	while ((c = *(p++)) != 0) {
+		if (c == '\n')
+			SCC_put_char('\r');
+		SCC_put_char(c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	SCC_fair_output();
+}
+
+/* FIXME: check with SCC_enab_tx_int!! */
+#if 0
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	transmit_chars(info);
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, total = 0;
+	struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			down(&tmp_buf_sem);
+			memcpy_fromfs(tmp_buf, buf, c);
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			up(&tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+	    && !info->tx_active)
+		transmit_chars(info);
+	restore_flags(flags);
+	return total;
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void SCC_throttle(struct m68k_async_struct *info, int status)
+{
+	unsigned long	flags;
+
+	save_flags(flags); 
+	cli();
+
+	if (status) {
+		/*
+		 * Here we want to turn off the RTS line.  On Macintoshes,
+		 * we only get the DTR line, which goes to both DTR and
+		 * RTS on the modem.  RTS doesn't go out to the serial
+		 * port socket.  So you should make sure your modem is
+		 * set to ignore DTR if you're using CRTSCTS.
+		 */
+		info->private->curregs[5] &= ~(DTR | RTS);
+		info->private->pendregs[5] &= ~(DTR | RTS);
+		write_zsreg(info->private->zs_channel, 5, 
+			    info->private->curregs[5]);
+	} else {
+		/* Assert RTS and DTR lines */
+		info->private->curregs[5] |= DTR | RTS;
+		info->private->pendregs[5] |= DTR | RTS;
+		write_zsreg(info->private->zs_channel, 5, 
+			    info->private->curregs[5]);
+	}
+
+	restore_flags(flags);
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static void SCC_get_serial_info(struct m68k_async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	retinfo->baud_base = info->baud_base;
+	retinfo->custom_divisor = info->custom_divisor;
+}
+
+/* FIXME: set_serial_info needs check_custom_divisor !!! */
+
+/*
+ * 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 SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+
+	cli();
+	status = read_zsreg(info->private->zs_channel, 0);
+	sti();
+	return status;
+}
+
+static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
+{
+	unsigned char control, status;
+	unsigned int result;
+
+	cli();
+	control = info->private->curregs[5];
+	status = read_zsreg(info->private->zs_channel, 0);
+	sti();
+	result =  ((control & RTS) ? TIOCM_RTS: 0)
+		| ((control & DTR) ? TIOCM_DTR: 0)
+		| ((status  & DCD) ? TIOCM_CAR: 0)
+		| ((status  & CTS) ? 0: TIOCM_CTS);
+	return result;
+}
+
+/* FIXME: zs_setdtr was used in rs_open ... */
+
+static int SCC_set_modem_info(struct m68k_async_struct *info, 
+			      int new_dtr, int new_rts)
+{
+	int error;
+	unsigned int arg, bits;
+
+	bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
+	info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
+	info->private->pendregs[5] = info->private->curregs[5];
+	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+	sti();
+	return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	if (break_flag) {
+		info->private->curregs[5] |= SND_BRK;
+		write_zsreg(info->private->zs_channel, 5, 
+			    info->private->curregs[5]);
+	} else {
+		info->private->curregs[5] &= ~SND_BRK;
+		write_zsreg(info->private->zs_channel, 5, 
+			    info->private->curregs[5]);
+	}
+
+	restore_flags(flags);
+}
+
+/* FIXME: these have to be enabled in rs_ioctl !! */
+
+static int SCC_ioctl(struct tty_struct *tty, struct file * file,
+		    struct m68k_async_struct * info, unsigned int cmd, 
+	            unsigned long arg)
+{
+	int error;
+	int retval;
+
+	switch (cmd) {
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return SCC_get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct m68k_async_struct));
+			if (error)
+				return error;
+			copy_to_user((struct m68k_async_struct *) arg,
+				      info, sizeof(struct m68k_async_struct));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void SCC_stop_receive (struct m68k_async_struct *info)
+{
+	/* disable Rx */
+	info->private->curregs[3] &= ~RxENABLE;
+	info->private->pendregs[3] = info->private->curregs[3];
+	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+	/* disable Rx interrupts */
+	info->private->curregs[1] &= ~(0x18);	/* disable any rx ints */
+	info->private->pendregs[1] = info->private->curregs[1];
+	write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
+	ZS_CLEARFIFO(info->private->zs_channel);
+}
+
+static int SCC_trans_empty (struct m68k_async_struct *info)
+{
+	return  (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+#ifdef CONFIG_MAC
+
+/*
+ *	Mac: use boot_info data; assume 2 channels
+ */
+ 
+static void probe_sccs(void)
+{
+	int n;
+
+#define ZS_CONTROL	0x50F04000
+#define ZS_DATA		(ZS_CONTROL+4)
+#define ZS_IRQ		5
+#define ZS_MOVE		-2
+#define ZS_DATA_MOVE	4
+#define ZS_CH_A_FIRST	2
+
+	/* last-ditch fixup for NetBSD booter case */
+	if (mac_bi_data.sccbase == 0)
+		mac_bi_data.sccbase = ZS_CONTROL;
+
+	/* testing: fix up broken 24 bit addresses (ClassicII) */
+	if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
+		mac_bi_data.sccbase |= 0x50000000;
+
+	for(n=0;n<2;n++)
+	{
+#if 0
+		zs_channels[n].control = (volatile unsigned char *)
+				ZS_CONTROL+ZS_MOVE*n;
+		zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
+#else
+		zs_channels[n].control = (volatile unsigned char *)
+			(mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
+		zs_channels[n].data = (volatile unsigned char *)
+			(mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
+#endif
+		zs_soft[n].private = &zs_soft_private[n];
+		zs_soft[n].private->zs_channel = &zs_channels[n];
+		zs_soft[n].irq = IRQ4;
+#if 0		
+		if (request_irq(ch->intrs[0], rs_interrupt, 0,
+				"SCC", &zs_soft[n]))
+			panic("macserial: can't get irq %d",
+			      ch->intrs[0]);
+#endif
+		if (n & 1)
+			zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+		else
+			zs_soft[n].private->zs_chan_a = &zs_channels[n];
+	}
+
+	zs_channels_found=2;
+}
+
+#else
+
+/*
+ *	PowerMAC - query the PROM
+ */
+ 
+static void show_serial_version(void)
+{
+	printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+	struct device_node *dev, *ch;
+	struct m68k_async_struct **pp;
+	int n;
+
+	n = 0;
+	pp = &zs_chain;
+	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+		if (n >= NUM_CHANNELS) {
+			printk("Sorry, can't use %s: no more channels\n",
+			       dev->full_name);
+			continue;
+		}
+		for (ch = dev->child; ch != 0; ch = ch->sibling) {
+			if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+				printk("Can't use %s: %d addrs %d intrs\n",
+				      ch->full_name, ch->n_addrs, ch->n_intrs);
+				continue;
+			}
+			zs_channels[n].control = (volatile unsigned char *)
+				ch->addrs[0].address;
+			zs_channels[n].data = zs_channels[n].control
+				+ ch->addrs[0].size / 2;
+			zs_soft[n].private = &zs_soft_private[n];
+			zs_soft[n].private->zs_channel = &zs_channels[n];
+			zs_soft[n].irq = ch->intrs[0];
+			if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
+					"SCC", &zs_soft[n]))
+				panic("macserial: can't get irq %d",
+				      ch->intrs[0]);
+			/* XXX this assumes the prom puts chan A before B */
+			if (n & 1)
+				zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+			else
+				zs_soft[n].private->zs_chan_a = &zs_channels[n];
+
+			*pp = &zs_soft[n];
+			pp = &zs_soft[n].private->zs_next;
+			++n;
+		}
+	}
+	*pp = 0;
+	zs_channels_found = n;
+}
+
+#endif
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct m68k_async_struct *ss, int channel)
+{
+	int i, o, io;
+	static consout_registered = 0;
+	static msg_printed = 0;
+
+	i = o = io = 0;
+
+	/* Is this one of the serial console lines? */
+	if ((zs_cons_chanout != channel) &&
+	    (zs_cons_chanin != channel))
+		return;
+	zs_conschan = ss->private->zs_channel;
+	zs_consinfo = ss;
+
+	/* Register the console output putchar, if necessary */
+	if (zs_cons_chanout == channel) {
+		o = 1;
+		/* double whee.. */
+		if (!consout_registered) {
+			register_console(zs_console_print);
+			consout_registered = 1;
+		}
+	}
+
+	if (zs_cons_chanin == channel) {
+		i = 1;
+	}
+	if (o && i)
+		io = 1;
+	if (ss->private->zs_baud != 9600)
+		panic("Console baud rate weirdness");
+
+	/* Set flag variable for this port so that it cannot be
+	 * opened for other uses by accident.
+	 */
+	ss->private->is_cons = 1;
+
+	if (io) {
+		if(!msg_printed) {
+			printk("zs%d: console I/O\n", ((channel>>1)&1));
+			msg_printed = 1;
+		}
+	} else {
+		printk("zs%d: console %s\n", ((channel>>1)&1),
+		       (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+	}
+
+	/* FIXME : register interrupt here??? */
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int mac_SCC_init(void)
+{
+	int channel, line, nr = 0, i;
+	unsigned long flags;
+	struct serial_struct req;
+	struct m68k_async_struct *info;
+
+	printk("Mac68K Z8530 serial driver version 1.01\n");
+
+	/* SCC present at all? */
+	if (MACH_IS_ATARI || MACH_IS_AMIGA 
+#if 0
+	    || !(MACHW_PRESENT(SCC) || MACHW_PRESENT(ST_ESCC))
+#endif
+	   )
+		return( -ENODEV );
+
+	if (zs_chain == 0)
+		probe_sccs();
+
+	save_flags(flags);
+	cli();
+
+	/* 
+	 * FIXME: init of rs_table entry and register_serial now done,
+	 * but possible clash of zs_soft[channel] and rs_table[channel]!!
+	 * zs_soft initialized in probe_sccs(), some settings copied to
+	 * info = &rs_table[channel], which is used by the mid-level code.
+	 * The info->private part is shared among both!
+	 */
+
+	for (channel = 0; channel < zs_channels_found; ++channel) {
+		req.line = channel;
+		req.type = SER_SCC_MAC;
+		req.port = zs_soft[channel].private->zs_channel->control;
+
+		if ((line = register_serial( &req )) >= 0) {
+			SCC_init_port( &rs_table[line], req.type, line );
+			++nr;
+		}
+		else
+			printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
+	}
+
+	restore_flags(flags);
+
+	return( nr > 0 ? 0 : -ENODEV );
+}
+
+/* Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+	if (zs_chain == 0)
+		probe_sccs();
+	zs_soft[channel].private->clk_divisor = 16;
+	zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
+	rs_cons_check(&zs_soft[channel], channel);
+	if (out)
+		zs_cons_chanout = channel;
+	else
+		zs_cons_chanin = channel;
+
+	/* FIXME : register interrupt here??? */
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+	if (zs_chain == 0)
+		probe_sccs();
+	zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
+	zs_soft[tty_num].private->clk_divisor = 16;
+	zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
+	zs_soft[tty_num].private->kgdb_channel = 1;     /* This runs kgdb */
+	zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
+	/* Turn on transmitter/receiver at 8-bits/char */
+	kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+	ZS_CLEARERR(zs_kgdbchan);
+	ZS_CLEARFIFO(zs_kgdbchan);
+
+	/* FIXME : register interrupt here??? */
+}
+
diff -u --recursive --new-file v2.1.105/linux/drivers/char/mac_SCC.h linux/drivers/char/mac_SCC.h
--- v2.1.105/linux/drivers/char/mac_SCC.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/mac_SCC.h	Sat Jun 13 13:44:30 1998
@@ -0,0 +1,321 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MAC_SCC_H
+#define _MAC_SCC_H
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF	0
+#define ZILOG_CLOSING_WAIT_NONE	65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+				   on the callout port */
+#define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK	0x0030
+#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS	0x0FFF	/* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430	/* Legal flags that non-privileged
+				 * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+/* MSch: gone to <asm/serial.h> */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+#define RxNBITS_MASK	0xc0
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+#define SB_MASK		0xc
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+#define XCLK_MASK	0xC0
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define TxNBITS_MASK	0x60
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define	ZCIE	2	/* Zero count IE */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	FRM_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				} while(0)
+
+#endif /* !(_MAC_SCC_H) */
diff -u --recursive --new-file v2.1.105/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.105/linux/drivers/char/mem.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/char/mem.c	Sat Jun 13 12:10:30 1998
@@ -27,8 +27,14 @@
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_SOUND
+void soundcore_init(void);
+#ifdef CONFIG_SOUND_OSS
 void soundcard_init(void);
 #endif
+#ifdef CONFIG_DMASOUND
+void dmasound_init(void);
+#endif
+#endif
 #ifdef CONFIG_ISDN
 int isdn_init(void);
 #endif
@@ -539,6 +545,9 @@
 	soundcore_init();
 #ifdef CONFIG_SOUND_OSS	
 	soundcard_init();
+#endif	
+#ifdef CONFIG_DMASOUND
+	dmasound_init();
 #endif	
 #endif
 #ifdef CONFIG_JOYSTICK
diff -u --recursive --new-file v2.1.105/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.105/linux/drivers/char/misc.c	Thu May 14 19:47:39 1998
+++ linux/drivers/char/misc.c	Sat Jun 13 13:44:30 1998
@@ -72,6 +72,7 @@
 extern int amiga_mouse_init(void);
 extern int atari_mouse_init(void);
 extern int sun_mouse_init(void);
+extern int adb_mouse_init(void);
 extern void watchdog_init(void);
 extern void wdt_init(void);
 extern void acq_init(void);
@@ -223,6 +224,9 @@
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
 #endif
+#ifdef CONFIG_MACMOUSE
+	adb_mouse_init();
+#endif
 #ifdef CONFIG_PC110_PAD
 	pc110pad_init();
 #endif
@@ -250,7 +254,7 @@
 #ifdef CONFIG_H8
 	h8_init();
 #endif
-#ifdef CONFIG_RTC
+#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
 	rtc_init();
 #endif
 #ifdef CONFIG_ATARI_DSP56K
diff -u --recursive --new-file v2.1.105/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.1.105/linux/drivers/char/msp3400.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/char/msp3400.c	Tue Jun  9 01:21:49 1998
@@ -916,7 +916,7 @@
 	if (-1 == msp3400c_reset(msp->bus)) {
 		UNLOCK_I2C_BUS(msp->bus);
 		kfree(msp);
-		return -1;
+		return -EIO;
 	}
     
 	msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
@@ -1088,6 +1088,8 @@
 	msp3400c_detach,
 	msp3400c_command
 };
+
+EXPORT_NO_SYMBOLS;
 
 #ifdef MODULE
 int init_module(void)
diff -u --recursive --new-file v2.1.105/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.1.105/linux/drivers/char/nvram.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/nvram.c	Sat Jun 13 13:44:30 1998
@@ -156,7 +156,7 @@
  *
  * They're only built if CONFIG_ATARI is defined, because Atari drivers use
  * them. For other configurations (PC), the rest of the kernel can't rely on
- * them being present (this driver couldn't be configured at all, or as a
+ * them being present (this driver may not be configured at all, or as a
  * module), so they access config information themselves.
  */
 
@@ -227,12 +227,15 @@
 	return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
 }
 
-static ssize_t nvram_read( struct file * file,
-						char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_read(struct file * file,
+	char * buf, size_t count, loff_t *ppos )
 {
 	unsigned long flags;
 	unsigned i = *ppos;
 	char *tmp = buf;
+	
+	if (i != *ppos)
+		return -EINVAL;
 
 	save_flags(flags);
 	cli();
@@ -250,12 +253,16 @@
 	return( tmp - buf );
 }
 
-static ssize_t nvram_write( struct file * file, const char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_write(struct file * file,
+		const char * buf, size_t count, loff_t *ppos )
 {
 	unsigned long flags;
 	unsigned i = *ppos;
 	const char *tmp = buf;
 	char c;
+	
+	if (i != *ppos)
+		return -EINVAL;
 
 	save_flags(flags);
 	cli();
@@ -411,7 +418,7 @@
 	if (!CHECK_DRIVER_INIT())
 	    return( -ENXIO );
 
-	printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+	printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
 	misc_register( &nvram_dev );
 #ifdef CONFIG_PROC_FS
 	if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
@@ -618,7 +625,7 @@
 #define fieldsize(a)	(sizeof(a)/sizeof(*a))
 
 static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
-							 off_t *begin, off_t offset, int size )
+			    off_t *begin, off_t offset, int size )
 {
 	int checksum = nvram_check_checksum();
 	int i;
@@ -645,7 +652,7 @@
 
 	/* the following entries are defined only for the Falcon */
 	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
-		return;
+		return 1;
 
 	PRINT_PROC( "OS language      : " );
 	if (nvram[6] < fieldsize(languages))
diff -u --recursive --new-file v2.1.105/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.105/linux/drivers/char/pc_keyb.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/char/pc_keyb.c	Sat Jun 13 13:44:30 1998
@@ -178,6 +178,20 @@
 		              | KBD_MODE_DISABLE_MOUSE
 		              | KBD_MODE_KCC);
 
+	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+		/*
+		 * If the controller does not support conversion,
+		 * Set the keyboard to scan-code set 1.
+		 */
+		kbd_write(KBD_DATA_REG, 0xF0);
+		kbd_wait_for_input();
+		kbd_write(KBD_DATA_REG, 0x01);
+		kbd_wait_for_input();
+	}
+
+	
 	kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
 	if (kbd_wait_for_input() != KBD_REPLY_ACK)
 		return "Enable keyboard: no ACK";
diff -u --recursive --new-file v2.1.105/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c
--- v2.1.105/linux/drivers/char/radio-aimslab.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/char/radio-aimslab.c	Sat Jun 13 10:26:27 1998
@@ -1,6 +1,7 @@
 /* radiotrack (radioreveal) driver for Linux radio support
  * (c) 1997 M. Kirkwood
  * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
  *
@@ -47,7 +48,7 @@
 
 /* local things */
 
-static void sleep_delay(int n)
+static void sleep_delay(long n)
 {
 	/* Sleep nicely for 'n' uS */
 	int d=n/1000000/HZ;
@@ -61,108 +62,129 @@
 			schedule();
 	}
 }
-	
-/* Clock out data to the chip. This looks suspiciously like i2c as usual */
-
-static void outbits(int bits, int data, int port)
-{
-	while(bits--) 
-	{
-		if(data & 1) 
-		{
-			outw(5, port);
-			outw(5, port);
-			outw(7, port);
-			outw(7, port);
-		}
-		else 
-		{
-			outw(1, port);
-			outw(1, port);
-			outw(3, port);
-			outw(3, port);
-		}
-		data>>=1;
-	}
-}
 
-static void rt_decvol(int port)
+static void rt_decvol(void)
 {
-	outb(0x48, port);
+	outb(0x58, io);		/* volume down + sigstr + on	*/
 	sleep_delay(100000);
-	outb(0xc8, port);
+	outb(0xd8, io);		/* volume steady + sigstr + on	*/
 }
 
-static void rt_incvol(int port)
+static void rt_incvol(void)
 {
-	outb(0x88, port);
+	outb(0x98, io);		/* volume up + sigstr + on	*/
 	sleep_delay(100000);
-	outb(0xc8, port);
+	outb(0xd8, io);		/* volume steady + sigstr + on	*/
 }
 
-static void rt_mute(int port)
+static void rt_mute(void)
 {
-	outb(0, port);
-	outb(0xc0, port);
-}
-
-static void rt_unmute(int port)
-{
-	outb(0, port);
-	outb(0xc8, port);
+	outb(0x48, io);			/* volume down but still "on"	*/
+	sleep_delay(2000000);		/* make sure it's totally down	*/
+	outb(0xc0, io);			/* volume steady, off		*/
 }
 
 static int rt_setvol(struct rt_device *dev, int vol)
 {
 	int i;
-	if(vol == dev->curvol)
+
+	if(vol == dev->curvol)		/* no change needed */
 		return 0;
 
-	if(vol == 0)
-		rt_mute(dev->port);
+	if(vol == 0) {			/* volume = 0 means mute the card */
+		rt_mute();
+		dev->curvol = 0;
+		return 0;
+	}
 
 	if(vol > dev->curvol)
-		for(i = dev->curvol; i < vol; i++)
-			rt_incvol(dev->port);
+		for(i = dev->curvol; i < vol; i++) 
+			rt_incvol();
 	else
-		for(i = dev->curvol; i > vol; i--)
-			rt_decvol(dev->port);
+		for(i = dev->curvol; i > vol; i--) 
+			rt_decvol();
 
-	if(dev->curvol == 0)
-		rt_unmute(dev->port);
+	dev->curvol = vol;
 
 	return 0;
 }
 
-static int rt_setfreq(struct rt_device *dev, unsigned long frequency)
+/* the 128+64 on these outb's is to keep the volume stable while tuning 
+ * without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled
+ */
+
+void send_0_byte(int port, struct rt_device *dev)
+{
+	if (dev->curvol == 0) {
+		outb_p(128+64+16+  1, port);   /* wr-enable + data low */
+		outb_p(128+64+16+2+1, port);   /* clock */
+	}
+	else {
+		outb_p(128+64+16+8+  1, port);  /* on + wr-enable + data low */
+		outb_p(128+64+16+8+2+1, port);  /* clock */
+	}
+	sleep_delay(1000); 
+}
+
+void send_1_byte(int port, struct rt_device *dev)
 {
-	int myport = dev->port;
-#define	RTRACK_ENCODE(x)	(((((x)*2)/5)-(40*88))+0xf6c)
-	outbits(16, RTRACK_ENCODE(frequency), myport);
-	outbits(8, 0xa0, myport);
-/* XXX - get rid of this once setvol is implemented properly - XXX */
-/* these insist on turning the thing on.  not sure I approve... */
-	udelay(1000);
-	outb(0, myport);
-	outb(0xc8, myport);
+	if (dev->curvol == 0) {
+		outb_p(128+64+16+4  +1, port);   /* wr-enable+data high */
+		outb_p(128+64+16+4+2+1, port);   /* clock */
+	} 
+	else {
+		outb_p(128+64+16+8+4  +1, port); /* on+wr-enable+data high */
+		outb_p(128+64+16+8+4+2+1, port); /* clock */
+	}
 
-	return 0;
+	sleep_delay(1000); 
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_setfreq(struct rt_device *dev, unsigned long freq)
 {
-	int res;
-	int myport = dev->port;
+	int i;
 
-	outb(0xf8, myport);
-	sleep_delay(200000);
-	res = (int)inb(myport);
-	sleep_delay(10000);
-	outb(0xe8, myport);
-	if(res == 0xfd)
-		return 1;
+	/* adapted from radio-aztech.c */
+
+	freq = (freq / 16.0) * 100;	/* massage the data a little	*/
+	freq += 1070;			/* IF = 10.7 MHz 		*/
+	freq /= 5;			/* ref = 25 kHz			*/
+
+	send_0_byte (io, dev);		/*  0: LSB of frequency		*/
+
+	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)	*/
+		if (freq & (1 << i))
+			send_1_byte (io, dev);
+		else
+			send_0_byte (io, dev);
+
+	send_0_byte (io, dev);		/* 14: test bit - always 0    */
+	send_0_byte (io, dev);		/* 15: test bit - always 0    */
+
+	send_0_byte (io, dev);		/* 16: band data 0 - always 0 */
+	send_0_byte (io, dev);		/* 17: band data 1 - always 0 */
+	send_0_byte (io, dev);		/* 18: band data 2 - always 0 */
+	send_0_byte (io, dev);		/* 19: time base - always 0   */
+
+	send_0_byte (io, dev);		/* 20: spacing (0 = 25 kHz)   */
+	send_1_byte (io, dev);		/* 21: spacing (1 = 25 kHz)   */
+	send_0_byte (io, dev);		/* 22: spacing (0 = 25 kHz)   */
+	send_1_byte (io, dev);		/* 23: AM/FM (FM = 1, always) */
+
+	if (dev->curvol == 0)
+		outb (0xd0, io);	/* volume steady + sigstr */
 	else
+		outb (0xd8, io);	/* volume steady + sigstr + on */
+
+	return 0;
+}
+
+int rt_getsigstr(struct rt_device *dev)
+{
+	if (inb(io) & 2)	/* bit set = no signal present	*/
 		return 0;
+	return 1;		/* signal present		*/
 }
 
 static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -226,7 +248,7 @@
 			struct video_audio v;
 			memset(&v,0, sizeof(v));
 			v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			v.volume=rt->curvol;
+			v.volume=rt->curvol * 6554;
 			strcpy(v.name, "Radio");
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
@@ -239,12 +261,14 @@
 				return -EFAULT;	
 			if(v.audio) 
 				return -EINVAL;
-			rt->curvol=v.volume;
 
-			if(v.flags&VIDEO_AUDIO_MUTE) 
-				rt_mute(rt->port);
+			if(v.flags&VIDEO_AUDIO_MUTE) {
+				rt_mute();
+				rt->curvol=0;
+			}
 			else
-				rt_setvol(rt,rt->curvol/6554);	
+				rt_setvol(rt,v.volume/6554);	
+
 			return 0;
 		}
 		default:
@@ -299,7 +323,8 @@
 	request_region(io, 2, "rtrack");
 	printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
 	/* mute card - prevents noisy bootups */
-	rt_mute(io);
+	rt_mute();
+	rtrack_unit.curvol = 0;
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.105/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.1.105/linux/drivers/char/random.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/char/random.c	Sat Jun 13 11:38:49 1998
@@ -513,6 +513,10 @@
 	do_gettimeofday(&tv);
 	add_entropy_words(r, tv.tv_sec, tv.tv_usec);
 
+	/*
+	 *	This doesnt lock system.utsname. Howeve we are generating
+	 *	entropy so a race with a name set here is fine.
+	 */
 	p = (__u32 *)&system_utsname;
 	for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
 		memcpy(words, p, sizeof(words));
diff -u --recursive --new-file v2.1.105/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.105/linux/drivers/char/tty_io.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/char/tty_io.c	Sat Jun 13 13:44:30 1998
@@ -123,6 +123,10 @@
 static int tty_ioctl(struct inode * inode, struct file * file,
 		     unsigned int cmd, unsigned long arg);
 static int tty_fasync(struct file * filp, int on);
+#ifdef CONFIG_8xx
+extern long console_8xx_init(void);
+extern int rs_8xx_init(void);
+#endif /* CONFIG_8xx */
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -2055,6 +2059,9 @@
 #ifdef CONFIG_SERIAL
 	rs_init();
 #endif
+#ifdef CONFIG_MAC_SERIAL
+	macserial_init();
+#endif
 #ifdef CONFIG_ROCKETPORT
 	rp_init();
 #endif
@@ -2079,6 +2086,9 @@
 #ifdef CONFIG_SPECIALIX
 	specialix_init();
 #endif
+#ifdef CONFIG_8xx
+        rs_8xx_init();
+#endif /* CONFIG_8xx */
 	pty_init();
 #ifdef CONFIG_VT
 	vcs_init();
diff -u --recursive --new-file v2.1.105/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.1.105/linux/drivers/char/tuner.c	Wed Apr  8 19:36:26 1998
+++ linux/drivers/char/tuner.c	Tue Jun  9 01:21:49 1998
@@ -243,6 +243,8 @@
 	tuner_command
 };
 
+EXPORT_NO_SYMBOLS;
+
 #ifdef MODULE
 int init_module(void)
 #else
diff -u --recursive --new-file v2.1.105/linux/drivers/dio/Makefile linux/drivers/dio/Makefile
--- v2.1.105/linux/drivers/dio/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/dio/Makefile	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# 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...
+#
+# NB: cribbed from the drivers/sbus/Makefile -- PMM
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_OBJS   := dio.o
+L_TARGET := dio.a
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/drivers/dio/dio.c linux/drivers/dio/dio.c
--- v2.1.105/linux/drivers/dio/dio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/dio/dio.c	Sat Jun 13 13:14:31 1998
@@ -0,0 +1,292 @@
+/* Code to support devices on the DIO (and eventually DIO-II) bus
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * 
+ * This code has basically these routines at the moment:
+ * int dio_find(u_int deviceid)
+ *    Search the list of DIO devices and return the select code
+ *    of the next unconfigured device found that matches the given device ID.
+ *    Note that the deviceid parameter should be the encoded ID.
+ *    This means that framebuffers should pass it as 
+ *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
+ *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
+ * void *dio_scodetoviraddr(int scode)
+ *    Return the virtual address corresponding to the given select code.
+ *    NB: DIO-II devices will have to be mapped in in this routine!
+ * int dio_scodetoipl(int scode)
+ *    Every DIO card has a fixed interrupt priority level. This function 
+ *    returns it, whatever it is.
+ * const char *dio_scodetoname(int scode)
+ *    Return a character string describing this board [might be "" if 
+ *    not CONFIG_DIO_CONSTANTS]
+ * void dio_config_board(int scode)     mark board as configured in the list
+ * void dio_unconfig_board(int scode)   mark board as no longer configured
+ *
+ * This file is based on the way the Amiga port handles Zorro II cards, 
+ * although we aren't so complicated...
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/dio.h>
+#include <linux/malloc.h>                         /* kmalloc() */
+#include <linux/init.h>
+#include <asm/hwtest.h>                           /* hwreg_present() */
+#include <asm/io.h>                               /* readb() */
+/* not a real config option yet! */
+#define CONFIG_DIO_CONSTANTS
+
+#ifdef CONFIG_DIO_CONSTANTS
+/* We associate each numeric ID with an appropriate descriptive string
+ * using a constant array of these structs.
+ * FIXME: we should be able to arrange to throw away most of the strings
+ * using the initdata stuff. Then we wouldn't need to worry about 
+ * carrying them around...
+ * I think we do this by copying them into newly kmalloc()ed memory and 
+ * marking the names[] array as .initdata ?
+ */
+struct dioname
+{
+        int id;
+        const char *name;
+};
+
+/* useful macro */
+#define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
+#define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
+
+static struct dioname names[] = 
+{
+        DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
+        DIONAME(DCM), DIONAME(DCMREM),
+        DIONAME(LAN),
+        DIONAME(FHPIB), DIONAME(NHPIB), DIONAME(IHPIB),
+        DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
+        DIONAME(FBUFFER),
+        DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
+        DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
+        DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
+        DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11), 
+        DIONAME(MISC12), DIONAME(MISC13),
+        DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
+        DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
+        DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
+        DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)   
+};
+
+#undef DIONAME
+#undef DIOFBNAME
+
+#define NUMNAMES (sizeof(names) / sizeof(struct dioname))
+
+static const char *unknowndioname 
+        = "unknown DIO board -- please email <pmaydell@chiark.greenend.org.uk>!";
+
+static const char *dio_getname(int id)
+{
+        /* return pointer to a constant string describing the board with given ID */
+	unsigned int i;
+        for (i = 0; i < NUMNAMES; i++)
+                if (names[i].id == id) 
+                        return names[i].name;
+        
+        return unknowndioname;
+}
+
+#else
+
+static char dio_no_name[] = { 0 };
+#define dio_getname(_id)	(dio_no_name)
+
+#endif /* CONFIG_DIO_CONSTANTS */
+
+/* We represent all the DIO boards in the system with a linked list of these structs. */
+struct dioboard
+{
+        struct dioboard *next;                    /* link to next struct in list */
+        int ipl;                                  /* IPL of this board */
+        int configured;                           /* has this board been configured? */
+        int scode;                                /* select code of this board */
+        int id;                                   /* encoded ID */
+        const char *name;
+};
+
+static struct dioboard *blist = NULL;
+
+__initfunc(static int dio_find_slow(int deviceid))
+{
+	/* Called to find a DIO device before the full bus scan has run.  Basically
+	   only used by the console driver.  */
+	int scode;
+	for (scode = 0; scode < DIO_SCMAX; scode++)
+	{
+		void *va;
+
+                if (DIO_SCINHOLE(scode))
+                        continue;
+                
+                va = dio_scodetoviraddr(scode);
+                if (!va || !hwreg_present(va + DIO_IDOFF))
+                        continue;             /* no board present at that select code */
+
+		if (DIO_ID(va) == deviceid)
+			return scode;
+	}
+	return 0;
+}
+
+int dio_find(int deviceid)
+{
+	if (blist) 
+	{
+		/* fast way */
+		struct dioboard *b;
+		for (b = blist; b; b = b->next)
+			if (b->id == deviceid && b->configured == 0)
+				return b->scode;
+		return 0;
+	}
+	return dio_find_slow(deviceid);
+}
+
+/* This is the function that scans the DIO space and works out what
+ * hardware is actually present.
+ */
+__initfunc(void dio_init(void))
+{
+        int scode;
+        struct dioboard *b, *bprev = NULL;
+   
+        printk("Scanning for DIO devices...\n");
+        
+        for (scode = 0; scode < DIO_SCMAX; ++scode)
+        {
+                u_char prid, secid = 0;        /* primary, secondary ID bytes */
+                u_char *va;
+                
+                if (DIO_SCINHOLE(scode))
+                        continue;
+                
+                va = dio_scodetoviraddr(scode);
+                if (!va || !hwreg_present(va + DIO_IDOFF))
+                        continue;              /* no board present at that select code */
+
+                /* Found a board, allocate it an entry in the list */
+                b = kmalloc(sizeof(struct dioboard), GFP_KERNEL);
+                
+                /* read the ID byte(s) and encode if necessary. Note workaround 
+                 * for broken internal HPIB devices...
+                 */
+                if (!DIO_ISIHPIB(scode))
+                        prid = DIO_ID(va);
+                else 
+                        prid = DIO_ID_IHPIB;
+                
+                if (DIO_NEEDSSECID(prid))
+                {
+                        secid = DIO_SECID(va);
+                        b->id = DIO_ENCODE_ID(prid, secid);
+                }
+                else
+                        b->id = prid;
+      
+                b->configured = 0;
+                b->scode = scode;
+                b->ipl = DIO_IPL(va);
+                b->name = dio_getname(b->id);
+                printk("select code %3d: ID %02X", scode, prid);
+                if (DIO_NEEDSSECID(b->id))
+                        printk(":%02X", secid);
+                printk(" %s\n", b->name);
+                
+                b->next = NULL;
+
+                if (bprev)
+                        bprev->next = b;
+                else
+                        blist = b;
+                bprev = b;
+        }
+}
+
+/* Bear in mind that this is called in the very early stages of initialisation
+ * in order to get the virtual address of the serial port for the console...
+ */
+void *dio_scodetoviraddr(int scode)
+{
+        if (scode > DIOII_SCBASE)
+        {
+                printk("dio_scodetoviraddr: don't support DIO-II yet!\n");
+                return 0;
+        }
+        else if (scode > DIO_SCMAX || scode < 0)
+                return 0;
+        else if (DIO_SCINHOLE(scode))
+                return 0;
+        else if (scode == DIO_IHPIBSCODE) /* this should really be #ifdef CONFIG_IHPIB */
+                return (void*)DIO_IHPIBADDR;   /* or something similar... */
+        
+        return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000);
+}
+
+int dio_scodetoipl(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+        
+        if (!b)
+        {
+                printk("dio_scodetoipl: bad select code %d\n", scode);
+                return 0;
+        }
+        else
+                return b->ipl;
+}
+
+const char *dio_scodetoname(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+        
+        if (!b)
+        {
+                printk("dio_scodetoname: bad select code %d\n", scode);
+                return NULL;
+        }
+        else
+                return b->name;
+}
+
+void dio_config_board(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode)
+                        break;
+   
+        if (!b) 
+                printk("dio_config_board: bad select code %d\n", scode);
+        else if (b->configured)
+                printk("dio_config_board: board at select code %d already configured\n", scode);
+        else
+                b->configured = 1;
+}
+
+void dio_unconfig_board(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+   
+        if (!b) 
+                printk("dio_unconfig_board: bad select code %d\n", scode);
+        else if (!b->configured)
+                printk("dio_unconfig_board: board at select code %d not configured\n", 
+		       scode);
+        else 
+                b->configured = 0;
+}
diff -u --recursive --new-file v2.1.105/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.1.105/linux/drivers/misc/parport_arc.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/misc/parport_arc.c	Sat Jun 13 12:56:46 1998
@@ -82,6 +82,12 @@
 	arc_release_resources,
 	arc_claim_resources,
 	
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
 	NULL, /* epp_write_block */
 	NULL, /* epp_read_block */
 
diff -u --recursive --new-file v2.1.105/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c
--- v2.1.105/linux/drivers/misc/parport_ax.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/misc/parport_ax.c	Sat Jun 13 12:56:46 1998
@@ -39,7 +39,8 @@
 #define DATA		0x00
 #define STATUS		0x01
 #define CONTROL		0x02
-#define EPPREG		0x04
+#define EPPADDR		0x03
+#define EPPDATA		0x04
 
 #define CFIFO		0x400
 #define DFIFO		0x400
@@ -57,13 +58,34 @@
 void
 parport_ax_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base + EPPREG);
+	outb(d, p->base + EPPDATA);
 }
 
 unsigned char
 parport_ax_read_epp(struct parport *p)
 {
-	return inb(p->base + EPPREG);
+	return inb(p->base + EPPDATA);
+}
+
+void
+parport_ax_write_epp_addr(struct parport *p, unsigned char d)
+{
+	outb(d, p->base + EPPADDR);
+}
+
+unsigned char
+parport_ax_read_epp_addr(struct parport *p)
+{
+	return inb(p->base + EPPADDR);
+}
+
+int 
+parport_ax_check_epp_timeout(struct parport *p)
+{
+	if (!(inb(p->base+STATUS) & 1))
+		return 0;
+	parport_ax_epp_clear_timeout(p);
+	return 1;
 }
 
 unsigned char
@@ -302,6 +324,12 @@
 	parport_ax_release_resources,
 	parport_ax_claim_resources,
 	
+	parport_ax_write_epp,
+	parport_ax_read_epp,
+	parport_ax_write_epp_addr,
+	parport_ax_read_epp_addr,
+	parport_ax_check_epp_timeout,
+
 	parport_ax_epp_write_block,
 	parport_ax_epp_read_block,
 
@@ -498,7 +526,7 @@
 	if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
 		return 0;
 
-	/* Safe away pointer to our EBus DMA */
+	/* Save away pointer to our EBus DMA */
 	p->private_data = (void *)dev->base_address[2];
 
 	p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
diff -u --recursive --new-file v2.1.105/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.105/linux/drivers/misc/parport_pc.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/misc/parport_pc.c	Sat Jun 13 12:56:46 1998
@@ -20,8 +20,8 @@
  *
  * In addition, there are some optional registers:
  *
- *	base+3		EPP command
- *	base+4		EPP
+ *	base+3		EPP address
+ *	base+4		EPP data
  *	base+0x400	ECP config A
  *	base+0x401	ECP config B
  *	base+0x402	ECP control
@@ -60,12 +60,30 @@
 
 void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPREG);
+	outb(d, p->base+EPPDATA);
 }
 
 unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPREG);
+	return inb(p->base+EPPDATA);
+}
+
+void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+	outb(d, p->base+EPPADDR);
+}
+
+unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+	return inb(p->base+EPPADDR);
+}
+
+int parport_pc_check_epp_timeout(struct parport *p)
+{
+	if (!(inb(p->base+STATUS) & 1))
+		return 0;
+	parport_pc_epp_clear_timeout(p);
+	return 1;
 }
 
 unsigned char parport_pc_read_configb(struct parport *p)
@@ -196,7 +214,7 @@
 {
 	size_t got = 0;
 	for (; got < length; got++) {
-		*((char*)buf)++ = inb (p->base+EPPREG);
+		*((char*)buf)++ = inb (p->base+EPPDATA);
 		if (inb (p->base+STATUS) & 0x01)
 			break;
 	}
@@ -207,7 +225,7 @@
 {
 	size_t written = 0;
 	for (; written < length; written++) {
-		outb (*((char*)buf)++, p->base+EPPREG);
+		outb (*((char*)buf)++, p->base+EPPDATA);
 		if (inb (p->base+STATUS) & 0x01)
 			break;
 	}
@@ -267,6 +285,12 @@
 	parport_pc_release_resources,
 	parport_pc_claim_resources,
 	
+	parport_pc_write_epp,
+	parport_pc_read_epp,
+	parport_pc_write_epp_addr,
+	parport_pc_read_epp_addr,
+	parport_pc_check_epp_timeout,
+
 	parport_pc_epp_write_block,
 	parport_pc_epp_read_block,
 
@@ -290,7 +314,7 @@
 /*
  * Clear TIMEOUT BIT in EPP MODE
  */
-static int epp_clear_timeout(struct parport *pb)
+int parport_pc_epp_clear_timeout(struct parport *pb)
 {
 	unsigned char r;
 
@@ -313,6 +337,14 @@
  */
 static int parport_SPP_supported(struct parport *pb)
 {
+	/*
+	 * first clear an eventually pending EPP timeout 
+	 * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+	 * that does not even respond to SPP cycles if an EPP
+	 * timeout is pending
+	 */
+	parport_pc_epp_clear_timeout(pb);
+
 	/* Do a simple read-write test to make sure the port exists. */
 	parport_pc_write_control(pb, 0xc);
 	parport_pc_write_data(pb, 0xaa);
@@ -406,18 +438,18 @@
 static int parport_EPP_supported(struct parport *pb)
 {
 	/* If EPP timeout bit clear then EPP available */
-	if (!epp_clear_timeout(pb))
+	if (!parport_pc_epp_clear_timeout(pb))
 		return 0;  /* No way to clear timeout */
 
 	parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
 	parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 	
 	parport_pc_read_epp(pb);
 	udelay(30);  /* Wait for possible EPP timeout */
 	
 	if (parport_pc_read_status(pb) & 0x01) {
-		epp_clear_timeout(pb);
+		parport_pc_epp_clear_timeout(pb);
 		return PARPORT_MODE_PCEPP;
 	}
 
@@ -465,7 +497,7 @@
 	int ok = 0;
 	unsigned char octr = parport_pc_read_control(pb);
   
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 
 	parport_pc_write_control(pb, octr | 0x20);  /* try to tri-state the buffer */
 	
@@ -563,10 +595,10 @@
 	if (pb->modes & PARPORT_MODE_PCECR)
 		parport_pc_frob_econtrol (pb, 0x10, 0x10);
 	
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 	parport_pc_frob_control (pb, 0x20, 0x20);
 	parport_pc_frob_control (pb, 0x10, 0x10);
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 
 	/* Device isn't expecting an EPP read
 	 * and generates an IRQ.
@@ -648,12 +680,12 @@
 	    (pb->modes & PARPORT_MODE_PCECPEPP))
 		pb->irq = irq_probe_EPP(pb);
 
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 
 	if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
 		pb->irq = irq_probe_EPP(pb);
 
-	epp_clear_timeout(pb);
+	parport_pc_epp_clear_timeout(pb);
 
 	if (pb->irq == PARPORT_IRQ_NONE)
 		pb->irq = irq_probe_SPP(pb);
diff -u --recursive --new-file v2.1.105/linux/drivers/net/7990.c linux/drivers/net/7990.c
--- v2.1.105/linux/drivers/net/7990.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/7990.c	Sat Jun 13 13:28:34 1998
@@ -0,0 +1,651 @@
+/* 
+ * 7990.c -- LANCE ethernet IC generic routines. 
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE 
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ * NB: this was made easy by the fact that Jes Sorensen had cleaned up
+ * most of a2025 and sunlance with the aim of merging them, so the 
+ * common code was pretty obvious.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <linux/errno.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "7990.h"
+
+/* Lossage Factor Nine, Mr Sulu. */
+#define WRITERAP(x) (lp->writerap(lp,x))
+#define WRITERDP(x) (lp->writerdp(lp,x))
+#define READRDP() (lp->readrdp(lp))
+/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh. 
+ * If you want to switch them back then 
+ * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
+ */
+#define DECLARE_LL /* nothing to declare */
+
+/* debugging output macros, various flavours */
+/* #define TEST_HITS */
+#ifdef UNDEF
+#define PRINT_RINGS() \
+do { \
+        int t; \
+        for (t=0; t < RX_RING_SIZE; t++) { \
+                printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n",\
+                       t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0,\
+                       ib->brx_ring[t].length,\
+                       ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits);\
+        }\
+        for (t=0; t < TX_RING_SIZE; t++) { \
+                printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n",\
+                       t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0,\
+                       ib->btx_ring[t].length,\
+                       ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
+        }\
+} while (0) 
+#else
+#define PRINT_RINGS()
+#endif        
+
+/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
+static void load_csrs (struct lance_private *lp)
+{
+        volatile struct lance_init_block *aib = lp->lance_init_block;
+        int leptr;
+        DECLARE_LL;
+
+        leptr = LANCE_ADDR (aib);
+
+        WRITERAP(LE_CSR1);                        /* load address of init block */
+        WRITERDP(leptr & 0xFFFF);
+        WRITERAP(LE_CSR2);
+        WRITERDP(leptr >> 16);
+        WRITERAP(LE_CSR3);
+        WRITERDP(lp->busmaster_regval);           /* set byteswap/ALEctrl/byte ctrl */
+
+        /* Point back to csr0 */
+        WRITERAP(LE_CSR0);
+}
+
+/* #define to 0 or 1 appropriately */
+#define DEBUG_IRING 0
+/* Set up the Lance Rx and Tx rings and the init block */
+/* Sets dev->tbusy */
+static void lance_init_ring (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
+        int leptr;
+        int i;
+
+        aib = lp->lance_init_block;
+
+        /* Lock out other processes while setting up hardware */
+        dev->tbusy = 1;
+        lp->rx_new = lp->tx_new = 0;
+        lp->rx_old = lp->tx_old = 0;
+
+        ib->mode = LE_MO_PROM;                             /* normal, enable Tx & Rx */
+
+        /* Copy the ethernet address to the lance init block
+         * Notice that we do a byteswap if we're big endian.
+         * [I think this is the right criterion; at least, sunlance,
+         * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
+         * However, the datasheet says that the BSWAP bit doesn't affect
+         * the init block, so surely it should be low byte first for
+         * everybody? Um.] 
+         * We could define the ib->physaddr as three 16bit values and
+         * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
+         */
+#ifdef __BIG_ENDIAN
+        ib->phys_addr [0] = dev->dev_addr [1];
+        ib->phys_addr [1] = dev->dev_addr [0];
+        ib->phys_addr [2] = dev->dev_addr [3];
+        ib->phys_addr [3] = dev->dev_addr [2];
+        ib->phys_addr [4] = dev->dev_addr [5];
+        ib->phys_addr [5] = dev->dev_addr [4];
+#else
+        for (i=0; i<6; i++)
+           ib->phys_addr[i] = dev->dev_addr[i];
+#endif        
+
+        if (DEBUG_IRING)
+                printk ("TX rings:\n");
+    
+        /* Setup the Tx ring entries */
+        for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
+                leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+                ib->btx_ring [i].tmd0      = leptr;
+                ib->btx_ring [i].tmd1_hadr = leptr >> 16;
+                ib->btx_ring [i].tmd1_bits = 0;
+                ib->btx_ring [i].length    = 0xf000; /* The ones required by tmd2 */
+                ib->btx_ring [i].misc      = 0;
+                if (DEBUG_IRING) 
+                   printk ("%d: 0x%8.8x\n", i, leptr);
+        }
+
+        /* Setup the Rx ring entries */
+        if (DEBUG_IRING)
+                printk ("RX rings:\n");
+        for (i = 0; i < (1<<lp->lance_log_rx_bufs); i++) {
+                leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
+
+                ib->brx_ring [i].rmd0      = leptr;
+                ib->brx_ring [i].rmd1_hadr = leptr >> 16;
+                ib->brx_ring [i].rmd1_bits = LE_R1_OWN;
+                /* 0xf000 == bits that must be one (reserved, presumably) */
+                ib->brx_ring [i].length    = -RX_BUFF_SIZE | 0xf000;
+                ib->brx_ring [i].mblength  = 0;
+                if (DEBUG_IRING)
+                        printk ("%d: 0x%8.8x\n", i, leptr);
+        }
+
+        /* Setup the initialization block */
+    
+        /* Setup rx descriptor pointer */
+        leptr = LANCE_ADDR(&aib->brx_ring);
+        ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+        ib->rx_ptr = leptr;
+        if (DEBUG_IRING)
+                printk ("RX ptr: %8.8x\n", leptr);
+    
+        /* Setup tx descriptor pointer */
+        leptr = LANCE_ADDR(&aib->btx_ring);
+        ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+        ib->tx_ptr = leptr;
+        if (DEBUG_IRING)
+                printk ("TX ptr: %8.8x\n", leptr);
+
+        /* Clear the multicast filter */
+        ib->filter [0] = 0;
+        ib->filter [1] = 0;
+        PRINT_RINGS();
+}
+
+/* LANCE must be STOPped before we do this, too... */
+static int init_restart_lance (struct lance_private *lp)
+{
+        int i;
+        DECLARE_LL;
+
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_INIT);
+
+        /* Need a hook here for sunlance ledma stuff */
+
+        /* Wait for the lance to complete initialization */
+        for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+                barrier();
+        if ((i == 100) || (READRDP() & LE_C0_ERR)) {
+                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+                return -1;
+        }
+
+        /* Clear IDON by writing a "1", enable interrupts and start lance */
+        WRITERDP(LE_C0_IDON);
+        WRITERDP(LE_C0_INEA | LE_C0_STRT);
+
+        return 0;
+}
+
+static int lance_reset (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        int status;
+        DECLARE_LL;
+    
+        /* Stop the lance */
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+
+        load_csrs (lp);
+        lance_init_ring (dev);
+        dev->trans_start = jiffies;
+        dev->interrupt = 0;
+        dev->start = 1;
+        dev->tbusy = 0;
+        status = init_restart_lance (lp);
+#ifdef DEBUG_DRIVER
+        printk ("Lance restart=%d\n", status);
+#endif
+        return status;
+}
+
+static int lance_rx (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_rx_desc *rd;
+        unsigned char bits;
+        int len = 0;                    /* XXX shut up gcc warnings */
+        struct sk_buff *skb = 0;        /* XXX shut up gcc warnings */
+#ifdef TEST_HITS
+        int i;
+#endif
+        DECLARE_LL;
+
+#ifdef TEST_HITS
+        printk ("[");
+        for (i = 0; i < RX_RING_SIZE; i++) {
+                if (i == lp->rx_new)
+                        printk ("%s",
+                                ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+                else
+                        printk ("%s",
+                                ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1");
+        }
+        printk ("]");
+#endif
+    
+        WRITERDP(LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
+        for (rd = &ib->brx_ring [lp->rx_new];     /* For each Rx ring we own... */
+             !((bits = rd->rmd1_bits) & LE_R1_OWN);
+             rd = &ib->brx_ring [lp->rx_new]) {
+
+                /* We got an incomplete frame? */
+                if ((bits & LE_R1_POK) != LE_R1_POK) {
+                        lp->stats.rx_over_errors++;
+                        lp->stats.rx_errors++;
+                        continue;
+                } else if (bits & LE_R1_ERR) {
+                        /* Count only the end frame as a rx error,
+                         * not the beginning
+                         */
+                        if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
+                        if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
+                        if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
+                        if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+                        if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+                } else {
+                        len = (rd->mblength & 0xfff) - 4;
+                        skb = dev_alloc_skb (len+2);
+
+                        if (skb == 0) {
+                                printk ("%s: Memory squeeze, deferring packet.\n",
+                                        dev->name);
+                                lp->stats.rx_dropped++;
+                                rd->mblength = 0;
+                                rd->rmd1_bits = LE_R1_OWN;
+                                lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+                                return 0;
+                        }
+            
+                        skb->dev = dev;
+                        skb_reserve (skb, 2);           /* 16 byte align */
+                        skb_put (skb, len);             /* make room */
+                        eth_copy_and_sum(skb,
+                                         (unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
+                                         len, 0);
+                        skb->protocol = eth_type_trans (skb, dev);
+                        netif_rx (skb);
+                        lp->stats.rx_packets++;
+                }
+
+                /* Return the packet to the pool */
+                rd->mblength = 0;
+                rd->rmd1_bits = LE_R1_OWN;
+                lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+        }
+        return 0;
+}
+
+static int lance_tx (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_tx_desc *td;
+        int i, j;
+        int status;
+        DECLARE_LL;
+
+        /* csr0 is 2f3 */
+        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        /* csr0 is 73 */
+
+        j = lp->tx_old;
+        for (i = j; i != lp->tx_new; i = j) {
+                td = &ib->btx_ring [i];
+
+                /* If we hit a packet not owned by us, stop */
+                if (td->tmd1_bits & LE_T1_OWN)
+                        break;
+                
+                if (td->tmd1_bits & LE_T1_ERR) {
+                        status = td->misc;
+            
+                        lp->stats.tx_errors++;
+                        if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
+                        if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+
+                        if (status & LE_T3_CLOS) {
+                                lp->stats.tx_carrier_errors++;
+                                if (lp->auto_select) {
+                                        lp->tpe = 1 - lp->tpe;
+                                        printk("%s: Carrier Lost, trying %s\n",
+                                               dev->name, lp->tpe?"TPE":"AUI");
+                                        /* Stop the lance */
+                                        WRITERAP(LE_CSR0);
+                                        WRITERDP(LE_C0_STOP);
+                                        lance_init_ring (dev);
+                                        load_csrs (lp);
+                                        init_restart_lance (lp);
+                                        return 0;
+                                }
+                        }
+
+                        /* buffer errors and underflows turn off the transmitter */
+                        /* Restart the adapter */
+                        if (status & (LE_T3_BUF|LE_T3_UFL)) {
+                                lp->stats.tx_fifo_errors++;
+
+                                printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+                                        dev->name);
+                                /* Stop the lance */
+                                WRITERAP(LE_CSR0);
+                                WRITERDP(LE_C0_STOP);
+                                lance_init_ring (dev);
+                                load_csrs (lp);
+                                init_restart_lance (lp);
+                                return 0;
+                        }
+                } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+                        /*
+                         * So we don't count the packet more than once.
+                         */
+                        td->tmd1_bits &= ~(LE_T1_POK);
+
+                        /* One collision before packet was sent. */
+                        if (td->tmd1_bits & LE_T1_EONE)
+                                lp->stats.collisions++;
+
+                        /* More than one collision, be optimistic. */
+                        if (td->tmd1_bits & LE_T1_EMORE)
+                                lp->stats.collisions += 2;
+
+                        lp->stats.tx_packets++;
+                }
+        
+                j = (j + 1) & lp->tx_ring_mod_mask;
+        }
+        lp->tx_old = j;
+        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        return 0;
+}
+
+static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct device *dev = (struct device *)dev_id;
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        int csr0;
+        DECLARE_LL;
+        
+        WRITERAP(LE_CSR0);              /* LANCE Controller Status */
+        csr0 = READRDP();
+
+        PRINT_RINGS();
+        
+        if (!(csr0 & LE_C0_INTR))       /* Check if any interrupt has */
+                return;                 /* been generated by the Lance. */
+
+        if (dev->interrupt)
+                printk ("%s: again", dev->name);
+
+        dev->interrupt = 1;
+
+        /* Acknowledge all the interrupt sources ASAP */
+        WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+
+        if ((csr0 & LE_C0_ERR)) {
+                /* Clear the error condition */
+                WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+        }
+
+        if (csr0 & LE_C0_RINT)
+                lance_rx (dev);
+
+        if (csr0 & LE_C0_TINT)
+                lance_tx (dev);
+
+        /* Log misc errors. */
+        if (csr0 & LE_C0_BABL)
+                lp->stats.tx_errors++;       /* Tx babble. */
+        if (csr0 & LE_C0_MISS)
+                lp->stats.rx_errors++;       /* Missed a Rx frame. */
+        if (csr0 & LE_C0_MERR) {
+                printk("%s: Bus master arbitration failure, status %4.4x.\n", 
+                       dev->name, csr0);
+                /* Restart the chip. */
+                WRITERDP(LE_C0_STRT);
+        }
+
+        if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+                dev->tbusy = 0;
+                mark_bh (NET_BH);
+        }
+        
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+        
+        dev->interrupt = 0;
+}
+
+int lance_open (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        DECLARE_LL;
+        
+        /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+        if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+                return -EAGAIN;
+
+        return lance_reset(dev);
+}
+
+int lance_close (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        DECLARE_LL;
+        
+        dev->start = 0;
+        dev->tbusy = 1;
+
+        /* Stop the LANCE */
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+
+        free_irq(lp->irq, dev);
+
+        return 0;
+}
+
+int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        int entry, skblen, len;
+        int status = 0;
+        static int outs;
+        DECLARE_LL;
+
+	lance_reset(dev);
+
+        /* Transmitter timeout, serious problems */
+        if (dev->tbusy) {
+                int tickssofar = jiffies - dev->trans_start;
+            
+                if (tickssofar < 100) {
+                        status = -1;
+                } else {
+                        printk ("%s: transmit timed out, status %04x, resetting\n",
+                                dev->name, READRDP());
+                        lance_reset (dev);
+                }
+                return status;
+        }
+
+        /* Block a timer-based transmit from overlapping. */
+        if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
+                printk ("Transmitter access conflict.\n");
+                return -1;
+        }
+
+        skblen = skb->len;
+
+        if (!TX_BUFFS_AVAIL)
+                return -1;
+
+#ifdef DEBUG_DRIVER
+        /* dump the packet */
+        {
+                int i;
+        
+                for (i = 0; i < 64; i++) {
+                        if ((i % 16) == 0)
+                                printk ("\n");
+                        printk ("%2.2x ", skb->data [i]);
+                }
+        }
+#endif
+        len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+        entry = lp->tx_new & lp->tx_ring_mod_mask;
+        ib->btx_ring [entry].length = (-len) | 0xf000;
+        ib->btx_ring [entry].misc = 0;
+    
+        memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+    
+        /* Now, give the packet to the lance */
+        ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+        lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+
+        outs++;
+        /* Kick the lance: transmit now */
+        WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+        dev->trans_start = jiffies;
+        dev_kfree_skb (skb);
+    
+        if (TX_BUFFS_AVAIL)
+                dev->tbusy = 0;
+
+        return status;
+}
+
+struct net_device_stats *lance_get_stats (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+
+        return &lp->stats;
+}
+
+/* taken from the depca driver via a2065.c */
+static void lance_load_multicast (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile u16 *mcast_table = (u16 *)&ib->filter;
+        struct dev_mc_list *dmi=dev->mc_list;
+        char *addrs;
+        int i, j, bit, byte;
+        u32 crc, poly = CRC_POLYNOMIAL_LE;
+        
+        /* set all multicast bits */
+        if (dev->flags & IFF_ALLMULTI){ 
+                ib->filter [0] = 0xffffffff;
+                ib->filter [1] = 0xffffffff;
+                return;
+        }
+        /* clear the multicast filter */
+        ib->filter [0] = 0;
+        ib->filter [1] = 0;
+
+        /* Add addresses */
+        for (i = 0; i < dev->mc_count; i++){
+                addrs = dmi->dmi_addr;
+                dmi   = dmi->next;
+
+                /* multicast address? */
+                if (!(*addrs & 1))
+                        continue;
+                
+                crc = 0xffffffff;
+                for (byte = 0; byte < 6; byte++)
+                        for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
+                        {
+                                int test;
+
+                                test = ((bit ^ crc) & 0x01);
+                                crc >>= 1;
+
+                                if (test)
+                                {
+                                        crc = crc ^ poly;
+                                }
+                        }
+                
+                crc = crc >> 26;
+                mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+        }
+        return;
+}
+
+
+void lance_set_multicast (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        DECLARE_LL;
+
+        while (dev->tbusy)
+                schedule();
+        set_bit (0, (void *) &dev->tbusy);
+
+        while (lp->tx_old != lp->tx_new)
+                schedule();
+
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+        lance_init_ring (dev);
+
+        if (dev->flags & IFF_PROMISC) {
+                ib->mode |= LE_MO_PROM;
+        } else {
+                ib->mode &= ~LE_MO_PROM;
+                lance_load_multicast (dev);
+        }
+        load_csrs (lp);
+        init_restart_lance (lp);
+        dev->tbusy = 0;
+}
+
diff -u --recursive --new-file v2.1.105/linux/drivers/net/7990.h linux/drivers/net/7990.h
--- v2.1.105/linux/drivers/net/7990.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/7990.h	Sat Jun 13 13:28:34 1998
@@ -0,0 +1,256 @@
+/* 
+ * 7990.h -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ * 
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ */
+
+#ifndef _7990_H
+#define _7990_H
+
+/* The lance only has two register locations. We communicate mostly via memory. */
+struct lance_regs 
+{
+        unsigned short rdp;                       /* Register Data Port */
+        unsigned short rap;                       /* Register Address Port */
+};
+
+/* Transmit/receive ring definitions.
+ * We allow the specific drivers to override these defaults if they want to.
+ * NB: according to lance.c, increasing the number of buffers is a waste
+ * of space and reduces the chance that an upper layer will be able to
+ * reorder queued Tx packets based on priority. [Clearly there is a minimum
+ * limit too: too small and we drop rx packets and can't tx at full speed.]
+ * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
+ */
+
+/* Blast! This won't work. The problem is that we can't specify a default
+ * setting because that would cause the lance_init_block struct to be
+ * too long (and overflow the RAM on shared-memory cards like the HP LANCE.
+ */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+#endif
+
+#define TX_RING_SIZE (1<<LANCE_LOG_TX_BUFFERS)
+#define RX_RING_SIZE (1<<LANCE_LOG_RX_BUFFERS)
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
+#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
+#define PKT_BUFF_SIZE (1544)
+#define RX_BUFF_SIZE PKT_BUFF_SIZE
+#define TX_BUFF_SIZE PKT_BUFF_SIZE
+
+/* Each receive buffer is described by a receive message descriptor (RMD) */
+struct lance_rx_desc {
+	volatile unsigned short rmd0;        /* low address of packet */
+	volatile unsigned char  rmd1_bits;   /* descriptor bits */
+	volatile unsigned char  rmd1_hadr;   /* high address of packet */
+	volatile short    length;    	    /* This length is 2s complement (negative)!
+				     * Buffer length
+				     */
+	volatile unsigned short mblength;    /* Actual number of bytes received */
+};
+ 
+/* Ditto for TMD: */
+struct lance_tx_desc {
+	volatile unsigned short tmd0;        /* low address of packet */
+	volatile unsigned char  tmd1_bits;   /* descriptor bits */
+	volatile unsigned char  tmd1_hadr;   /* high address of packet */
+	volatile short    length;       	    /* Length is 2s complement (negative)! */
+	volatile unsigned short misc;
+};
+
+/* There are three memory structures accessed by the LANCE:
+ * the initialization block, the receive and transmit descriptor rings,
+ * and the data buffers themselves. In fact we might as well put the
+ * init block,the Tx and Rx rings and the buffers together in memory:
+ */
+struct lance_init_block {
+        volatile unsigned short mode;            /* Pre-set mode (reg. 15) */
+        volatile unsigned char phys_addr[6];     /* Physical ethernet address */
+        volatile unsigned filter[2];             /* Multicast filter (64 bits) */
+
+        /* Receive and transmit ring base, along with extra bits. */
+        volatile unsigned short rx_ptr;          /* receive descriptor addr */
+        volatile unsigned short rx_len;          /* receive len and high addr */
+        volatile unsigned short tx_ptr;          /* transmit descriptor addr */
+        volatile unsigned short tx_len;          /* transmit len and high addr */
+    
+        /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. 
+         * This will be true if this whole struct is 8-byte aligned.
+         */
+        volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
+        volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
+
+        volatile char   tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+        volatile char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+        /* we use this just to make the struct big enough that we can move its startaddr
+         * in order to force alignment to an eight byte boundary.
+         */
+};
+
+/* This is where we keep all the stuff the driver needs to know about.
+ * I'm definitely unhappy about the mechanism for allowing specific
+ * drivers to add things...
+ */
+struct lance_private
+{
+        char *name;
+        volatile struct lance_regs *ll;
+        volatile struct lance_init_block *init_block; /* CPU address of RAM */
+        volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
+        
+        int rx_new, tx_new;
+        int rx_old, tx_old;
+        
+        int lance_log_rx_bufs, lance_log_tx_bufs;
+        int rx_ring_mod_mask, tx_ring_mod_mask;
+        
+        struct net_device_stats stats;
+        int tpe;                                  /* TPE is selected */
+        int auto_select;                          /* cable-selection is by carrier */
+        unsigned short busmaster_regval;
+
+        unsigned int irq;                         /* IRQ to register */
+        
+        /* This is because the HP LANCE is disgusting and you have to check 
+         * a DIO-specific register every time you read/write the LANCE regs :-<
+         * [could we get away with making these some sort of macro?]
+         */
+        void (*writerap)(void *, unsigned short);
+        void (*writerdp)(void *, unsigned short);
+        unsigned short (*readrdp)(struct lance_private *);
+};
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+/*
+ *              Am7990 Control and Status Registers
+ */
+#define LE_CSR0         0x0000          /* LANCE Controller Status */
+#define LE_CSR1         0x0001          /* IADR[15:0] (bit0==0 ie word aligned) */
+#define LE_CSR2         0x0002          /* IADR[23:16] (high bits reserved) */
+#define LE_CSR3         0x0003          /* Misc */
+
+/*
+ *		Bit definitions for CSR0 (LANCE Controller Status)
+ */
+#define LE_C0_ERR	0x8000		/* Error = BABL | CERR | MISS | MERR */
+#define LE_C0_BABL	0x4000		/* Babble: Transmitted too many bits */
+#define LE_C0_CERR	0x2000		/* No Heartbeat (10BASE-T) */
+#define LE_C0_MISS	0x1000		/* Missed Frame (no rx buffer to put it in) */
+#define LE_C0_MERR	0x0800		/* Memory Error */
+#define LE_C0_RINT	0x0400		/* Receive Interrupt */
+#define LE_C0_TINT	0x0200		/* Transmit Interrupt */
+#define LE_C0_IDON	0x0100		/* Initialization Done */
+#define LE_C0_INTR	0x0080		/* Interrupt Flag 
+                                         = BABL | MISS | MERR | RINT | TINT | IDON */
+#define LE_C0_INEA	0x0040		/* Interrupt Enable */
+#define LE_C0_RXON	0x0020		/* Receive On */
+#define LE_C0_TXON	0x0010		/* Transmit On */
+#define LE_C0_TDMD	0x0008		/* Transmit Demand */
+#define LE_C0_STOP	0x0004		/* Stop */
+#define LE_C0_STRT	0x0002		/* Start */
+#define LE_C0_INIT	0x0001		/* Initialize */
+
+
+/*
+ *		Bit definitions for CSR3
+ */
+#define LE_C3_BSWP	0x0004		/* Byte Swap
+					   (on for big endian byte order) */
+#define LE_C3_ACON	0x0002		/* ALE Control
+					   (on for active low ALE) */
+#define LE_C3_BCON	0x0001		/* Byte Control */
+
+
+/*
+ *		Mode Flags
+ */
+#define LE_MO_PROM	0x8000		/* Promiscuous Mode */
+/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
+ * but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
+ */
+#define LE_MO_DRCVBC  0x4000          /* disable receive broadcast */
+#define LE_MO_DRCVPA  0x2000          /* disable physical address detection */
+#define LE_MO_DLNKTST 0x1000          /* disable link status */
+#define LE_MO_DAPC    0x0800          /* disable automatic polarity correction */
+#define LE_MO_MENDECL 0x0400          /* MENDEC loopback mode */
+#define LE_MO_LRTTSEL 0x0200          /* lower RX threshold / TX mode selection */
+#define LE_MO_PSEL1   0x0100          /* port selection bit1 */
+#define LE_MO_PSEL0   0x0080          /* port selection bit0 */
+/* and this one is from the C-LANCE data sheet... */
+#define LE_MO_EMBA      0x0080          /* Enable Modified Backoff Algorithm 
+                                           (C-LANCE, not original LANCE) */
+#define LE_MO_INTL	0x0040		/* Internal Loopback */
+#define LE_MO_DRTY	0x0020		/* Disable Retry */
+#define LE_MO_FCOLL	0x0010		/* Force Collision */
+#define LE_MO_DXMTFCS	0x0008		/* Disable Transmit CRC */
+#define LE_MO_LOOP	0x0004		/* Loopback Enable */
+#define LE_MO_DTX	0x0002		/* Disable Transmitter */
+#define LE_MO_DRX	0x0001		/* Disable Receiver */
+
+
+/*
+ *		Receive Flags
+ */
+#define LE_R1_OWN	0x80		/* LANCE owns the descriptor */
+#define LE_R1_ERR	0x40		/* Error */
+#define LE_R1_FRA	0x20		/* Framing Error */
+#define LE_R1_OFL	0x10		/* Overflow Error */
+#define LE_R1_CRC	0x08		/* CRC Error */
+#define LE_R1_BUF	0x04		/* Buffer Error */
+#define LE_R1_SOP	0x02		/* Start of Packet */
+#define LE_R1_EOP	0x01		/* End of Packet */
+#define LE_R1_POK       0x03		/* Packet is complete: SOP + EOP */
+
+
+/*
+ *		Transmit Flags
+ */
+#define LE_T1_OWN	0x80		/* LANCE owns the descriptor */
+#define LE_T1_ERR	0x40		/* Error */
+#define LE_T1_RES	0x20		/* Reserved, LANCE writes this with a zero */
+#define LE_T1_EMORE	0x10		/* More than one retry needed */
+#define LE_T1_EONE	0x08		/* One retry needed */
+#define LE_T1_EDEF	0x04		/* Deferred */
+#define LE_T1_SOP	0x02		/* Start of Packet */
+#define LE_T1_EOP	0x01		/* End of Packet */
+#define LE_T1_POK	0x03		/* Packet is complete: SOP + EOP */
+
+/*
+ *		Error Flags
+ */
+#define LE_T3_BUF 	0x8000		/* Buffer Error */
+#define LE_T3_UFL 	0x4000		/* Underflow Error */
+#define LE_T3_LCOL 	0x1000		/* Late Collision */
+#define LE_T3_CLOS 	0x0800		/* Loss of Carrier */
+#define LE_T3_RTY 	0x0400		/* Retry Error */
+#define LE_T3_TDR	0x03ff		/* Time Domain Reflectometry */
+
+/* Miscellaneous useful macros */
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+                        lp->tx_old+lp->tx_ring_mod_mask-lp->tx_new:\
+                        lp->tx_old - lp->tx_new-1)
+
+/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
+#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
+
+/* Now the prototypes we export */
+extern int lance_open(struct device *dev);
+extern int lance_close (struct device *dev);
+extern int lance_start_xmit (struct sk_buff *skb, struct device *dev);
+extern struct net_device_stats *lance_get_stats (struct device *dev);
+extern void lance_set_multicast (struct device *dev);
+
+#endif /* ndef _7990_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.1.105/linux/drivers/net/8390.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/8390.c	Tue Jun  9 22:43:52 1998
@@ -334,7 +334,6 @@
 	}
     
 	dev->interrupt = 1;
-	sti();
     
 	/* Change to page 0 and read the intr status reg. */
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
@@ -850,8 +849,11 @@
   		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
 }
 
-/* Initialize the rest of the 8390 device structure. */
-__initfunc(int ethdev_init(struct device *dev))
+/*
+ * Initialize the rest of the 8390 device structure.  Do NOT __initfunc
+ * this, as it is used by 8390 based modular drivers too.
+ */
+int ethdev_init(struct device *dev)
 {
 	if (ei_debug > 1)
 		printk(version);
diff -u --recursive --new-file v2.1.105/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.105/linux/drivers/net/Config.in	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/Config.in	Sat Jun 13 12:59:15 1998
@@ -24,6 +24,13 @@
 #
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+  if [ "$CONFIG_ARM" = "y" ]; then
+    if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+      tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
+    else
+      source drivers/acorn/net/Config.in
+    fi
+  fi
   if [ "$CONFIG_PMAC" = "y" ]; then
     bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
   fi
diff -u --recursive --new-file v2.1.105/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.105/linux/drivers/net/Makefile	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/Makefile	Sat Jun 13 13:28:34 1998
@@ -12,14 +12,16 @@
 M_OBJS   :=
 MOD_LIST_NAME := NET_MODULES
 
-# Need these to keep track of whether the 8390, PPP and SLHC modules should
-# really go in the kernel or a module.
+# Need these to keep track of whether the 7990 (LANCE), 8390, PPP and SLHC 
+# modules should really go in the kernel or a module.
 CONFIG_8390_BUILTIN :=
 CONFIG_8390_MODULE  :=
 CONFIG_SLHC_BUILTIN :=
 CONFIG_SLHC_MODULE  :=
 CONFIG_PPPDEF_BUILTIN :=
 CONFIG_PPPDEF_MODULE  :=
+CONFIG_7990_BUILTIN :=
+CONFIG_7990_MODULE :=
 
 ifeq ($(CONFIG_ISDN),y)
   ifeq ($(CONFIG_ISDN_PPP),y)
@@ -111,6 +113,13 @@
   endif
 endif
 
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ETHERH),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
 
 ifeq ($(CONFIG_WD80x3),y)
 L_OBJS += wd.o
@@ -667,6 +676,24 @@
   endif
 endif
 
+ifeq ($(CONFIG_HPLANCE),y)
+L_OBJS += hplance.o
+CONFIG_7990_BUILTIN = y
+else
+  ifeq ($(CONFIG_HPLANCE),m)
+  CONFIG_7990_MODULE = y
+  M_OBJS += hplance.o
+  endif
+endif
+# If we need generic LANCE support, either in the kernel or as a module,
+# build it in the appropriate way.
+ifdef CONFIG_7990_BUILTIN
+L_OBJS += 7990.o
+else
+  ifdef CONFIG_7990_MODULE
+  M_OBJS += 7990.o
+  endif
+endif
 
 ifeq ($(CONFIG_EQUALIZER),y)
 L_OBJS += eql.o
diff -u --recursive --new-file v2.1.105/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.105/linux/drivers/net/Space.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/Space.c	Sat Jun 13 13:29:45 1998
@@ -92,12 +92,17 @@
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int bionet_probe(struct device *);
+extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
+extern int acorn_ethif_probe(struct device *dev);
+extern int am79c961_probe(struct device *dev);
 extern int epic100_probe(struct device *dev);
 extern int rtl8139_probe(struct device *dev);
+extern int hplance_probe(struct device *dev);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -276,6 +281,15 @@
 #ifdef CONFIG_HYDRA		/* Hydra Systems Amiganet Ethernet board */
 	&& hydra_probe(dev)
 #endif
+#ifdef CONFIG_ATARI_BIONET	/* Atari Bionet Ethernet board */
+	&& bionet_probe(dev)
+#endif
+#ifdef CONFIG_ATARI_PAMSNET	/* Atari PAMsNet Ethernet board */
+	&& pamsnet_probe(dev)
+#endif
+#ifdef CONFIG_HPLANCE		/* HP300 internal Ethernet */
+	&& hplance_probe(dev)
+#endif
 #ifdef CONFIG_SUNLANCE
 	&& sparc_lance_probe(dev)
 #endif
@@ -296,7 +310,7 @@
 #endif
 #ifdef CONFIG_MIPS_JAZZ_SONIC
 	&& sonic_probe(dev)
-#endif	
+#endif
 #ifdef CONFIG_ARCH_ACORN
 	&& acorn_ethif_probe(dev)
 #endif
@@ -425,7 +439,7 @@
 # define ETH0_IRQ 0
 #endif
 
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(CONFIG_ARCH_ACORN)
 #define ETH_NOPROBE_ADDR 0xffe0
 #else
 #define ETH_NOPROBE_ADDR 0
diff -u --recursive --new-file v2.1.105/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.1.105/linux/drivers/net/atari_bionet.c	Thu Feb 12 20:56:07 1998
+++ linux/drivers/net/atari_bionet.c	Sat Jun 13 13:28:34 1998
@@ -7,6 +7,8 @@
  *
  * Little adaptions for integration into pl7 by Roman Hodek
  *
+ * Some changes in bionet_poll_rx by Karl-Heinz Lohner
+ *
 	What is it ?
 	------------
 	This driver controls the BIONET-100 LAN-Adapter which connects
@@ -238,7 +240,7 @@
 	dma_wd.dma_mode_status		= 0x9a;
 	dma_wd.dma_mode_status		= 0x19a;
 	dma_wd.dma_mode_status		= 0x9a;
-	dma_wd.fdc_acces_seccount	= 0x05;		/* sector count */
+	dma_wd.fdc_acces_seccount	= 0x04;		/* sector count (was 5) */
 	dma_wd.dma_lo			= (unsigned char)paddr;
 	paddr >>= 8;
 	dma_wd.dma_md			= (unsigned char)paddr;
@@ -293,7 +295,7 @@
 	paddr >>= 8;
 	dma_wd.dma_hi		= (unsigned char)paddr;
 
-	dma_wd.fdc_acces_seccount	= 0xaa;		/* sector count */
+	dma_wd.fdc_acces_seccount	= 0x4;		/* sector count */
 	restore_flags(flags);
 
 	c = sendcmd(0,0x100,NODE_ADR | C_WRITE);	/* CMD: WRITE */
@@ -454,6 +456,28 @@
 			buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
 		}
 
+		if (bionet_debug >1) {
+			u_char *data = nic_packet->buffer, *p;
+			int i;
+			
+			printk( "%s: TX pkt type 0x%4x from ", dev->name,
+				  ((u_short *)data)[6]);
+
+			for( p = &data[6], i = 0; i < 6; i++ )
+				printk("%02x%s", *p++,i != 5 ? ":" : "" );
+			printk(" to ");
+
+			for( p = data, i = 0; i < 6; i++ )
+				printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+			printk( "%s: ", dev->name );
+			printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+			       " %02x%02x%02x%02x len %d\n",
+				  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+				  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+				  data[28], data[29], data[30], data[31], data[32], data[33],
+				  length );
+		}
 		dma_cache_maintenance(buf, length, 1);
 
 		stat = hardware_send_packet(buf, length);
@@ -499,7 +523,7 @@
 	while(boguscount--) {
 		status = get_frame((unsigned long)phys_nic_packet, 0);
 
-		if( status != 1 ) break;
+		if( status == 0 ) break;
 
 		/* Good packet... */
 
@@ -508,34 +532,63 @@
 		pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
 
 		lp->poll_time = bionet_min_poll_time;    /* fast poll */
-		if( pkt_len >= 60 && pkt_len <= 1514 ) {
-
+		if( pkt_len >= 60 && pkt_len <= 1520 ) {
+					/*	^^^^ war 1514  KHL */
 			/* Malloc up new buffer.
 			 */
-			struct sk_buff *skb = alloc_skb(pkt_len, GFP_ATOMIC);
+			struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
 			if (skb == NULL) {
 				printk("%s: Memory squeeze, dropping packet.\n",
 					dev->name);
 				lp->stats.rx_dropped++;
 				break;
 			}
-			skb->len = pkt_len;
+
 			skb->dev = dev;
+			skb_reserve( skb, 2 );		/* 16 Byte align  */
+			skb_put( skb, pkt_len );	/* make room */
 
 			/* 'skb->data' points to the start of sk_buff data area.
 			 */
 			memcpy(skb->data, nic_packet->buffer, pkt_len);
+			skb->protocol = eth_type_trans( skb, dev ); 
 			netif_rx(skb);
 			lp->stats.rx_packets++;
 			lp->stats.rx_bytes+=pkt_len;
-		}
-	}
 
 	/* If any worth-while packets have been received, dev_rint()
 	   has done a mark_bh(INET_BH) for us and will work on them
 	   when we get to the bottom-half routine.
 	 */
 
+ 			if (bionet_debug >1) {
+ 				u_char *data = nic_packet->buffer, *p;
+ 				int i;
+ 				
+ 				printk( "%s: RX pkt type 0x%4x from ", dev->name,
+ 					  ((u_short *)data)[6]);
+ 					 
+ 				
+ 				for( p = &data[6], i = 0; i < 6; i++ )
+ 					printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ 				printk(" to ");
+ 				for( p = data, i = 0; i < 6; i++ )
+ 					printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+ 
+ 				printk( "%s: ", dev->name );
+ 				printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ 				       " %02x%02x%02x%02x len %d\n",
+ 					  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ 					  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ 					  data[28], data[29], data[30], data[31], data[32], data[33],
+ 						  pkt_len );
+ 			}
+ 		}
+ 		else {
+ 			printk(" Packet has wrong length: %04d bytes\n", pkt_len);
+ 			lp->stats.rx_errors++;
+ 		}
+ 	}
 	stdma_release();
 	ENABLE_IRQ();
 	return;
diff -u --recursive --new-file v2.1.105/linux/drivers/net/cops.c linux/drivers/net/cops.c
--- v2.1.105/linux/drivers/net/cops.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/cops.c	Tue Jun  9 01:28:32 1998
@@ -24,13 +24,16 @@
  *					Hooks for cops_setup routine
  *					(not yet implemented).
  *	19971101	Jay Schulist	Fixes for multiple lt* devices.
- *	19980507	Steven Hirsch	Fixed the badly broken support
- *					for Tangent type cards. (COPS
- *					LT-1 and the like)
+ *	19980607	Steven Hirsch	Fixed the badly broken support
+ *					for Tangent type cards. Only
+ *                                      tested on Daystar LT200. Some
+ *                                      cleanup of formatting and program
+ *                                      logic.  Added emacs 'local-vars'
+ *                                      setup for Jay's brace style.
  */
 
 static const char *version =
-	"cops.c:v0.03 3/17/97 Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n";
+"cops.c:v0.04 6/7/98 Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n";
 /*
  *  Sources:
  *      COPS Localtalk SDK. This provides almost all of the information
@@ -133,6 +136,15 @@
  *	driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
  *		Farallon PhoneNET PC
  *		Original Apple LocalTalk PC card
+ * 
+ *      N.B.
+ *
+ *      The Daystar Digital LT200 boards do not support interrupt-driven
+ *      IO.  You must specify 'io=0xff' as a module parameter to invoke
+ *      polled mode.  I also believe that the port probing logic is quite
+ *      dangerous at best and certainly hopeless for a polled card.  Best to 
+ *      specify both. - Steve H.
+ *
  */
 
 /*
@@ -155,7 +167,7 @@
 
 static struct timer_list cops_timer;
 
-/* use 0 for production, 1 for verification, 2 for debug, 3 for very verbose debug */
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
 #ifndef COPS_DEBUG
 #define COPS_DEBUG 1 
 #endif
@@ -192,7 +204,8 @@
 static int  cops_send_packet (struct sk_buff *skb, struct device *dev);
 static void set_multicast_list (struct device *dev);
 static int  cops_hard_header (struct sk_buff *skb, struct device *dev,
-                unsigned short type, void *daddr, void *saddr, unsigned len);
+			      unsigned short type, void *daddr, void *saddr, 
+			      unsigned len);
 
 static int  cops_ioctl (struct device *dev, struct ifreq *rq, int cmd);
 static int  cops_close (struct device *dev);
@@ -202,9 +215,8 @@
 /*
  *      Check for a network adaptor of this type, and return '0' iff one exists.
  *      If dev->base_addr == 0, probe all likely locations.
- *      If dev->base_addr == 1, always return failure.
- *      If dev->base_addr == 2, allocate space for the device and return success
- *      (detachable devices only).
+ *      If dev->base_addr in [1..0x1ff], always return failure.
+ *        otherwise go with what we pass in.
  */
 __initfunc(int cops_probe(struct device *dev))
 {
@@ -219,6 +231,11 @@
 	else if(base_addr != 0)  /* Don't probe at all. */
                	return -ENXIO;
 	
+	/* FIXME  Does this really work for cards which generate irq?
+	 * It's definitely N.G. for polled Tangent. sh
+	 * Dayna cards don't autoprobe well at all, but if your card is
+	 * at IRQ 5 & IO 0x240 we find it every time. ;) JS
+	 */
         for(i=0; cops_portlist[i]; i++) {
 		int ioaddr = cops_portlist[i];
 		if(check_region(ioaddr, COPS_IO_EXTENT))
@@ -239,17 +256,12 @@
 {
         struct cops_local *lp;
 	static unsigned version_printed = 0;
-	int irqaddr = 0;
-	int irqval;
 
 	int board = board_type;
 	
         if(cops_debug && version_printed++ == 0)
 		printk("%s", version);
 
-	/* Fill in the 'dev' fields. */
-	dev->base_addr = ioaddr;
-
         /*
          * Since this board has jumpered interrupts, allocate the interrupt
          * vector now. There is no point in waiting since no other device
@@ -257,37 +269,47 @@
          * interrupts are typically not reported by the boards, and we must
          * used AutoIRQ to find them.
 	 */
-	 
-	if(dev->irq < 2 && irq)
-		dev->irq = irq;
-		
-        if(dev->irq < 2)
+	switch (dev->irq)
 	{
-		irqaddr = cops_irq(ioaddr, board);	/* COPS AutoIRQ routine */
-		if(irqaddr == 0)
-			return -EAGAIN;		/* No IRQ found on this port */
-		else
-			dev->irq = irqaddr;	
-	}	
-	else if(dev->irq == 2)
-		/* 
-		 * Fixup for users that don't know that IRQ 2 is really
+		case 0:
+			/* COPS AutoIRQ routine */
+			dev->irq = cops_irq(ioaddr, board);
+			if(!dev->irq)
+				return -EINVAL;	/* No IRQ found on this port */
+			break;
+
+		case 1:
+			return -EINVAL;
+			break;
+
+		/* Fixup for users that don't know that IRQ 2 is really
 		 * IRQ 9, or don't know which one to set.
 		 */
-		dev->irq = 9;
+		case 2:
+			dev->irq = 9;
+			break;
 
-	/* Snarf the interrupt now. */
-        irqval = request_irq(dev->irq, &cops_interrupt, 0, cardname, dev);
+		/* Polled operation requested. Although irq of zero passed as
+		 * a parameter tells the init routines to probe, we'll
+		 * overload it to denote polled operation at runtime.
+		 */
+		case 0xff:
+			dev->irq = 0;
+			break;
 
-	/* If its in use set it to 0 and disallow open() calls.. users can still
-	   ifconfig the irq one day */
+		default:
+			break;
+	}
 
-        if(irqval)
-		dev->irq = 0;	
+	/* Reserve any actual interrupt. */
+	if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
+		return -EINVAL;
 
-	dev->hard_start_xmit    = &cops_send_packet;
+	/* Grab the region so no one else tries to probe our ioports. */
+	request_region(ioaddr, COPS_IO_EXTENT, cardname);
+	dev->base_addr          = ioaddr;
 
-        /* Initialize the device structure. */
+	/* Initialize the private device structure. */
         dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
         if(dev->priv == NULL)
         	return -ENOMEM;
@@ -298,20 +320,10 @@
 	/* Copy local board variable to lp struct. */
 	lp->board               = board;
 
-	/* Tell the user where the card is and what mode were in. */
-	if(board==DAYNA)
-		printk("%s: %s found at %#3x, using IRQ %d, in Dayna mode.\n", 
-			dev->name, cardname, ioaddr, dev->irq);
-	if(board==TANGENT)
-		printk("%s: %s found at %#3x, using IRQ %d, in Tangent mode.\n", 
-			dev->name, cardname, ioaddr, dev->irq);
-
-	/* Grab the region so no one else tries to probe our ioports. */
-	request_region(ioaddr, COPS_IO_EXTENT, cardname);
-
 	/* Fill in the fields of the device structure with LocalTalk values. */
 	ltalk_setup(dev);
 
+	dev->hard_start_xmit    = &cops_send_packet;
 	dev->hard_header	= cops_hard_header;
         dev->get_stats          = cops_get_stats;
 	dev->open               = cops_open;
@@ -320,14 +332,17 @@
 	dev->set_multicast_list = &set_multicast_list;
         dev->mc_list            = NULL;
 
-	if(board==TANGENT)	/* Poll 20 times per second */
-	{
-		init_timer(&cops_timer);
-		cops_timer.function 	= cops_poll;
-		cops_timer.data 	= (unsigned long)dev;
-		cops_timer.expires 	= jiffies + 5;
-		add_timer(&cops_timer);
-	}
+	/* Tell the user where the card is and what mode we're in. */
+	if(board==DAYNA)
+		printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
+			dev->name, cardname, ioaddr, dev->irq);
+	if(board==TANGENT)
+		if(dev->irq)
+			printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
+				dev->name, cardname, ioaddr, dev->irq);
+	else
+		printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
+			dev->name, cardname, ioaddr);
 
         return 0;
 }
@@ -335,7 +350,7 @@
 __initfunc(static int cops_irq (int ioaddr, int board))
 {       /*
          * This does not use the IRQ to determine where the IRQ is. We just
-         * assume that when we get a correct status response that its the IRQ.
+         * assume that when we get a correct status response that it's the IRQ.
          * This really just verifies the IO port but since we only have access
          * to such a small number of IRQs (5, 4, 3) this is not bad.
          * This will probably not work for more than one card.
@@ -383,10 +398,27 @@
  */
 static int cops_open(struct device *dev)
 {
+    struct cops_local *lp = (struct cops_local *)dev->priv;
+
 	if(dev->irq==0)
 	{
-		printk(KERN_WARNING "%s: No irq line set.\n", dev->name);
-		return -EAGAIN;
+		/*
+		 * I don't know if the Dayna-style boards support polled 
+		 * operation.  For now, only allow it for Tangent.
+		 */
+		if(lp->board==TANGENT)	/* Poll 20 times per second */
+		{
+		    init_timer(&cops_timer);
+		    cops_timer.function = cops_poll;
+		    cops_timer.data 	= (unsigned long)dev;
+		    cops_timer.expires 	= jiffies + 5;
+		    add_timer(&cops_timer);
+		} 
+		else 
+		{
+			printk(KERN_WARNING "%s: No irq line set\n", dev->name);
+			return -EAGAIN;
+		}
 	}
 
 	cops_jumpstart(dev);	/* Start the card up. */
@@ -428,18 +460,12 @@
 	return 0;
 }
 
-static int tangent_wait_reset(int ioaddr)
+static void tangent_wait_reset(int ioaddr)
 {
-	long snapt=jiffies;
-
-	while(jiffies-snapt<5*HZ)
-	{
-		if((inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)==0)
-			break;
-		schedule();
-	}
+	int timeout=0;
 
-	return 0;
+	while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+		mdelay(1);   /* Wait 1 second */
 }
 
 /*
@@ -452,23 +478,11 @@
 
         if(lp->board==TANGENT)
         {
-                inb(ioaddr);			/* Clear request latch. */
-                outb(0,ioaddr);			/* Clear the TANG_TX_READY flop. */
+                inb(ioaddr);		/* Clear request latch. */
+                outb(0,ioaddr);		/* Clear the TANG_TX_READY flop. */
                 outb(0, ioaddr+TANG_RESET);	/* Reset the adapter. */
 
-                /* Can take 5 seconds max - youch! */
-                if(sleep)
-                {
-                        long snapt=jiffies;
-                        while(jiffies-snapt<5*HZ)
-                        {
-                                if(inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)
-                                        break;
-                                schedule();
-                        }
-                }
-                else
-                        tangent_wait_reset(ioaddr);
+		tangent_wait_reset(ioaddr);
                 outb(0, ioaddr+TANG_CLEAR_INT);
         }
         if(lp->board==DAYNA)
@@ -563,12 +577,13 @@
         }
 
 	if(cops_debug > 1)
-        	printk(KERN_DEBUG "%s: Uploaded firmware - %d bytes of %d bytes.\n", dev->name, i, ltf->length);
+		printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
+			dev->name, i, ltf->length);
 
-        if(lp->board==DAYNA)
-                outb(1, ioaddr+DAYNA_INT_CARD);         /* Tell Dayna to run the firmware code. */
-	else
-		inb(ioaddr);				/* Tell Tang to run the firmware code. */
+        if(lp->board==DAYNA) 	/* Tell Dayna to run the firmware code. */
+                outb(1, ioaddr+DAYNA_INT_CARD);
+	else			/* Tell Tang to run the firmware code. */
+		inb(ioaddr);
 
         if(lp->board==TANGENT)
         {
@@ -601,10 +616,10 @@
 			schedule();
                 }
 
-                outb(2, ioaddr);        	/* Output command packet length as 2. */
+                outb(2, ioaddr);       	/* Output command packet length as 2. */
                 outb(0, ioaddr);
-                outb(LAP_INIT, ioaddr);     	/* Send LAP_INIT command byte. */
-                outb(nodeid, ioaddr);       	/* Suggest node address. */
+                outb(LAP_INIT, ioaddr);	/* Send LAP_INIT command byte. */
+                outb(nodeid, ioaddr);  	/* Suggest node address. */
         }
 
 	if(lp->board == TANGENT)
@@ -612,19 +627,19 @@
                 /* Empty any pending adapter responses. */
                 while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
                 {
-			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear any interrupt. */
-                	cops_rx(dev);          		/* Kick out any packet waiting. */
+			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupt. */
+                	cops_rx(dev);          	/* Kick out packets waiting. */
 			schedule();
                 }
 
-		/* Not sure what Tangent does if random nodeid we picked is already used. */
+		/* Not sure what Tangent does if nodeid picked is used. */
                 if(nodeid == 0)	         		/* Seed. */
-                	nodeid = jiffies&0xFF;		/* Get a random try .*/
-                outb(2, ioaddr);        		/* Command length LSB. */
-                outb(0, ioaddr);       			/* Command length MSB. */
-                outb(LAP_INIT, ioaddr); 		/* Send LAP_INIT command byte. */
+                	nodeid = jiffies&0xFF;		/* Get a random try */
+                outb(2, ioaddr);        		/* Command length LSB */
+                outb(0, ioaddr);       			/* Command length MSB */
+                outb(LAP_INIT, ioaddr); 		/* Send LAP_INIT byte */
                 outb(nodeid, ioaddr); 		  	/* LAP address hint. */
-                outb(0xFF, ioaddr);     		/* Interrupt level to use (NONE). */
+                outb(0xFF, ioaddr);     		/* Int. level to use */
         }
 
 	lp->node_acquire=0;		/* Set nodeid holder to 0. */
@@ -646,7 +661,8 @@
 	}
 
 	if(cops_debug > 1)
-        	printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", dev->name, lp->node_acquire);
+		printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
+			dev->name, lp->node_acquire);
 
 	lp->nodeid=1;	/* Set got nodeid to 1. */
 
@@ -658,7 +674,6 @@
  */
 static void cops_poll(unsigned long ltdev)
 {
-	struct cops_local *lp;
 	int ioaddr, status;
 	int boguscount = 0;
 
@@ -670,12 +685,6 @@
 		return;	/* We've been downed */
 
 	ioaddr = dev->base_addr;
-
-	/* Clear any interrupt. */
-	outb(0, ioaddr + COPS_CLEAR_INT);
-	dev->interrupt = 0;
-
-	lp = (struct cops_local *)dev->priv;
 	do {
 		status=inb(ioaddr+TANG_CARD_STATUS);
 		if(status & TANG_RX_READY)
@@ -704,7 +713,8 @@
 
         if(dev == NULL)
         {
-                printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+                printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+			cardname, irq);
                 return;
         }
         dev->interrupt = 1;
@@ -787,7 +797,8 @@
         skb = dev_alloc_skb(pkt_len);
         if(skb == NULL)
         {
-                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+			dev->name);
                 lp->stats.rx_dropped++;
                 while(pkt_len--)        /* Discard packet */
                         inb(ioaddr);
@@ -800,14 +811,15 @@
         insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
 
         if(lp->board==DAYNA)
-                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card. */
+                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
 
         sti();  /* Restore interrupts. */
 
         /* Check for bad response length */
         if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
         {
-                printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len);
+		printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", 
+			dev->name, pkt_len);
                 lp->stats.tx_errors++;
                 kfree_skb(skb);
                 return;
@@ -815,8 +827,8 @@
 
         /* Set nodeid and then get out. */
         if(rsp_type == LAP_INIT_RSP)
-        {
-                lp->node_acquire = skb->data[0];        /* Nodeid taken from received packet. */
+        {	/* Nodeid taken from received packet. */
+                lp->node_acquire = skb->data[0];
                 kfree_skb(skb);
                 return;
         }
@@ -878,7 +890,8 @@
          * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	 */
         if(test_and_set_bit(0, (void*) &dev->tbusy) != 0)
-                printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+                printk(KERN_WARNING "%s: Transmitter access conflict.\n",
+			dev->name);
         else
         {
 		cli();	/* Disable interrupts. */
@@ -902,7 +915,7 @@
 
                 outsb(ioaddr, skb->data, skb->len);	/* Send out the data. */
 
-                if(lp->board==DAYNA)	/* The Dayna requires you kick the card. */
+                if(lp->board==DAYNA)	/* Dayna requires you kick the card */
                         outb(1, ioaddr+DAYNA_INT_CARD);
 
 		sti();	/* Restore interrupts. */
@@ -926,7 +939,7 @@
 static void set_multicast_list(struct device *dev)
 {
         if(cops_debug >= 3)
-                printk("%s: set_mulicast_list executed. NeatO.\n", dev->name);
+		printk("%s: set_multicast_list executed\n", dev->name);
 }
 
 /*
@@ -934,7 +947,8 @@
  */
  
 static int cops_hard_header(struct sk_buff *skb, struct device *dev,
-         unsigned short type, void *daddr, void *saddr, unsigned len)
+			    unsigned short type, void *daddr, void *saddr, 
+			    unsigned len)
 {
         if(cops_debug >= 3)
                 printk("%s: cops_hard_header executed. Wow!\n", dev->name);
@@ -983,6 +997,13 @@
  
 static int cops_close(struct device *dev)
 {
+	struct cops_local *lp = (struct cops_local *)dev->priv;
+
+	/* If we were running polled, yank the timer.
+	 */
+	if(lp->board==TANGENT && dev->irq==0)
+		del_timer(&cops_timer);
+
         dev->tbusy = 1;
         dev->start = 0;
 
@@ -1024,7 +1045,8 @@
         int result, err;
 
         if(io == 0)
-                printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", cardname);
+		printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
+			cardname);
 
         /* Copy the parameters from insmod into the device structure. */
         cops0_dev.base_addr = io;
@@ -1046,7 +1068,16 @@
 	unregister_netdev(&cops0_dev);
 	if(cops0_dev.priv)
                 kfree_s(cops0_dev.priv, sizeof(struct cops_local));
-        free_irq(cops0_dev.irq, &cops0_dev);
+	if(cops0_dev.irq)
+		free_irq(cops0_dev.irq, &cops0_dev);
         release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
 }
 #endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
+ *  c-basic-offset: 4
+ *  c-file-offsets: ((substatement-open . 0))
+ * End:
+ */
diff -u --recursive --new-file v2.1.105/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.1.105/linux/drivers/net/hamradio/dmascc.c	Wed May 20 19:10:39 1998
+++ linux/drivers/net/hamradio/dmascc.c	Sat Jun 13 10:26:27 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $
+ * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $
  *
  * Driver for high-speed SCC boards (those with DMA support)
  * Copyright (C) 1997 Klaus Kudielka
diff -u --recursive --new-file v2.1.105/linux/drivers/net/hplance.c linux/drivers/net/hplance.c
--- v2.1.105/linux/drivers/net/hplance.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hplance.c	Sat Jun 13 13:28:34 1998
@@ -0,0 +1,249 @@
+/* hplance.c  : the  Linux/hp300/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "hplance.h"
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h"                                 /* use generic LANCE code */
+
+/* Our private data structure */
+struct hplance_private {
+  struct lance_private lance;
+  unsigned int scode;
+  void *base;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions. 
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int hplance_probe(struct device *dev);
+static int hplance_init(struct device *dev, int scode);
+static int hplance_open(struct device *dev);
+static int hplance_close(struct device *dev);
+static void hplance_writerap(struct hplance_private *lp, unsigned short value);
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
+static unsigned short hplance_readrdp(struct hplance_private *lp);
+
+#ifdef MODULE
+static struct hplance_private *root_hplance_dev = NULL;
+#endif
+
+/* Find all the HP Lance boards and initialise them... */
+__initfunc(int hplance_probe(struct device *dev))
+{
+        int cards = 0, called = 0;
+
+        if (!MACH_IS_HP300 || called)
+                return(ENODEV);
+        called++;
+        
+        /* Isn't DIO nice? */
+        for(;;)
+        {
+                int v, scode = dio_find(DIO_ID_LAN);
+                                
+                if (!scode)
+                        break;
+                
+                if(cards)
+                        dev = NULL;      /* don't trash previous device, make a new one */
+                cards++;
+                
+                v = hplance_init(dev, scode);
+                if (v)                            /* error, abort immediately */
+                        return v;
+        }
+        /* OK, return success, or ENODEV if we didn't find any cards */
+        if (!cards)
+                return ENODEV;
+        return 0;
+}
+
+/* Initialise a single lance board at the given select code */
+__initfunc (static int hplance_init(struct device *dev, int scode))
+{
+        /* const char *name = dio_scodetoname(scode); */
+        static const char name[] = "HP LANCE";
+        void *va = dio_scodetoviraddr(scode);
+        struct hplance_private *lp;
+        int i;
+        
+        if (dev == NULL)
+                dev = init_etherdev(0, sizeof(struct hplance_private));
+        else
+        {
+                dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL);
+                if (dev->priv == NULL)
+                        return -ENOMEM;
+                memset(dev->priv, 0, sizeof(struct hplance_private));
+        }
+        printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
+
+        /* reset the board */
+        writeb(0xff,va+DIO_IDOFF);
+        udelay(100);                              /* ariba! ariba! udelay! udelay! */
+
+        /* Fill the dev fields */
+        dev->base_addr = (unsigned long)va;
+        dev->open = &hplance_open;
+        dev->stop = &hplance_close;
+        dev->hard_start_xmit = &lance_start_xmit;
+        dev->get_stats = &lance_get_stats;
+        dev->set_multicast_list = &lance_set_multicast;
+        dev->dma = 0;
+        
+        for (i=0; i<6; i++)
+        {
+                /* The NVRAM holds our ethernet address, one nibble per byte,
+                 * at bytes NVRAMOFF+1,3,5,7,9...
+                 */
+                dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+                        | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+                printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+        }
+        
+        lp = (struct hplance_private *)dev->priv;
+        lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
+        lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
+        lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
+        lp->lance.lance_init_block = 0;                 /* LANCE addr of same RAM */
+        lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
+        lp->lance.irq = dio_scodetoipl(scode);
+        lp->lance.writerap = hplance_writerap;
+        lp->lance.writerdp = hplance_writerdp;
+        lp->lance.readrdp = hplance_readrdp;
+        lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+        lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+        lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+        lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+        lp->scode = scode;
+	lp->base = va;
+        ether_setup(dev);
+	printk(", irq %d\n", lp->lance.irq);
+
+#ifdef MODULE
+        dev->ifindex = dev_new_index();
+        lp->next_module = root_hplance_dev;
+        root_hplance_dev = lp;
+#endif /* MODULE */
+
+        dio_config_board(scode);                  /* tell bus scanning code this one's taken */
+        return 0;
+}
+
+/* This is disgusting. We have to check the DIO status register for ack every
+ * time we read or write the LANCE registers.
+ */
+static void hplance_writerap(struct hplance_private *lp, unsigned short value)
+{
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                lp->lance.ll->rap = value;
+        } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
+{
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                lp->lance.ll->rdp = value;
+        } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static unsigned short hplance_readrdp(struct hplance_private *lp)
+{
+        unsigned short val;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                val = lp->lance.ll->rdp;
+        } while ((hpregs->status & LE_ACK) == 0);
+        return val;
+}
+
+static int hplance_open(struct device *dev)
+{
+        int status;
+        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        
+        status = lance_open(dev);                 /* call generic lance open code */
+        if (status)
+                return status;
+        /* enable interrupts at board level. */
+        writeb(LE_IE, &(hpregs->status));
+
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int hplance_close(struct device *dev)
+{
+        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        writeb(0,&(hpregs->status));              /* disable interrupts at boardlevel */
+        lance_close(dev);
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+        root_lance_dev = NULL;
+        return hplance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+        /* Walk the chain of devices, unregistering them */
+        struct hplance_private *lp;
+        while (root_hplance_dev) {
+                lp = root_hplance_dev->next_module;
+                dio_unconfig_board(lp->scode);
+                unregister_netdev(root_lance_dev->dev);
+                kfree(root_lance_dev->dev);
+                root_lance_dev = lp;
+        }
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.105/linux/drivers/net/hplance.h linux/drivers/net/hplance.h
--- v2.1.105/linux/drivers/net/hplance.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hplance.h	Sat Jun 13 13:28:34 1998
@@ -0,0 +1,31 @@
+/* Random defines and structures for the HP Lance driver.
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ */
+
+/* Registers */
+struct hplance_reg
+{
+        u_char pad0;
+        volatile u_char id;                       /* DIO register: ID byte */
+        u_char pad1;
+        volatile u_char status;                   /* DIO register: interrupt enable */
+};
+
+/* Control and status bits for the hplance->status register */
+#define LE_IE 0x80                                /* interrupt enable */
+#define LE_IR 0x40                                /* interrupt requested */
+#define LE_LOCK 0x08                              /* lock status register */
+#define LE_ACK 0x04                               /* ack of lock */
+#define LE_JAB 0x02                               /* loss of tx clock (???) */
+/* We can also extract the IPL from the status register with the standard
+ * DIO_IPL(hplance) macro, or using dio_scodetoipl()
+ */
+
+/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
+ * memory and NVRAM:
+ */
+#define HPLANCE_IDOFF 0                           /* board baseaddr, struct hplance_reg */
+#define HPLANCE_REGOFF 0x4000                     /* struct lance_regs */
+#define HPLANCE_MEMOFF 0x8000                     /* struct lance_init_block */
+#define HPLANCE_NVRAMOFF 0xC008                   /* etheraddress as one *nibble* per byte */
diff -u --recursive --new-file v2.1.105/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.1.105/linux/drivers/net/loopback.c	Thu Feb 12 20:56:08 1998
+++ linux/drivers/net/loopback.c	Thu Jun 11 22:52:33 1998
@@ -52,7 +52,7 @@
 #include <linux/if_ether.h>	/* For the statistics structure. */
 #include <linux/if_arp.h>	/* For ARPHRD_ETHER */
 
-#define LOOPBACK_MTU (PAGE_SIZE*7/8)
+#define LOOPBACK_MTU	(PAGE_SIZE - 172)
 
 /*
  * The higher levels take care of making this non-reentrant (it's
diff -u --recursive --new-file v2.1.105/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.105/linux/drivers/net/net_init.c	Fri May  8 23:14:48 1998
+++ linux/drivers/net/net_init.c	Tue Jun  9 01:21:49 1998
@@ -390,7 +390,7 @@
 	for (i = 0; i < MAX_ETH_CARDS; ++i)	{
 		if (ethdev_index[i] == NULL) {
 			sprintf(dev->name, "eth%d", i);
-			printk("loading device '%s'...\n", dev->name);
+/*			printk("loading device '%s'...\n", dev->name);*/
 			ethdev_index[i] = dev;
 			return i;
 		}
diff -u --recursive --new-file v2.1.105/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.105/linux/drivers/net/ppp.c	Thu May  7 22:51:50 1998
+++ linux/drivers/net/ppp.c	Sat Jun 13 12:30:45 1998
@@ -8,7 +8,9 @@
  *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
  *
- *  ==FILEVERSION 980501==
+ *  Machine hang caused by NULLing a live wait queue fix. <Alan.Cox@linux.org>
+ *
+ *  ==FILEVERSION 980608==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -206,6 +208,7 @@
 	CHECK_PPP_MAGIC(ppp); \
 	if (!ppp->inuse) { \
 		printk (ppp_warning, __LINE__); \
+		return; \
 	} \
 } while (0)
 
@@ -415,8 +418,6 @@
 	ppp->ubuf	= NULL;
 	ppp->cbuf	= NULL;
 	ppp->slcomp	= NULL;
-	ppp->read_wait	= NULL;
-	ppp->write_wait = NULL;
 	ppp->last_xmit	= jiffies - flag_time;
 	ppp->last_recv  = jiffies;
 
@@ -1706,7 +1707,6 @@
 {
 	struct ppp *ppp = tty2ppp (tty);
 	__u8 c;
-	int error;
 	ssize_t len, ret;
 
 #define GETC(c)						\
@@ -1720,41 +1720,40 @@
  */
 	if (!ppp)
 		return -EIO;
-
-	/* if (ppp->magic != PPP_MAGIC)
-		return -EIO; */
-
 	CHECK_PPP (-ENXIO);
 
 /*
  * Before we attempt to write the frame to the user, ensure that the
  * user has access to the pages for the total buffer length.
  */
-	error = verify_area (VERIFY_WRITE, buf, nr);
-	if (error != 0)
-		return (error);
+	if (verify_area (VERIFY_WRITE, buf, nr))
+		return -EFAULT;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+	MOD_INC_USE_COUNT;
 
 /*
  * Acquire the read lock.
  */
 	for (;;) {
+		ret = 0;
 		ppp = tty2ppp (tty);
 		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
 		    || tty != ppp->tty)
-			return 0;
+			goto done;
 
 		if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
-#if 0
-			if (ppp->flags & SC_DEBUG)
-				printk (KERN_DEBUG
-				     "ppp_tty_read: sleeping(ubuf)\n");
-#endif
 			current->timeout = 0;
 			current->state	 = TASK_INTERRUPTIBLE;
-			schedule ();
+			schedule();
 
+			ret = -EINTR;
 			if (signal_pending(current))
-				return -EINTR;
+				goto done;
 			continue;
 		}
 
@@ -1777,17 +1776,14 @@
  */
 		/* no data */
 		clear_bit (0, &ppp->ubuf->locked);
+		ret = -EAGAIN;
 		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
+			goto done;
 		current->timeout = 0;
-#if 0
-		if (ppp->flags & SC_DEBUG)
-			printk (KERN_DEBUG
-				"ppp_tty_read: sleeping(read_wait)\n");
-#endif
 		interruptible_sleep_on (&ppp->read_wait);
+		ret = -EINTR;
 		if (signal_pending(current))
-			return -EINTR;
+			goto done;
 	}
 
 /*
@@ -1802,7 +1798,7 @@
 				"ppp: read of %lu bytes too small for %ld "
 				"frame\n", (unsigned long) nr, (long) len + 2);
 		ppp->stats.ppp_ierrors++;
-		error = -EOVERFLOW;
+		ret = -EOVERFLOW;
 		goto out;
 	}
 
@@ -1810,35 +1806,32 @@
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
-	error = put_user((u_char) PPP_ALLSTATIONS, buf);
-	if (error)
-		goto out;
-	++buf;
-	error = put_user((u_char) PPP_UI, buf);
-	if (error)
+	ret = -EFAULT;
+	if (put_user((u_char) PPP_ALLSTATIONS, buf)
+	    || put_user((u_char) PPP_UI, buf+1))
 		goto out;
-	++buf;
+	buf += 2;
 
 /*
  * Copy the received data from the buffer to the caller's area.
  */
-	ret = len + 2; 	/* Account for ADDRESS and CONTROL bytes */
+	nr = len + 2; 	/* Account for ADDRESS and CONTROL bytes */
 	while (len-- > 0) {
 		GETC (c);
-		error = put_user(c, buf);
-		if (error)
+		if (put_user(c, buf))
 			goto out;
 		++buf;
 	}
-
-	clear_bit (0, &ppp->ubuf->locked);
-	return ret;
+	ret = nr;
 
 out:
-	ppp->ubuf->tail += len;
-	ppp->ubuf->tail &= ppp->ubuf->size;
-	clear_bit (0, &ppp->ubuf->locked);
-	return error;
+	if (len > 0)
+		ppp->ubuf->tail = (ppp->ubuf->tail + len) & ppp->ubuf->size;
+	clear_bit(0, &ppp->ubuf->locked);
+
+done:
+	MOD_DEC_USE_COUNT;
+	return ret;
 #undef GETC
 }
 
@@ -2100,6 +2093,14 @@
 	error = -EFAULT;
 	if (copy_from_user(new_data, data, count))
 		goto out_free;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+	MOD_INC_USE_COUNT;
+
 /*
  * Lock this PPP unit so we will be the only writer,
  * sleeping if necessary.
@@ -2131,7 +2132,7 @@
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&ppp->write_wait, &wait);
 	if (error)
-		goto out_free;
+		goto out_free_dec;
 
 /*
  * Change the LQR frame
@@ -2154,6 +2155,8 @@
 	}
 	error = count;
 
+out_free_dec:
+	MOD_DEC_USE_COUNT;
 out_free:
 	kfree (new_data);
 out:
@@ -2619,6 +2622,7 @@
 			dev->name);
 
 	CHECK_PPP (-ENXIO);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -2631,6 +2635,7 @@
 {
 	struct ppp *ppp = dev2ppp (dev);
 
+	MOD_DEC_USE_COUNT;
 	if (ppp2tty (ppp) == NULL) {
 		return -ENXIO;
 	}
@@ -3094,6 +3099,8 @@
 		ppp_last->next = ppp;
 	ppp_last = ppp;
 	ppp->next = 0;
+	ppp->read_wait	= NULL;
+	ppp->write_wait = NULL;
 
 	dev = ppp2dev(ppp);
 	dev->next      = NULL;
diff -u --recursive --new-file v2.1.105/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.105/linux/drivers/net/wavelan.c	Sun Jun  7 11:16:33 1998
+++ linux/drivers/net/wavelan.c	Sat Jun 13 12:01:39 1998
@@ -1,10 +1,10 @@
 /*
- *	Wavelan ISA driver
+ *	WaveLAN ISA driver
  *
  *		Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
- * Original copyrigth follow (see also end of this file).
+ * Original copyright follows (also see the end of this file).
  * See wavelan.p.h for details.
  */
 
@@ -19,7 +19,7 @@
 /************************* MISC SUBROUTINES **************************/
 /*
  * Subroutines which won't fit in one of the following category
- * (wavelan modem or i82586)
+ * (WaveLAN modem or i82586)
  */
 
 /*------------------------------------------------------------------*/
@@ -95,14 +95,14 @@
 #undef	SC
 
   return((char *) NULL);
-} /* wv_structuct_check */
+} /* wv_struct_check */
 #endif	/* STRUCT_CHECK */
 
 /********************* HOST ADAPTER SUBROUTINES *********************/
 /*
- * Usefull subroutines to manage the wavelan ISA interface
+ * Useful subroutines to manage the WaveLAN ISA interface
  *
- * One major difference with the Pcmcia hardware (exept the port mapping)
+ * One major difference with the PCMCIA hardware (except the port mapping)
  * is that we have to keep the state of the Host Control Register
  * because of the interrupt enable & bus size flags.
  */
@@ -166,7 +166,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
  */
 static inline void
 wv_16_off(u_long	ioaddr,
@@ -178,7 +178,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
  */
 static inline void
 wv_16_on(u_long		ioaddr,
@@ -190,7 +190,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Disable interrupts on the wavelan hardware
+ * Disable interrupts on the WaveLAN hardware.
  */
 static inline void
 wv_ints_off(device *	dev)
@@ -209,7 +209,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Enable interrupts on the wavelan hardware
+ * Enable interrupts on the WaveLAN hardware.
  */
 static inline void
 wv_ints_on(device *	dev)
@@ -228,7 +228,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the WaveLAN
  */
 
 /*------------------------------------------------------------------*/
@@ -259,7 +259,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Write the Paramter Storage Area to the WaveLAN card's memory
+ * Write the Parameter Storage Area to the WaveLAN card's memory.
  */
 static void
 psa_write(u_long	ioaddr,
@@ -294,10 +294,10 @@
 /*------------------------------------------------------------------*/
 /*
  * Calculate the PSA CRC (not tested yet)
- * As the Wavelan drivers don't use the CRC, I won't use it either...
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * As the WaveLAN drivers don't use the CRC, I won't use it either.
+ * Thanks to Nico Valster <NVALSTER@wcnd.nl.lucent.com> for the code
  * NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
+ * returned value should be zero. (i.e. a correct checksum in the PSA).
  */
 static u_short
 psa_crc(u_short *	psa,	/* The PSA */
@@ -344,7 +344,7 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to write bytes to the Modem Management Controller.
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
  */
 static inline void
 mmc_write(u_long	ioaddr,
@@ -361,8 +361,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Read 1 byte from the MMC.
- * Optimised version for 1 byte, avoid using memory...
+ * Read a byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory.
  */
 static inline u_char
 mmc_in(u_long	ioaddr,
@@ -383,7 +383,7 @@
  * The implementation is complicated by a lack of address lines,
  * which prevents decoding of the low-order bit.
  * (code has just been moved in the above function)
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
  */
 static inline void
 mmc_read(u_long		ioaddr,
@@ -400,7 +400,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Get the type of encryption available...
+ * Get the type of encryption available.
  */
 static inline int
 mmc_encr(u_long		ioaddr)	/* i/o port of the card */
@@ -416,8 +416,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Wait for the frequency EEprom to complete a command...
- * I hope this one will be optimally inlined...
+ * Wait for the frequency EEPROM to complete a command.
+ * I hope this one will be optimally inlined.
  */
 static inline void
 fee_wait(u_long		ioaddr,	/* i/o port of the card */
@@ -433,7 +433,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Read bytes from the Frequency EEprom (frequency select cards).
+ * Read bytes from the Frequency EEPROM (frequency select cards).
  */
 static void
 fee_read(u_long		ioaddr,	/* i/o port of the card */
@@ -452,21 +452,21 @@
       /* Write the read command */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
 
-      /* Wait until EEprom is ready (should be quick !) */
+      /* Wait until EEPROM is ready (should be quick). */
       fee_wait(ioaddr, 10, 100);
 
-      /* Read the value */
+      /* Read the value. */
       *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
 	      mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
     }
 }
 
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT	/* if the wireless extension exists in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
- * Write bytes from the Frequency EEprom (frequency select cards).
- * This is a bit complicated, because the frequency eeprom has to
+ * Write bytes from the Frequency EEPROM (frequency select cards).
+ * This is a bit complicated, because the frequency EEPROM has to
  * be unprotected and the write enabled.
  * Jean II
  */
@@ -476,7 +476,7 @@
 	  u_short *	b,	/* data buffer */
 	  int		n)	/* number of registers */
 {
-  b += n;		/* Position at the end of the area */
+  b += n;		/* Position at the end of the area. */
 
 #ifdef EEPROM_IS_PROTECTED	/* disabled */
 #ifdef DOESNT_SEEM_TO_WORK	/* disabled */
@@ -485,19 +485,19 @@
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Read the protected register */
+  /* Read the protected register. */
   printk("Protected 2 : %02X-%02X\n",
 	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
 	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
 #endif	/* DOESNT_SEEM_TO_WORK */
 
-  /* Enable protected register */
+  /* Enable protected register. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Unprotect area */
+  /* Unprotect area. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 #ifdef DOESNT_SEEM_TO_WORK	/* disabled */
@@ -508,38 +508,38 @@
   fee_wait(ioaddr, 10, 100);
 #endif	/* EEPROM_IS_PROTECTED */
 
-  /* Write enable */
+  /* Write enable. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Write the EEprom address */
+  /* Write the EEPROM address. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
 
   /* Loop on all buffer */
   while(n-- > 0)
     {
-      /* Write the value */
+      /* Write the value. */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
 
-      /* Write the write command */
+      /* Write the write command. */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
 
-      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+      /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
       mdelay(10);
       fee_wait(ioaddr, 10, 100);
     }
 
-  /* Write disable */
+  /* Write disable. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
 
   fee_wait(ioaddr, 10, 100);
 
 #ifdef EEPROM_IS_PROTECTED	/* disabled */
-  /* Reprotect EEprom */
+  /* Reprotect EEPROM. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 
@@ -550,13 +550,13 @@
 
 /************************ I82586 SUBROUTINES *************************/
 /*
- * Usefull subroutines to manage the Ethernet controler
+ * Useful subroutines to manage the Ethernet controller
  */
 
 /*------------------------------------------------------------------*/
 /*
  * Read bytes from the on-board RAM.
- * Why inlining this function make it fail ???
+ * Why does inlining this function make it fail?
  */
 static /*inline*/ void
 obram_read(u_long	ioaddr,
@@ -584,7 +584,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Acknowledge the reading of the status issued by the i82586
+ * Acknowledge the reading of the status issued by the i82586.
  */
 static void
 wv_ack(device *		dev)
@@ -626,7 +626,7 @@
 /*------------------------------------------------------------------*/
 /*
  * Set channel attention bit and busy wait until command has
- * completed, then acknowledge the command completion.
+ * completed, then acknowledge completion of the command.
  */
 static inline int
 wv_synchronous_cmd(device *	dev,
@@ -675,7 +675,7 @@
 /*------------------------------------------------------------------*/
 /*
  * Configuration commands completion interrupt.
- * Check if done, and if ok...
+ * Check if done, and if OK.
  */
 static inline int
 wv_config_complete(device *	dev,
@@ -693,7 +693,7 @@
   mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
     + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
 
-  /* Read the status of the last command (set mc list) */
+  /* Read the status of the last command (set mc list). */
   obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
 
   /* If not completed -> exit */
@@ -717,7 +717,7 @@
 	printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
 	       dev->name, str, status);
 
-      /* Check config command */
+      /* Check config command. */
       cfg_addr = ias_addr - sizeof(ac_cfg_t);
       obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
       if(status & AC_SFLD_OK != 0)
@@ -776,7 +776,7 @@
 	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
 */
 
-      /* Was it the last one ? */
+      /* Was it the last one? */
       if(lp->tx_n_in_use <= 0)
 	lp->tx_first_in_use = I82586NULL;
       else
@@ -882,12 +882,12 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Reconfigure the i82586, or at least ask for it...
- * Because wv_82586_config use a transmission buffer, we must do it
+ * Reconfigure the i82586, or at least ask for it.
+ * Because wv_82586_config uses a transmission buffer, we must do it
  * when we are sure that there is one left, so we do it now
  * or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option...), so you may experience
- * some delay sometime...
+ * wavelan_interrupt is not an option), so you may experience
+ * delays sometimes.
  */
 static inline void
 wv_82586_reconfig(device *	dev)
@@ -909,8 +909,8 @@
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
- * This routines are used in the code to show debug informations.
- * Most of the time, it dump the content of hardware structures...
+ * This routine is used in the code to show information for debugging.
+ * Most of the time, it dumps the contents of hardware structures.
  */
 
 #ifdef DEBUG_PSA_SHOW
@@ -921,7 +921,7 @@
 static void
 wv_psa_show(psa_t *	p)
 {
-  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	 p->psa_io_base_addr_1,
 	 p->psa_io_base_addr_2,
@@ -1006,7 +1006,7 @@
 /*------------------------------------------------------------------*/
 /*
  * Print the formatted status of the Modem Management Controller.
- * This function need to be completed...
+ * This function needs to be completed.
  */
 static void
 wv_mmc_show(device *	dev)
@@ -1028,12 +1028,12 @@
   mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
 
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
   /* Don't forget to update statistics */
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
-  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
 	 m.mmr_unused0[0],
@@ -1045,7 +1045,7 @@
 	 m.mmr_unused0[6],
 	 m.mmr_unused0[7]);
 #endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+  printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
 	 m.mmr_des_avail, m.mmr_des_status);
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
@@ -1093,7 +1093,7 @@
 #ifdef DEBUG_I82586_SHOW
 /*------------------------------------------------------------------*/
 /*
- * Print the last block of the i82586 memory
+ * Print the last block of the i82586 memory.
  */
 static void
 wv_scb_show(u_long	ioaddr)
@@ -1102,7 +1102,7 @@
 
   obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));   
 
-  printk(KERN_DEBUG "##### wavelan system control block: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
 
   printk(KERN_DEBUG "status: ");
   printk("stat 0x%x[%s%s%s%s] ",
@@ -1163,7 +1163,7 @@
 {
   /* net_local *lp = (net_local *) dev->priv; */
 
-  printk(KERN_DEBUG "##### wavelan i82586 receiver unit status: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
   printk(KERN_DEBUG "ru:");
   /*
    * Not implemented yet...
@@ -1173,7 +1173,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Display info about one control block of the i82586 memory
+ * Display info about one control block of the i82586 memory.
  */
 static void
 wv_cu_show_one(device *		dev,
@@ -1206,7 +1206,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Print status of the command unit of the i82586
+ * Print status of the command unit of the i82586.
  */
 static void
 wv_cu_show(device *	dev)
@@ -1215,7 +1215,7 @@
   unsigned int	i;
   u_short	p;
 
-  printk(KERN_DEBUG "##### wavelan i82586 command unit status: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
 
   printk(KERN_DEBUG);
   for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
@@ -1310,8 +1310,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This is the information which is displayed by the driver at startup
- * There  is a lot of flag to configure it at your will...
+ * This is the information which is displayed by the driver at startup.
+ * There are lots of flags for configuring it to your liking.
  */
 static inline void
 wv_init_info(device *	dev)
@@ -1341,7 +1341,7 @@
     printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
   printk(", IRQ %d", dev->irq);
 
-  /* Print current network id */
+  /* Print current network ID. */
   if(psa.psa_nwid_select)
     printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
   else
@@ -1353,14 +1353,14 @@
     {
       unsigned short	freq;
 
-      /* Ask the EEprom to read the frequency from the first area */
+      /* Ask the EEPROM to read the frequency from the first area */
       fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
 	       &freq, 1);
 
       /* Print frequency */
       printk(", 2.00, %ld", (freq >> 6) + 2400L);
 
-      /* Hack !!! */
+      /* Hack! */
       if(freq & 0x20)
 	printk(".5");
     }
@@ -1381,7 +1381,7 @@
 	  printk("MCIA");
 	  break;
 	default:
-	  printk("???");
+	  printk("?");
 	}
       printk(", ");
       switch (psa.psa_subband)
@@ -1402,7 +1402,7 @@
 	  printk("2430.5");
 	  break;
 	default:
-	  printk("???");
+	  printk("?");
 	}
     }
 
@@ -1417,7 +1417,7 @@
 
 /********************* IOCTL, STATS & RECONFIG *********************/
 /*
- * We found here routines that are called by Linux on differents
+ * We found here routines that are called by Linux on different
  * occasions after the configuration and not for transmitting data
  * These may be called when the user use ifconfig, /proc/net/dev
  * or wireless extensions
@@ -1425,7 +1425,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Get the current ethernet statistics. This may be called with the
+ * Get the current Ethernet statistics. This may be called with the
  * card open or closed.
  * Used when the user read /proc/net/dev
  */
@@ -1461,9 +1461,9 @@
 	 dev->name, dev->flags, dev->mc_count);
 #endif
 
-  /* If we ask for promiscuous mode,
-   * or all multicast addresses (we don't have that !)
-   * or too much multicast addresses for the hardware filter */
+  /* Are we asking for promiscuous mode,
+   * or all multicast addresses (we don't have that!)
+   * or too many multicast addresses for the hardware filter? */
   if((dev->flags & IFF_PROMISC) ||
      (dev->flags & IFF_ALLMULTI) ||
      (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
@@ -1478,12 +1478,12 @@
 
 	  wv_82586_reconfig(dev);
 
-	  /* Tell the kernel that we are doing a really bad job... */
+	  /* Tell the kernel that we are doing a really bad job. */
 	  dev->flags |= IFF_PROMISC;
 	}
     }
   else
-    /* If there is some multicast addresses to send */
+    /* Are there multicast addresses to send? */
     if(dev->mc_list != (struct dev_mc_list *) NULL)
       {
 	/*
@@ -1522,7 +1522,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This function doesn't exist...
+ * This function doesn't exist.
  */
 static int
 wavelan_set_mac_address(device *	dev,
@@ -1530,16 +1530,16 @@
 {
   struct sockaddr *	mac = addr;
 
-  /* Copy the address */
+  /* Copy the address. */
   memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
 
-  /* Reconfig the beast */
+  /* Reconfigure the beast. */
   wv_82586_reconfig(dev);
 
   return 0;
 }
 
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
@@ -1558,10 +1558,10 @@
 #endif
 
   /* Setting by frequency */
-  /* Theoritically, you may set any frequency between
+  /* Theoretically, you may set any frequency between
    * the two limits with a 0.5 MHz precision. In practice,
    * I don't want you to have trouble with local
-   * regulations... */
+   * regulations. */
   if((frequency->e == 1) &&
      (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
     {
@@ -1569,29 +1569,29 @@
     }
 
   /* Setting by channel (same as wfreqsel) */
-  /* Warning : each channel is 22MHz wide, so some of the channels
-   * will interfere... */
+  /* Warning: each channel is 22 MHz wide, so some of the channels
+   * will interfere. */
   if((frequency->e == 0) &&
      (frequency->m >= 0) && (frequency->m < BAND_NUM))
     {
-      /* frequency in 1/4 of MHz (as read in the offset register) */
+      /* frequency in units of 250 kHz (as read in the offset register) */
       short	bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 };
 
-      /* Get frequency offset */
+      /* Get frequency offset. */
       freq = bands[frequency->m] >> 1;
     }
 
-  /* Verify if the frequency is allowed */
+  /* Verify that the frequency is allowed. */
   if(freq != 0L)
     {
       u_short	table[10];	/* Authorized frequency table */
 
-      /* Read the frequency table */
+      /* Read the frequency table. */
       fee_read(ioaddr, 0x71 /* frequency table */,
 	       table, 10);
 
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Frequency table :");
+      printk(KERN_DEBUG "Frequency table: ");
       for(i = 0; i < 10; i++)
 	{
 	  printk(" %04X",
@@ -1600,7 +1600,7 @@
       printk("\n");
 #endif
 
-      /* Look in the table if the frequency is allowed */
+      /* Look in the table to see whether the frequency is allowed. */
       if(!(table[9 - ((freq - 24) / 16)] &
 	   (1 << ((freq - 24) % 16))))
 	return -EINVAL;		/* not allowed */
@@ -1608,7 +1608,7 @@
   else
     return -EINVAL;
 
-  /* If we get a usable frequency */
+  /* if we get a usable frequency */
   if(freq != 0L)
     {
       unsigned short	area[16];
@@ -1616,7 +1616,7 @@
       unsigned short	area_verify[16];
       unsigned short	dac_verify[2];
       /* Corresponding gain (in the power adjust value table)
-       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+       * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
        * & WCIN062D.DOC, page 6.2.9 */
       unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
       int		power_band = 0;		/* Selected band */
@@ -1628,15 +1628,15 @@
 	    (power_limit[++power_band] != 0))
 	;
 
-      /* Read the first area */
+      /* Read the first area. */
       fee_read(ioaddr, 0x00,
 	       area, 16);
 
-      /* Read the DAC */
+      /* Read the DAC. */
       fee_read(ioaddr, 0x60,
 	       dac, 2);
 
-      /* Read the new power adjust value */
+      /* Read the new power adjust value. */
       fee_read(ioaddr, 0x6B - (power_band >> 1),
 	       &power_adjust, 1);
       if(power_band & 0x1)
@@ -1645,7 +1645,7 @@
 	power_adjust &= 0xFF;
 
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
       for(i = 0; i < 16; i++)
 	{
 	  printk(" %04X",
@@ -1653,11 +1653,11 @@
 	}
       printk("\n");
 
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+      printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
 	     dac[0], dac[1]);
 #endif
 
-      /* Frequency offset (for info only...) */
+      /* Frequency offset (for info only) */
       area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
 
       /* Receiver Principle main divider coefficient */
@@ -1668,43 +1668,43 @@
       area[13] = (freq >> 1) + 2400L;
       area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
 
-      /* Others part of the area are flags, bit streams or unused... */
+      /* Other parts of the area are flags, bit streams or unused. */
 
-      /* Set the value in the DAC */
+      /* Set the value in the DAC. */
       dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
       dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
 
-      /* Write the first area */
+      /* Write the first area. */
       fee_write(ioaddr, 0x00,
 		area, 16);
 
-      /* Write the DAC */
+      /* Write the DAC. */
       fee_write(ioaddr, 0x60,
 		dac, 2);
 
-      /* We now should verify here that the EEprom writting was ok */
+      /* We now should verify here that the writing of the EEPROM was OK. */
 
-      /* ReRead the first area */
+      /* Reread the first area. */
       fee_read(ioaddr, 0x00,
 	       area_verify, 16);
 
-      /* ReRead the DAC */
+      /* Reread the DAC. */
       fee_read(ioaddr, 0x60,
 	       dac_verify, 2);
 
-      /* Compare */
+      /* Compare. */
       if(memcmp(area, area_verify, 16 * 2) ||
 	 memcmp(dac, dac_verify, 2 * 2))
 	{
 #ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+	  printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
 #endif
 	  return -EOPNOTSUPP;
 	}
 
       /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
+       * synthesizers (from the EEPROM - area 1)
+       * Note: as the EEPROM is automatically decremented, we set the end
        * if the area... */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
@@ -1714,7 +1714,7 @@
       fee_wait(ioaddr, 100, 100);
 
       /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC) */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
 	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
@@ -1723,9 +1723,9 @@
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_IOCTL_INFO
-      /* Verification of what we have done... */
+      /* Verification of what we have done */
 
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
       for(i = 0; i < 16; i++)
 	{
 	  printk(" %04X",
@@ -1733,7 +1733,7 @@
 	}
       printk("\n");
 
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+      printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
 	     dac_verify[0], dac_verify[1]);
 #endif
 
@@ -1760,7 +1760,7 @@
   fee_read(ioaddr, 0x71 /* frequency table */,
 	   table, 10);
 
-  /* Look all frequencies */
+  /* Check all frequencies */
   i = 0;
   for(freq = 0; freq < 150; freq++)
     /* Look in the table if the frequency is allowed */
@@ -1770,7 +1770,7 @@
 	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
 	list[i++].e = 1;
 
-	/* Check number */
+	/* Check number. */
 	if(i >= max)
 	  return(i);
       }
@@ -1781,9 +1781,9 @@
 #ifdef WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
- * Gather wireless spy statistics : for each packet, compare the source
- * address with out list, and if match, get the stats...
- * Sorry, but this function really need wireless extensions...
+ * Gather wireless spy statistics:  for each packet, compare the source
+ * address with our list, and if they match, get the statistics.
+ * Sorry, but this function really needs the wireless extensions.
  */
 static inline void
 wl_spy_gather(device *	dev,
@@ -1793,7 +1793,7 @@
   net_local *	lp = (net_local *) dev->priv;
   int		i;
 
-  /* Look all addresses */
+  /* Check all addresses. */
   for(i = 0; i < lp->spy_number; i++)
     /* If match */
     if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
@@ -1810,12 +1810,12 @@
 #ifdef HISTOGRAM
 /*------------------------------------------------------------------*/
 /*
- * This function calculate an histogram on the signal level.
+ * This function calculates a histogram of the signal level.
  * As the noise is quite constant, it's like doing it on the SNR.
  * We have defined a set of interval (lp->his_range), and each time
  * the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one wavelan is really weak,
- * or you may also calculate the mean and standard deviation of the level...
+ * With this histogram you may detect if one WaveLAN is really weak,
+ * or you may also calculate the mean and standard deviation of the level.
  */
 static inline void
 wl_his_gather(device *	dev,
@@ -1825,25 +1825,25 @@
   u_char	level = stats[0] & MMR_SIGNAL_LVL;
   int		i;
 
-  /* Find the correct interval */
+  /* Find the correct interval. */
   i = 0;
   while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
     ;
 
-  /* Increment interval counter */
+  /* Increment interval counter. */
   (lp->his_sum[i])++;
 }
 #endif	/* HISTOGRAM */
 
 /*------------------------------------------------------------------*/
 /*
- * Perform ioctl : config & info stuff
+ * Perform ioctl:  configuration and information
  * This is here that are treated the wireless extensions (iwconfig)
  */
 static int
-wavelan_ioctl(struct device *	dev,	/* Device on wich the ioctl apply */
-	      struct ifreq *	rq,	/* Data passed */
-	      int		cmd)	/* Ioctl number */
+wavelan_ioctl(struct device *	dev,	/* device on which the ioctl is applied */
+	      struct ifreq *	rq,	/* data passed */
+	      int		cmd)	/* ioctl number */
 {
   u_long		ioaddr = dev->base_addr;
   net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
@@ -1870,7 +1870,7 @@
       break;
 
     case SIOCSIWNWID:
-      /* Set NWID in wavelan */
+      /* Set NWID in WaveLAN. */
       if(wrq->u.nwid.on)
 	{
 	  /* Set NWID in psa */
@@ -1889,19 +1889,19 @@
 	}
       else
 	{
-	  /* Disable nwid in the psa */
+	  /* Disable NWID in the psa. */
 	  psa.psa_nwid_select = 0x00;
 	  psa_write(ioaddr, lp->hacr,
 		    (char *)&psa.psa_nwid_select - (char *)&psa,
 		    (unsigned char *)&psa.psa_nwid_select, 1);
 
-	  /* Disable nwid in the mmc (no filtering) */
+	  /* Disable NWID in the mmc (no filtering). */
 	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
 	}
       break;
 
     case SIOCGIWNWID:
-      /* Read the NWID */
+      /* Read the NWID. */
       psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
 	       (unsigned char *)psa.psa_nwid, 3);
       wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
@@ -1909,7 +1909,7 @@
       break;
 
     case SIOCSIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
       if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
@@ -1918,14 +1918,14 @@
       break;
 
     case SIOCGIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody ??? - especially old cards...) */
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+       * Does it work for everybody, especially old cards? */
       if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
 	  unsigned short	freq;
 
-	  /* Ask the EEprom to read the frequency from the first area */
+	  /* Ask the EEPROM to read the frequency from the first area */
 	  fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
 		   &freq, 1);
 	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
@@ -1949,7 +1949,7 @@
       break;
 
     case SIOCSIWSENS:
-      /* Set the level threshold */
+      /* Set the level threshold. */
       if(!suser())
 	return -EPERM;
       psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
@@ -1959,14 +1959,14 @@
       break;
 
     case SIOCGIWSENS:
-      /* Read the level threshold */
+      /* Read the level threshold. */
       psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
 	       (unsigned char *) &psa.psa_thr_pre_set, 1);
       wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
       break;
 
      case SIOCSIWENCODE:
-       /* Set encryption key */
+       /* Set encryption key. */
        if(!mmc_encr(ioaddr))
 	 {
 	   ret = -EOPNOTSUPP;
@@ -1974,7 +1974,7 @@
 	 }
 
        if(wrq->u.encoding.method)
-	 {	/* enable encryption */
+	 {	/* Enable encryption. */
 	   int		i;
 	   long long	key = wrq->u.encoding.code;
 
@@ -1994,7 +1994,7 @@
 		     (unsigned char *) &psa.psa_encryption_key, 8);
 	 }
        else
-	 {	/* disable encryption */
+	 {	/* Disable encryption. */
 	   psa.psa_encryption_select = 0;
 	   psa_write(ioaddr, lp->hacr,
 		     (char *) &psa.psa_encryption_select - (char *) &psa,
@@ -2005,14 +2005,14 @@
        break;
 
      case SIOCGIWENCODE:
-       /* Read the encryption key */
+       /* Read the encryption key. */
        if(!mmc_encr(ioaddr))
 	 {
 	   ret = -EOPNOTSUPP;
 	   break;
 	 }
 
-       /* only super-user can see encryption key */
+       /* Only super-user can see encryption key. */
        if(!suser())
 	 {
 	   ret = -EPERM;
@@ -2042,26 +2042,26 @@
        break;
 
     case SIOCGIWRANGE:
-      /* Basic checking... */
+      /* basic checking */
       if(wrq->u.data.pointer != (caddr_t) 0)
 	{
 	  struct iw_range	range;
 
-	  /* Verify the user buffer */
+	  /* Verify the user buffer. */
 	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
 			    sizeof(struct iw_range));
 	  if(ret)
 	    break;
 
-	  /* Set the length (useless : its constant...) */
+	  /* Set the length (useless:  it's constant). */
 	  wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set information in the range struct */
+	  /* Set information in the range struct.  */
 	  range.throughput = 1.6 * 1024 * 1024;	/* don't argue on this ! */
 	  range.min_nwid = 0x0000;
 	  range.max_nwid = 0xFFFF;
 
-	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
 	  if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
 	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	    {
@@ -2077,14 +2077,14 @@
 	  range.max_qual.level = MMR_SIGNAL_LVL;
 	  range.max_qual.noise = MMR_SILENCE_LVL;
 
-	  /* Copy structure to the user buffer */
+	  /* Copy structure to the user buffer. */
 	  copy_to_user(wrq->u.data.pointer, &range,
 		       sizeof(struct iw_range));
 	}
       break;
 
     case SIOCGIWPRIV:
-      /* Basic checking... */
+      /* Basic checking */
       if(wrq->u.data.pointer != (caddr_t) 0)
 	{
 	  struct iw_priv_args	priv[] =
@@ -2102,10 +2102,10 @@
 	  if(ret)
 	    break;
 
-	  /* Set the number of ioctl available */
+	  /* Set the number of available ioctls. */
 	  wrq->u.data.length = 4;
 
-	  /* Copy structure to the user buffer */
+	  /* Copy structure to the user buffer. */
 	  copy_to_user(wrq->u.data.pointer, (u_char *) priv,
 		       sizeof(priv));
 	}
@@ -2115,7 +2115,7 @@
     case SIOCSIWSPY:
       /* Set the spy list */
 
-      /* Check the number of addresses */
+      /* Check the number of addresses. */
       if(wrq->u.data.length > IW_MAX_SPY)
 	{
 	  ret = -E2BIG;
@@ -2123,33 +2123,33 @@
 	}
       lp->spy_number = wrq->u.data.length;
 
-      /* If there is some addresses to copy */
+      /* Are there are addresses to copy? */
       if(lp->spy_number > 0)
 	{
 	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
-	  /* Verify where the user has set his addresses */
+	  /* Verify where the user has set his addresses. */
 	  ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
 			    sizeof(struct sockaddr) * lp->spy_number);
 	  if(ret)
 	    break;
-	  /* Copy addresses to the driver */
+	  /* Copy addresses to the driver. */
 	  copy_from_user(address, wrq->u.data.pointer,
 			 sizeof(struct sockaddr) * lp->spy_number);
 
-	  /* Copy addresses to the lp structure */
+	  /* Copy addresses to the lp structure. */
 	  for(i = 0; i < lp->spy_number; i++)
 	    {
 	      memcpy(lp->spy_address[i], address[i].sa_data,
 		     WAVELAN_ADDR_SIZE);
 	    }
 
-	  /* Reset structure... */
+	  /* Reset structure. */
 	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
 
 #ifdef DEBUG_IOCTL_INFO
-	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n");
 	  for(i = 0; i < wrq->u.data.length; i++)
 	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
 		   lp->spy_address[i][0],
@@ -2164,25 +2164,25 @@
       break;
 
     case SIOCGIWSPY:
-      /* Get the spy list and spy stats */
+      /* Get the spy list and spy stats. */
 
       /* Set the number of addresses */
       wrq->u.data.length = lp->spy_number;
 
-      /* If the user want to have the addresses back... */
+      /* Does the user want to have the addresses back? */
       if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
 	{
 	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
-	  /* Verify the user buffer */
+	  /* Verify the user buffer. */
 	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
 			    (sizeof(iw_qual) + sizeof(struct sockaddr))
 			    * IW_MAX_SPY);
 	  if(ret)
 	    break;
 
-	  /* Copy addresses from the lp structure */
+	  /* Copy addresses from the lp structure. */
 	  for(i = 0; i < lp->spy_number; i++)
 	    {
 	      memcpy(address[i].sa_data, lp->spy_address[i],
@@ -2190,16 +2190,16 @@
 	      address[i].sa_family = AF_UNIX;
 	    }
 
-	  /* Copy addresses to the user buffer */
+	  /* Copy addresses to the user buffer. */
 	  copy_to_user(wrq->u.data.pointer, address,
 		       sizeof(struct sockaddr) * lp->spy_number);
 
-	  /* Copy stats to the user buffer (just after) */
+	  /* Copy stats to the user buffer (just after). */
 	  copy_to_user(wrq->u.data.pointer +
 		       (sizeof(struct sockaddr) * lp->spy_number),
 		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
 
-	  /* Reset updated flags */
+	  /* Reset updated flags. */
 	  for(i = 0; i < lp->spy_number; i++)
 	    lp->spy_stat[i].updated = 0x0;
 	}	/* if(pointer != NULL) */
@@ -2230,7 +2230,7 @@
       if(!suser())
 	return -EPERM;
 
-      /* Check the number of intervals */
+      /* Check the number of intervals. */
       if(wrq->u.data.length > 16)
 	{
 	  ret = -E2BIG;
@@ -2238,10 +2238,10 @@
 	}
       lp->his_number = wrq->u.data.length;
 
-      /* If there is some addresses to copy */
+      /* Are there addresses to copy? */
       if(lp->his_number > 0)
 	{
-	  /* Verify where the user has set his addresses */
+	  /* Verify where the user has set his addresses. */
 	  ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
 			    sizeof(char) * lp->his_number);
 	  if(ret)
@@ -2250,25 +2250,25 @@
 	  copy_from_user(lp->his_range, wrq->u.data.pointer,
 			 sizeof(char) * lp->his_number);
 
-	  /* Reset structure... */
+	  /* Reset structure. */
 	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
 	}
       break;
 
     case SIOCGIPHISTO:
-      /* Set the number of intervals */
+      /* Set the number of intervals. */
       wrq->u.data.length = lp->his_number;
 
       /* Give back the distribution statistics */
       if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
 	{
-	  /* Verify the user buffer */
+	  /* Verify the user buffer. */
 	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
 			    sizeof(long) * 16);
 	  if(ret)
 	    break;
 
-	  /* Copy data to the user buffer */
+	  /* Copy data to the user buffer. */
 	  copy_to_user(wrq->u.data.pointer, lp->his_sum,
 		       sizeof(long) * lp->his_number);
 	}	/* if(pointer != NULL) */
@@ -2281,7 +2281,7 @@
       ret = -EOPNOTSUPP;
     }
 
-  /* ReEnable interrupts & restore flags */
+  /* Enable interrupts and restore flags. */
   wv_splx(x);
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -2292,8 +2292,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Get wireless statistics
- * Called by /proc/net/wireless...
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
  */
 static iw_stats *
 wavelan_get_wireless_stats(device *	dev)
@@ -2308,14 +2308,14 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  /* Disable interrupts & save flags */
+  /* Disable interrupts and save flags. */
   x = wv_splhi();
 
   if(lp == (net_local *) NULL)
     return (iw_stats *) NULL;
   wstats = &lp->wstats;
 
-  /* Get data from the mmc */
+  /* Get data from the mmc. */
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
 
   mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
@@ -2324,7 +2324,7 @@
 
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
 
-  /* Copy data to wireless stuff */
+  /* Copy data to wireless stuff. */
   wstats->status = m.mmr_dce_status;
   wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
   wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
@@ -2336,7 +2336,7 @@
   wstats->discard.code = 0L;
   wstats->discard.misc = 0L;
 
-  /* ReEnable interrupts & restore flags */
+  /* Enable interrupts and restore flags. */
   wv_splx(x);
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -2348,22 +2348,22 @@
 
 /************************* PACKET RECEPTION *************************/
 /*
- * This part deal with receiving the packets.
- * The interrupt handler get an interrupt when a packet has been
- * successfully received and called this part...
+ * This part deals with receiving the packets.
+ * The interrupt handler gets an interrupt when a packet has been
+ * successfully received and calls this part.
  */
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does the actual copy of data (including the ethernet
+ * This routine does the actual copying of data (including the Ethernet
  * header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: We
+ * will be passed up to the network interface layer. NOTE: we
  * currently don't handle trailer protocols (neither does the rest of
  * the network interface), so if that is needed, it will (at least in
  * part) be added here.  The contents of the receive ring buffer are
  * copied to a message chain that is then passed to the kernel.
  *
- * Note: if any errors occur, the packet is "dropped on the floor"
+ * Note: if any errors occur, the packet is "dropped on the floor".
  * (called by wv_packet_rcv())
  */
 static inline void
@@ -2393,7 +2393,7 @@
 
   skb->dev = dev;
 
-  /* Copy the packet to the buffer */
+  /* Copy the packet to the buffer. */
   obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
   skb->protocol=eth_type_trans(skb, dev);
 
@@ -2401,7 +2401,7 @@
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
 
-  /* Statistics gathering & stuff associated.
+  /* Statistics-gathering and associated stuff.
    * It seem a bit messy with all the define, but it's really simple... */
 #if defined(WIRELESS_SPY) || defined(HISTOGRAM)
   if(
@@ -2413,13 +2413,13 @@
 #endif	/* HISTOGRAM */
      0)
     {
-      u_char	stats[3];	/* Signal level, Noise level, Signal quality */
+      u_char	stats[3];	/* signal level, noise level, signal quality */
 
-      /* read signal level, silence level and signal quality bytes */
-      /* Note : in the Pcmcia hardware, these are part of the frame. It seem
+      /* Read signal level, silence level and signal quality bytes. */
+      /* Note: in the PCMCIA hardware, these are part of the frame. It seems
        * that for the ISA hardware, it's nowhere to be found in the frame,
-       * so I'm oblige to do this (it has side effect on /proc/net/wireless)
-       * Any idea ? */
+       * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+       * Any ideas? */
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
       mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
@@ -2440,11 +2440,11 @@
 #endif	/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
 
   /*
-   * Hand the packet to the Network Module
+   * Hand the packet to the network module.
    */
   netif_rx(skb);
 
-  /* Keep stats up to date */
+  /* Keep statistics up to date */
   lp->stats.rx_packets++;
   lp->stats.rx_bytes += skb->len;
 
@@ -2470,7 +2470,7 @@
   printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
 #endif
 
-  /* Loop on each received packet */
+  /* Loop on each received packet. */
   for(;;)
     {
       fd_t		fd;
@@ -2479,13 +2479,13 @@
 
       obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
 
-      /* If the current frame is not complete, we have reach the end... */
+      /* If the current frame is not complete, we have reached the end. */
       if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
-	break;		/* This is how we exit the loop */
+	break;		/* This is how we exit the loop. */
 
       nreaped++;
 
-      /* Check if frame correctly received */
+      /* Check whether frame was correctly received. */
       if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
 	 (FD_STATUS_B | FD_STATUS_OK))
 	{
@@ -2508,7 +2508,7 @@
 #endif
 	}
 
-      /* Check is there was problems in the frame processing */
+      /* Were there problems in processing the frame?  Let's check. */
       if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
 			  FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
 	 != 0)
@@ -2565,7 +2565,7 @@
 	    }
 	}
 
-      /* Check if frame contain a pointer to the data */
+      /* Does the frame contain a pointer to the data?  Let's check. */
       if(fd.fd_rbd_offset == I82586NULL)
 #ifdef DEBUG_RX_ERROR
 	printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
@@ -2618,7 +2618,7 @@
 
 /*********************** PACKET TRANSMISSION ***********************/
 /*
- * This part deal with sending packet through the wavelan
+ * This part deals with sending packets through the WaveLAN.
  *
  */
 
@@ -2628,13 +2628,13 @@
  * locations on the WaveLAN card and starts the card off on
  * the transmit.
  *
- * The principle :
- * Each block contains a transmit command, a nop command,
+ * The principle:
+ * Each block contains a transmit command, a NOP command,
  * a transmit block descriptor and a buffer.
  * The CU reads the transmit block which points to the tbd,
  * reads the tbd and the content of the buffer.
  * When it has finished with it, it goes to the next command
- * which in our case is the nop. The nop points on itself,
+ * which in our case is the NOP. The NOP points on itself,
  * so the CU stops here.
  * When we add the next block, we modify the previous nop
  * to make it point on the new tx command.
@@ -2665,13 +2665,13 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  /* Check if we need some padding */
+  /* Do we need some padding? */
   if(clen < ETH_ZLEN)
     clen = ETH_ZLEN;
 
   x = wv_splhi();
 
-  /* Calculate addresses of next block and previous block */
+  /* Calculate addresses of next block and previous block. */
   txblock = lp->tx_first_free;
   txpred = txblock - TXBLOCKZ;
   if(txpred < OFFSET_CU)
@@ -2687,14 +2687,14 @@
 
   lp->tx_n_in_use++;
 
-  /* Calculate addresses of the differents part of the block */
+  /* Calculate addresses of the different parts of the block. */
   tx_addr = txblock;
   nop_addr = tx_addr + sizeof(tx);
   tbd_addr = nop_addr + sizeof(nop);
   buf_addr = tbd_addr + sizeof(tbd);
 
   /*
-   * Transmit command.
+   * Transmit command
    */
   tx.tx_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -2702,7 +2702,7 @@
 	      sizeof(tx.tx_h.ac_status));
 
   /*
-   * NOP command.
+   * NOP command
    */
   nop.nop_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -2714,7 +2714,7 @@
 	      sizeof(nop.nop_h.ac_link));
 
   /*
-   * Transmit buffer descriptor. 
+   * Transmit buffer descriptor
    */
   tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
   tbd.tbd_next_bd_offset = I82586NULL;
@@ -2723,7 +2723,7 @@
   obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
 
   /*
-   * Data.
+   * Data
    */
   obram_write(ioaddr, buf_addr, buf, clen);
 
@@ -2741,13 +2741,13 @@
 	      (unsigned char *) &nop.nop_h.ac_link,
 	      sizeof(nop.nop_h.ac_link));
 
-  /* Keep stats up to date */
+  /* Keep stats up to date. */
   lp->stats.tx_bytes += length;
 
   /* If watchdog not already active, activate it... */
   if(lp->watchdog.prev == (timer_list *) NULL)
     {
-      /* set timer to expire in WATCHDOG_JIFFIES */
+      /* Set timer to expire in WATCHDOG_JIFFIES. */
       lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
       add_timer(&lp->watchdog);
     }
@@ -2774,7 +2774,7 @@
  * This routine is called when we want to send a packet (NET3 callback)
  * In this routine, we check if the hardware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
- * to send the packet...
+ * to send the packet.
  */
 static int
 wavelan_packet_xmit(struct sk_buff *	skb,
@@ -2788,9 +2788,9 @@
 #endif
 
   /* This flag indicate that the hardware can't perform a transmission.
-   * Theoritically, NET3 check it before sending a packet to the driver,
-   * but in fact it never do that and pool continuously.
-   * As the watchdog will abort too long transmissions, we are quite safe...
+   * Theoretically, NET3 checks it before sending a packet to the driver,
+   * but in fact it never does that and pools continuously.
+   * As the watchdog will abort overly long transmissions, we are quite safe.
    */
   if(dev->tbusy)
     return 1;
@@ -2805,7 +2805,9 @@
 #endif
   else
     {
-      /* If somebody has asked to reconfigure the controler, we can do it now */
+      /* If somebody has asked to reconfigure the controller, 
+       * we can do it now.
+       */
       if(lp->reconfig_82586)
 	{
 	  wv_82586_config(dev);
@@ -2829,12 +2831,12 @@
   return 0;
 }
 
-/********************** HARDWARE CONFIGURATION **********************/
+/*********************** HARDWARE CONFIGURATION ***********************/
 /*
- * This part do the real job of starting and configuring the hardware.
+ * This part does the real job of starting and configuring the hardware.
  */
 
-/*------------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
 /*
  * Routine to initialize the Modem Management Controller.
  * (called by wv_hw_reset())
@@ -2852,7 +2854,7 @@
   printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
 #endif
 
-  /* Read the parameter storage area */
+  /* Read the parameter storage area. */
   psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
 
 #ifdef USE_PSA_CONFIG
@@ -2864,11 +2866,11 @@
   /* Is the PSA is not configured */
   if(!configured)
     {
-      /* User will be able to configure NWID after (with iwconfig) */
+      /* User will be able to configure NWID later (with iwconfig). */
       psa.psa_nwid[0] = 0;
       psa.psa_nwid[1] = 0;
 
-      /* As NWID is not set : no NWID checking */
+      /* no NWID checking since NWID is not set */
       psa.psa_nwid_select = 0;
 
       /* Disable encryption */
@@ -2901,10 +2903,10 @@
 #endif
     }
 
-  /* Zero the mmc structure */
+  /* Zero the mmc structure. */
   memset(&m, 0x00, sizeof(m));
 
-  /* Copy PSA info to the mmc */
+  /* Copy PSA info to the mmc. */
   m.mmw_netw_id_l = psa.psa_nwid[1];
   m.mmw_netw_id_h = psa.psa_nwid[0];
   
@@ -2924,7 +2926,7 @@
   m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
   m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
 
-  /* Missing : encryption stuff... */
+  /* Encryption stuff is missing. */
 
   /*
    * Set default modem control parameters.
@@ -2942,58 +2944,58 @@
   m.mmw_decay_prm = 0;
   m.mmw_decay_updat_prm = 0;
 
-  /* Write all info to mmc */
+  /* Write all info to MMC. */
   mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
 
-  /* The following code start the modem of the 2.00 frequency
+  /* The following code starts the modem of the 2.00 frequency
    * selectable cards at power on. It's not strictly needed for the
-   * following boots...
+   * following boots.
    * The original patch was by Joe Finney for the PCMCIA driver, but
-   * I've cleaned it a bit and add documentation.
+   * I've cleaned it up a bit and added documentation.
    * Thanks to Loeke Brederveld from Lucent for the info.
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody ??? - especially old cards...) */
-  /* Note : WFREQSEL verify that it is able to read from EEprom
-   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
-   * is 0xA (Xilinx version) or 0xB (Ariadne version).
-   * My test is more crude but do work... */
+   * Does it work for everybody, especially old cards? */
+  /* Note: WFREQSEL verifies that it is able to read a sensible
+   * frequency from from EEPROM (address 0x00) and that
+   * MMR_FEE_STATUS_ID is 0xA (Xilinx version) or 0xB (Ariadne version).
+   * My test is more crude but does work. */
   if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
        (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
     {
       /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
+       * synthesizers (from the EEPROM - area 1)
+       * Note: as the EEPROM is automatically decremented, we set the end
        * if the area... */
       m.mmw_fee_addr = 0x0F;
       m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
       mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
 		(unsigned char *)&m.mmw_fee_ctrl, 2);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_CONFIG_INFO
-      /* The frequency was in the last word downloaded... */
+      /* The frequency was in the last word downloaded. */
       mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
 	       (unsigned char *)&m.mmw_fee_data_l, 2);
 
-      /* Print some info for the user */
-      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+      /* Print some info for the user. */
+      printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
 	     dev->name,
 	     ((m.mmw_fee_data_h << 4) |
 	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
 #endif
 
       /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC). */
       m.mmw_fee_addr = 0x61;
       m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
       mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
 		(unsigned char *)&m.mmw_fee_ctrl, 2);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
     }	/* if 2.00 card */
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3091,13 +3093,13 @@
  * Start the command unit executing the NOP
  * self-loop of the first transmit block.
  *
- * Here, we create the list of send buffer used to transmit packets
+ * Here we create the list of send buffers used to transmit packets
  * between the PC and the command unit. For each buffer, we create a
  * buffer descriptor (pointing on the buffer), a transmit command
- * (pointing to the buffer descriptor) and a nop command.
- * The transmit command is linked to the nop, and the nop to itself.
- * When we will have finish to execute the transmit command, we will
- * then loop on the nop. By releasing the nop link to a new command,
+ * (pointing to the buffer descriptor) and a NOP command.
+ * The transmit command is linked to the NOP, and the NOP to itself.
+ * When we will have finished executing the transmit command, we will
+ * then loop on the NOP. By releasing the NOP link to a new command,
  * we may send another buffer.
  *
  * (called by wv_hw_reset())
@@ -3194,12 +3196,13 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN 
+ * controller (i82586).
  *
- * It initialise the scp, iscp and scb structure
- * The two first are only pointer to the next.
+ * It initialises the scp, iscp and scb structure
+ * The first two are just pointers to the next.
  * The last one is used for basic configuration and for basic
- * communication (interrupt status)
+ * communication (interrupt status).
  *
  * (called by wv_hw_reset())
  */
@@ -3240,7 +3243,7 @@
   iscp.iscp_offset = OFFSET_SCB;
   obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
 
-  /* Our first command is to reset the i82586 */
+  /* Our first command is to reset the i82586. */
   memset(&scb, 0x00, sizeof(scb));
   scb.scb_command = SCB_CMD_RESET;
   scb.scb_cbl_offset = OFFSET_CU;
@@ -3249,7 +3252,7 @@
 
   set_chan_attn(ioaddr, lp->hacr);
 
-  /* Wait for command to finish */
+  /* Wait for command to finish. */
   for(i = 1000; i > 0; i--)
     {
       obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
@@ -3269,7 +3272,7 @@
       return -1;
     }
 
-  /* Check command completion */
+  /* Check command completion. */
   for(i = 15; i > 0; i--)
     {
       obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
@@ -3291,7 +3294,7 @@
 
   wv_ack(dev);
 
-  /* Set the action command header */
+  /* Set the action command header. */
   memset(&cb, 0x00, sizeof(cb));
   cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
   cb.ac_link = OFFSET_CU;
@@ -3322,14 +3325,15 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
  *
  * This routine is a violent hack. We use the first free transmit block
  * to make our configuration. In the buffer area, we create the three
- * configure command (linked). We make the previous nop point to the
- * beggining of the buffer instead of the tx command. After, we go as
- * usual to the nop command...
- * Note that only the last command (mc_set) will generate an interrupt...
+ * configuration commands (linked). We make the previous NOP point to
+ * the beginning of the buffer instead of the tx command. After, we go
+ * as usual to the NOP command.
+ * Note that only the last command (mc_set) will generate an interrupt.
  *
  * (called by wv_hw_reset(), wv_82586_reconfig())
  */
@@ -3360,7 +3364,7 @@
 
   x = wv_splhi();
 
-  /* Calculate addresses of next block and previous block */
+  /* Calculate addresses of next block and previous block. */
   txblock = lp->tx_first_free;
   txpred = txblock - TXBLOCKZ;
   if(txpred < OFFSET_CU)
@@ -3371,16 +3375,16 @@
 
   lp->tx_n_in_use++;
 
-  /* Calculate addresses of the differents part of the block */
+  /* Calculate addresses of the different parts of the block. */
   tx_addr = txblock;
   nop_addr = tx_addr + sizeof(tx);
   tbd_addr = nop_addr + sizeof(nop);
-  cfg_addr = tbd_addr + sizeof(tbd_t);	/* beggining of the buffer */
+  cfg_addr = tbd_addr + sizeof(tbd_t);	/* beginning of the buffer */
   ias_addr = cfg_addr + sizeof(cfg);
   mcs_addr = ias_addr + sizeof(ias);
 
   /*
-   * Transmit command.
+   * Transmit command
    */
   tx.tx_h.ac_status = 0xFFFF;	/* Fake completion value */
   obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -3388,7 +3392,7 @@
 	      sizeof(tx.tx_h.ac_status));
 
   /*
-   * NOP command.
+   * NOP command
    */
   nop.nop_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -3399,23 +3403,23 @@
 	      (unsigned char *) &nop.nop_h.ac_link,
 	      sizeof(nop.nop_h.ac_link));
 
-  /* Create a configure action */
+  /* Create a configure action. */
   memset(&cfg, 0x00, sizeof(cfg));
 
 #if	0
   /*
-   * The default board configuration.
+   * The default board configuration
    */
   cfg.fifolim_bytecnt 	= 0x080c;
   cfg.addrlen_mode  	= 0x2600;
   cfg.linprio_interframe	= 0x7820;	/* IFS=120, ACS=2 */
   cfg.slot_time      	= 0xf00c;	/* slottime=12    */
-  cfg.hardware	     	= 0x0008;	/* tx even w/o CD */
+  cfg.hardware	     	= 0x0008;	/* tx even without CD */
   cfg.min_frame_len   	= 0x0040;
 #endif	/* 0 */
 
   /*
-   * For Linux we invert AC_CFG_ALOC(..) so as to conform
+   * For Linux we invert AC_CFG_ALOC() so as to conform
    * to the way that net packets reach us from above.
    * (See also ac_tx_t.)
    */
@@ -3456,21 +3460,21 @@
   cfg.cfg_h.ac_link = ias_addr;
   obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
 
-  /* Setup the MAC address */
+  /* Set up the MAC address */
   memset(&ias, 0x00, sizeof(ias));
   ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
   ias.ias_h.ac_link = mcs_addr;
   memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
   obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
 
-  /* Initialize adapter's ethernet multicast addresses */
+  /* Initialize adapter's Ethernet multicast addresses */
   memset(&mcs, 0x00, sizeof(mcs));
   mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
   mcs.mcs_h.ac_link = nop_addr;
   mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
   obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
 
-  /* If any address to set */
+  /* Any address to set? */
   if(lp->mc_count)
     {
       for(dmi=dev->mc_list; dmi; dmi=dmi->next)
@@ -3526,8 +3530,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This routine stop gracefully the WaveLAN controler (i82586).
- * (called by wavelan_close())
+ * This routine, called by wavelan_close(), gracefully stops the 
+ * WaveLAN controller (i82586).
  */
 static inline void
 wv_82586_stop(device *	dev)
@@ -3540,7 +3544,7 @@
   printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
 #endif
 
-  /* Suspend both command unit and receive unit */
+  /* Suspend both command unit and receive unit. */
   scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
   obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
 	      (unsigned char *)&scb_cmd, sizeof(scb_cmd));
@@ -3556,7 +3560,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Totally reset the wavelan and restart it.
+ * Totally reset the WaveLAN and restart it.
  * Performs the following actions:
  *	1. A power reset (reset DMA)
  *	2. Initialize the radio modem (using wv_mmc_init)
@@ -3575,11 +3579,11 @@
 	 (unsigned int)dev);
 #endif
 
-  /* If watchdog was activated, kill it ! */
+  /* If watchdog was activated, kill it! */
   if(lp->watchdog.prev != (timer_list *) NULL)
     del_timer(&lp->watchdog);
 
-  /* Increase the number of resets done */
+  /* Increase the number of resets done. */
   lp->nresets++;
 
   wv_hacr_reset(ioaddr);
@@ -3589,7 +3593,7 @@
      (wv_82586_start(dev) < 0))
     return -1;
 
-  /* Enable the card to send interrupts */
+  /* Enable the card to send interrupts. */
   wv_ints_on(dev);
 
   /* Start card functions */
@@ -3597,7 +3601,7 @@
      (wv_cu_start(dev) < 0))
     return -1;
 
-  /* Finish configuration */
+  /* Finish configuration. */
   wv_82586_config(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3608,8 +3612,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Check if there is a wavelan at the specific base address.
- * As a side effect, it read the MAC address.
+ * Check if there is a WaveLAN at the specific base address.
+ * As a side effect, this reads the MAC address.
  * (called in wavelan_probe() and init_module())
  */
 static int
@@ -3618,22 +3622,22 @@
 {
   int		i;		/* Loop counter */
 
-  /* Check if the base address if available */
+  /* Check if the base address if available. */
   if(check_region(ioaddr, sizeof(ha_t)))
-    return  EADDRINUSE;		/* ioaddr already used... */
+    return  EADDRINUSE;		/* ioaddr already used */
 
   /* Reset host interface */
   wv_hacr_reset(ioaddr);
 
-  /* Read the MAC address from the parameter storage area */
+  /* Read the MAC address from the parameter storage area. */
   psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
 	   mac, 6);
 
   /*
-   * Check the first three octets of the addr for the manufacturer's code.
-   * Note: If you can't find your wavelan card, you've got a
-   * non-NCR/AT&T/Lucent ISA cards, see wavelan.p.h for detail on
-   * how to configure your card...
+   * Check the first three octets of the address for the manufacturer's code.
+   * Note: if this can't find your WaveLAN card, you've got a
+   * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
+   * how to configure your card.
    */
   for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
     if((mac[0] == MAC_ADDRESSES[i][0]) &&
@@ -3642,7 +3646,7 @@
       return 0;
 
 #ifdef DEBUG_CONFIG_INFO
-  printk(KERN_WARNING "Wavelan (0x%3X) : Your MAC address might be : %02X:%02X:%02X...\n",
+  printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
 	 ioaddr, mac[0], mac[1], mac[2]);
 #endif
     return ENODEV;
@@ -3675,7 +3679,7 @@
   lp = (net_local *) dev->priv;
   ioaddr = dev->base_addr;
 
-  /* Prevent reentrance. What should we do here ? */
+  /* Prevent reentrance. What should we do here? */
 #ifdef DEBUG_INTERRUPT_ERROR
   if(dev->interrupt)
     printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
@@ -3708,7 +3712,7 @@
       return;
     }
 
-  /* Read interrupt data */
+  /* Read interrupt data. */
   obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
 	     (unsigned char *) &status, sizeof(status));
 
@@ -3755,7 +3759,7 @@
       wv_receive(dev);
     }
 
-  /* Check the state of the command unit */
+  /* Check the state of the command unit. */
   if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
      (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
     {
@@ -3766,7 +3770,7 @@
       wv_hw_reset(dev);
     }
 
-  /* Check the state of the command unit */
+  /* Check the state of the command unit. */
   if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
      (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
     {
@@ -3786,14 +3790,14 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, we set a timer in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the previous version of the ISA driver. I make it this
+ * Note: this watchdog doesn't work on the same principle as the
+ * watchdog in the previous version of the ISA driver. I made it this
  * way because the overhead of add_timer() and del_timer() is nothing
- * and that it avoid calling the watchdog, saving some CPU...
+ * and because it avoids calling the watchdog, saving some CPU.
  */
 static void
 wavelan_watchdog(u_long		a)
@@ -3860,7 +3864,7 @@
       wv_hw_reset(dev);
     }
   else
-    /* Re-set watchodog for next transmission */
+    /* Reset watchdog for next transmission. */
     if(lp->tx_n_in_use > 0)
       {
 	/* set timer to expire in WATCHDOG_JIFFIES */
@@ -3877,15 +3881,15 @@
 
 /********************* CONFIGURATION CALLBACKS *********************/
 /*
- * Here are the functions called by the linux networking (NET3) for
- * initialization, configuration and deinstallations of the Wavelan
- * ISA Hardware.
+ * Here are the functions called by the Linux networking code (NET3)
+ * for initialization, configuration and deinstallations of the 
+ * WaveLAN ISA hardware.
  */
 
 /*------------------------------------------------------------------*/
 /*
  * Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "open" the device.
+ * Called by NET3 when it "opens" the device.
  */
 static int
 wavelan_open(device *	dev)
@@ -3901,7 +3905,7 @@
   if(dev->irq == 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wavelan_open(): no irq\n", dev->name);
+      printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
 #endif
       return -ENXIO;
     }
@@ -3909,7 +3913,7 @@
   if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wavelan_open(): invalid irq\n", dev->name);
+      printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
 #endif
       return -EAGAIN;
     }
@@ -3941,8 +3945,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Shutdown the WaveLAN ISA card.
- * Called by NET3 when it "close" the device.
+ * Shut down the WaveLAN ISA card.
+ * Called by NET3 when it "closes" the device.
  */
 static int
 wavelan_close(device *	dev)
@@ -3954,14 +3958,14 @@
 	 (unsigned int) dev);
 #endif
 
-  /* Not do the job twice... */
+  /* Don't do the job twice. */
   if(dev->start == 0)
     return 0;
 
   dev->tbusy = 1;
   dev->start = 0;
 
-  /* If watchdog was activated, kill it ! */
+  /* If watchdog was activated, kill it! */
   if(lp->watchdog.prev != (timer_list *) NULL)
     del_timer(&lp->watchdog);
 
@@ -3982,9 +3986,9 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Probe an i/o address, and if the wavelan is there configure the
+ * Probe an I/O address, and if the WaveLAN is there configure the
  * device structure
- * (called by wavelan_probe() & via init_module())
+ * (called by wavelan_probe() and via init_module()).
  */
 __initfunc(static int
 wavelan_config(device *	dev))
@@ -3999,7 +4003,7 @@
 	 (unsigned int)dev, ioaddr);
 #endif
 
-  /* Check irq arg on command line */
+  /* Check IRQ argument on command line. */
   if(dev->irq != 0)
     {
       irq_mask = wv_irq_to_psa(dev->irq);
@@ -4007,7 +4011,7 @@
       if(irq_mask == 0)
 	{
 #ifdef DEBUG_CONFIG_ERROR
-	  printk(KERN_WARNING "%s: wavelan_config(): invalid irq %d -- ignored.\n",
+	  printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
 		 dev->name, dev->irq);
 #endif
 	  dev->irq = 0;
@@ -4015,7 +4019,7 @@
       else
 	{
 #ifdef DEBUG_CONFIG_INFO
-	  printk(KERN_DEBUG "%s: wavelan_config(): changing irq to %d\n",
+	  printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
 		 dev->name, dev->irq);
 #endif
 	  psa_write(ioaddr, HACR_DEFAULT,
@@ -4049,9 +4053,9 @@
   memset(dev->priv, 0x00, sizeof(net_local));
   lp = (net_local *)dev->priv;
 
-  /* Back link to the device structure */
+  /* Back link to the device structure. */
   lp->dev = dev;
-  /* Add the device at the beggining of the linked list */
+  /* Add the device at the beginning of the linked list. */
   lp->next = wavelan_list;
   wavelan_list = lp;
 
@@ -4064,7 +4068,7 @@
 
   /*
    * Fill in the fields of the device structure
-   * with ethernet-generic values.
+   * with generic Ethernet values.
    */
   ether_setup(dev);
 
@@ -4075,14 +4079,14 @@
   dev->set_multicast_list = &wavelan_set_multicast_list;
   dev->set_mac_address = &wavelan_set_mac_address;
 
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
   dev->do_ioctl = wavelan_ioctl;
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   dev->mtu = WAVELAN_MTU;
 
-  /* Display nice info */
+  /* Display nice information. */
   wv_init_info(dev);
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4093,18 +4097,17 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Check for a network adaptor of this type.
- * Return '0' iff one exists.
- * (There seem to be different interpretations of
+ * Check for a network adaptor of this type.  Return '0' iff one 
+ * exists.  There seem to be different interpretations of
  * the initial value of dev->base_addr.
- * We follow the example in drivers/net/ne.c.)
+ * We follow the example in drivers/net/ne.c.
  * (called in "Space.c")
  */
 __initfunc(int
 wavelan_probe(device *	dev))
 {
   short		base_addr;
-  mac_addr	mac;		/* Mac address (check wavelan existence) */
+  mac_addr	mac;		/* MAC address (check existence of WaveLAN) */
   int		i;
   int		r;
 
@@ -4122,7 +4125,7 @@
     }
 #endif	/* STRUCT_CHECK */
 
-  /* Check the value of the command line parameter for base address */
+  /* Check the value of the command line parameter for base address. */
   base_addr = dev->base_addr;
 
   /* Don't probe at all. */
@@ -4138,10 +4141,10 @@
   /* Check a single specified location. */
   if(base_addr > 0x100)
     {
-      /* Check if the is something at this base address */
+      /* Check if there is something at this base address */
       if((r = wv_check_ioaddr(base_addr, mac)) == 0)
 	{
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy mac address */
+	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
 	  r = wavelan_config(dev);
 	}
 
@@ -4157,14 +4160,14 @@
       return r;
     }
 
-  /* Scan all possible address of the wavelan hardware */
+  /* Scan all possible addresses of the WaveLAN hardware. */
   for(i = 0; i < NELS(iobase); i++)
     {
-      /* Check if the is something at this base address */
+      /* Check whether there is something at this base address. */
       if(wv_check_ioaddr(iobase[i], mac) == 0)
 	{
-	  dev->base_addr = iobase[i];		/* Copy base address */
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy mac address */
+	  dev->base_addr = iobase[i];		/* Copy base address. */
+	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
 	  if(wavelan_config(dev) == 0)
 	    {
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4175,7 +4178,7 @@
 	}
     }
 
-  /* We may have touch base_addr : another driver may not like it... */
+  /* We may have touched base_addr.  Another driver may not like it. */
   dev->base_addr = base_addr;
 
 #ifdef DEBUG_CONFIG_INFO
@@ -4188,19 +4191,19 @@
 
 /****************************** MODULE ******************************/
 /*
- * Module entry point : insertion & removal
+ * Module entry point: insertion and removal
  */
 
 #ifdef	MODULE
 /*------------------------------------------------------------------*/
 /*
- * Insertion of the module...
- * I'm now quite proud of the multi-device support...
+ * Insertion of the module
+ * I'm now quite proud of the multi-device support.
  */
 int
 init_module(void)
 {
-  mac_addr	mac;		/* Mac address (check wavelan existence) */
+  mac_addr	mac;		/* MAC address (check WaveLAN existence) */
   int		ret = 0;
   int		i;
 
@@ -4212,48 +4215,48 @@
   if(io[0] == 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "wavelan init_module(): doing device probing (bad !)\n");
+      printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
       printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
 #endif
 
-      /* Copy the basic set of address to be probed */
+      /* Copy the basic set of address to be probed. */
       for(i = 0; i < NELS(iobase); i++)
 	io[i] = iobase[i];
     }
 
 
-  /* Loop on all possible base addresses */
+  /* Loop on all possible base addresses. */
   i = -1;
   while((io[++i] != 0) && (i < NELS(io)))
     {
-      /* Check if the is something at this base address */
+      /* Check if there is something at this base address. */
       if(wv_check_ioaddr(io[i], mac) == 0)
 	{
 	  device *	dev;
 
-	  /* Create device and set basics args */
+	  /* Create device and set basic arguments. */
 	  dev = kmalloc(sizeof(struct device), GFP_KERNEL);
 	  memset(dev, 0x00, sizeof(struct device));
 	  dev->name = name[i];
 	  dev->base_addr = io[i];
 	  dev->irq = irq[i];
 	  dev->init = &wavelan_config;
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy mac address */
+	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
 
-	  /* Try to create the device */
+	  /* Try to create the device. */
 	  if(register_netdev(dev) != 0)
 	    {
-	      /* DeAllocate everything */
-	      /* Note : if dev->priv is mallocated, there is no way to fail */
+	      /* Deallocate everything. */
+	      /* Note: if dev->priv is mallocated, there is no way to fail. */
 	      kfree_s(dev, sizeof(struct device));
 	      ret = -EIO;
 	    }
-	}	/* If there is something at the address */
-    }		/* Loop on all addresses */
+	}	/* if there is something at the address */
+    }		/* Loop on all addresses. */
 
 #ifdef DEBUG_CONFIG_ERRORS
   if(wavelan_list == (net_local *) NULL)
-    printk(KERN_WARNING "wavelan init_module(): No device found\n");
+    printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
 #endif
 
 #ifdef DEBUG_MODULE_TRACE
@@ -4273,7 +4276,7 @@
   printk(KERN_DEBUG "-> cleanup_module()\n");
 #endif
 
-  /* Loop on all devices and release them */
+  /* Loop on all devices and release them. */
   while(wavelan_list != (net_local *) NULL)
     {
       device *	dev = wavelan_list->dev;
@@ -4283,16 +4286,16 @@
 	     dev->name, (unsigned int) dev);
 #endif
 
-      /* Release the ioport-region. */
+      /* Release the ioport region. */
       release_region(dev->base_addr, sizeof(ha_t));
 
-      /* Remove definitely the device */
+      /* Definitely remove the device. */
       unregister_netdev(dev);
 
-      /* Unlink the device */
+      /* Unlink the device. */
       wavelan_list = wavelan_list->next;
 
-      /* Free pieces */
+      /* Free pieces. */
       kfree_s(dev->priv, sizeof(struct net_local));
       kfree_s(dev, sizeof(struct device));
     }
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.105/linux/drivers/scsi/Config.in	Tue Apr 14 14:29:21 1998
+++ linux/drivers/scsi/Config.in	Sat Jun 13 12:59:15 1998
@@ -131,4 +131,7 @@
   fi
   dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
 fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+  source drivers/acorn/scsi/Config.in
+fi
 endmenu
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
--- v2.1.105/linux/drivers/scsi/NCR53C9x.c	Sun Jun  7 11:16:33 1998
+++ linux/drivers/scsi/NCR53C9x.c	Sat Jun 13 13:28:34 1998
@@ -395,12 +395,6 @@
 	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 
-	/* Reload the configuration registers */
-	eregs->esp_cfact = esp->cfact;
-	eregs->esp_stp   = 0;
-	eregs->esp_soff  = 0;
-	eregs->esp_timeo = esp->neg_defp;
-
 	/* This is the only point at which it is reliable to read
 	 * the ID-code for a fast ESP chip variant.
 	 */
@@ -417,7 +411,10 @@
 		  }
 #endif
 		if(family_code == 0x02)
-			esp->erev = fas236;
+		        if ((version & 7) == 2)
+			        esp->erev = fas216;	
+                        else
+			        esp->erev = fas236;
 		else if(family_code == 0x0a)
 			esp->erev = fashme; /* Version is usually '5'. */
 		else
@@ -425,13 +422,20 @@
 		printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
 		       esp->esp_id,
 		       (esp->erev == fas236) ? "fas236" :
-		       ((esp->erev == fas100a) ? "fas100a" :
-		       "fasHME"), family_code, (version & 7));
+		       ((esp->erev == fas216) ? "fas216" :		       
+		       (((esp->erev == fas100a) ? "fas100a" :
+		       "fasHME"))), family_code, (version & 7));
 
 		esp->min_period = ((4 * esp->ccycle) / 1000);
 	} else {
 		esp->min_period = ((5 * esp->ccycle) / 1000);
 	}
+
+	/* Reload the configuration registers */
+	eregs->esp_cfact = esp->cfact;
+	eregs->esp_stp   = 0;
+	eregs->esp_soff  = 0;
+	eregs->esp_timeo = esp->neg_defp;
 	esp->max_period = (esp->max_period + 3)>>2;
 	esp->min_period = (esp->min_period + 3)>>2;
 
@@ -451,6 +455,7 @@
 	case fashme:
 		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
 		/* fallthrough... */
+	case fas216:	    
 	case fas236:
 		/* Fast 236 or HME */
 		eregs->esp_cfg2 = esp->config2;
@@ -630,6 +635,9 @@
 	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
 	esp->sync_defp = SYNC_DEFP_SLOW;
 
+	printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
+	       esp->scsi_id, (esp->cfreq / 1000000),
+	       esp->ccf, (int) esp->neg_defp);
 
 	/* Fill in ehost data */
 	esp->ehost->base = (unsigned char *) eregs;
@@ -707,10 +715,6 @@
 	esp_bootup_reset(esp, eregs);
 	
 	esps_in_use++;
-
-	printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
-	       esp->scsi_id, (esp->cfreq / 1000000),
-	       esp->ccf, (int) esp->neg_defp);
 }
 
 /* The info function will return whatever useful
@@ -724,17 +728,19 @@
 	esp = (struct NCR_ESP *) host->hostdata;
 	switch(esp->erev) {
 	case esp100:
-		return "Sparc ESP100 (NCR53C90)";
+		return "ESP100 (NCR53C90)";
 	case esp100a:
-		return "Sparc ESP100A (NCR53C90A)";
+		return "ESP100A (NCR53C90A)";
 	case esp236:
-		return "Sparc ESP236";
+		return "ESP236";
+	case fas216:
+		return "ESP216-FAST";
 	case fas236:
-		return "Sparc ESP236-FAST";
+		return "ESP236-FAST";
 	case fashme:
-		return "Sparc ESP366-HME";
+		return "ESP366-HME";
 	case fas100a:
-		return "Sparc ESP100A-FAST";
+		return "ESP100A-FAST";
 	default:
 		panic("Bogon ESP revision");
 	};
@@ -807,6 +813,9 @@
 	case esp236:
 		copy_info(&info, "ESP236\n");
 		break;
+	case fas216:
+		copy_info(&info, "FAS216\n");
+		break;
 	case fas236:
 		copy_info(&info, "FAS236\n");
 		break;
@@ -1252,20 +1261,11 @@
 		SCpnt->SCp.buffer           =
 			(struct scatterlist *) SCpnt->request_buffer;
 		SCpnt->SCp.buffers_residual = 0;
-#ifdef CONFIG_SCSI_SUNESP
-		/* Sneaky. */
-		SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
-							   SCpnt->SCp.this_residual,
-							   ((struct linux_sbus_device*) (esp->edev))->my_bus);
-		/* XXX The casts are extremely gross, but with 64-bit kernel
-		 * XXX and 32-bit SBUS what am I to do? -DaveM
-		 */
-		SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
-#else
-		SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
-			(char *) VTOP((unsigned long) SCpnt->request_buffer);
-#endif
-
+	        if (esp->dma_mmu_get_scsi_one)
+		        esp->dma_mmu_get_scsi_one (esp, SCpnt);
+	        else
+		        SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
+		                (char *) virt_to_phys(SCpnt->request_buffer);
 	} else {
 		ESPQUEUE(("use_sg "));
 #ifdef DEBUG_ESP_SG
@@ -1275,16 +1275,11 @@
 		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->buffer;
 		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
-		mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
-				 SCpnt->SCp.buffers_residual,
-				 ((struct linux_sbus_device *) (esp->edev))->my_bus);
-		/* XXX Again these casts are sick... -DaveM */
-		SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
-#else
-		SCpnt->SCp.ptr = 
-		  (char *) VTOP((unsigned long) SCpnt->SCp.buffer->address);
-#endif
+	        if (esp->dma_mmu_get_scsi_sgl)
+		        esp->dma_mmu_get_scsi_sgl (esp, SCpnt);
+	        else
+		        SCpnt->SCp.ptr = 
+		                (char *) virt_to_phys(SCpnt->SCp.buffer->address);
 	}
 	SCpnt->SCp.Status           = CHECK_CONDITION;
 	SCpnt->SCp.Message          = 0xff;
@@ -1481,21 +1476,14 @@
 
 		/* Free dvma entry. */
 		if(!done_SC->use_sg) {
-#ifdef CONFIG_SCSI_SUNESP
-			/* Sneaky. */
-			mmu_release_scsi_one(done_SC->SCp.have_data_in,
-					     done_SC->request_bufflen,
-					     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+		        if (esp->dma_mmu_release_scsi_one)
+			        esp->dma_mmu_release_scsi_one (esp, done_SC);
 		} else {
 #ifdef DEBUG_ESP_SG
 			printk("esp%d: unmapping sg ", esp->esp_id);
 #endif
-#ifdef CONFIG_SCSI_SUNESP
-			mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
-					     done_SC->use_sg - 1,
-					     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+		        if (esp->dma_mmu_release_scsi_sgl)
+			        esp->dma_mmu_release_scsi_sgl (esp, done_SC);
 #ifdef DEBUG_ESP_SG
 			printk("done.\n");
 #endif
@@ -1861,16 +1849,15 @@
 	return do_work_bus;
 }
 
-static inline void advance_sg(Scsi_Cmnd *sp)
+static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
 	++sp->SCp.buffer;
 	--sp->SCp.buffers_residual;
 	sp->SCp.this_residual = sp->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
-	sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
-#else
-	sp->SCp.ptr = (char *)VTOP((unsigned long) sp->SCp.buffer->address);
-#endif
+        if (esp->dma_advance_sg)
+	       esp->dma_advance_sg (sp);
+        else
+	       sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
 }
 
 /* Please note that the way I've coded these routines is that I _always_
@@ -2067,7 +2054,7 @@
 		 * figure this out.
 		 */
 		if(SCptr->use_sg && !SCptr->SCp.this_residual)
-			advance_sg(SCptr);
+			advance_sg(esp, SCptr);
 		if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
 			ESPDATA(("to more data\n"));
 			return esp_do_data(esp, eregs);
@@ -2922,6 +2909,7 @@
 			tmp = esp->ccycle / 1000;
 			regval = (((period << 2) + tmp - 1) / tmp);
 			if(regval && ((esp->erev == fas100a ||
+				       esp->erev == fas216 ||				       
 				       esp->erev == fas236 ||
 				       esp->erev == fashme))) {
 				if(period >= 50)
@@ -2934,7 +2922,7 @@
 
 			SDptr->sync_min_period = (regval & 0x1f);
 			SDptr->sync_max_offset = (offset | esp->radelay);
-			if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+			if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
 				if((esp->erev == fas100a) || (esp->erev == fashme))
 					bit = ESP_CONFIG3_FAST;
 				else
@@ -2963,7 +2951,7 @@
 			SDptr->sync_min_period = 0;
 			eregs->esp_soff = 0;
 			eregs->esp_stp = 0;
-			if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+			if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
 				if((esp->erev == fas100a) || (esp->erev == fashme))
 					bit = ESP_CONFIG3_FAST;
 				else
@@ -3595,17 +3583,13 @@
 		if(esp->current_SC) {
 			Scsi_Cmnd *SCptr = esp->current_SC;
 
-#ifdef CONFIG_SCSI_SUNESP
-			if(!SCptr->use_sg)
-				mmu_release_scsi_one(SCptr->SCp.have_data_in,
-						     SCptr->request_bufflen,
-						     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-			else
-				mmu_release_scsi_sgl((struct mmu_sglist *)
-						     SCptr->buffer,
-						     SCptr->use_sg - 1,
-						     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+			if(!SCptr->use_sg) {
+			        if (esp->dma_mmu_release_scsi_one)
+			                esp->dma_mmu_release_scsi_one (esp, SCptr);
+			} else {
+			        if (esp->dma_mmu_release_scsi_sgl)
+			                esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+			}
 			SCptr->result = (DID_RESET << 16);
 
 			SCptr->scsi_done(SCptr);
@@ -3614,17 +3598,13 @@
 		if(esp->disconnected_SC) {
 			Scsi_Cmnd *SCptr;
 			while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
-				if(!SCptr->use_sg)
-#ifdef CONFIG_SCSI_SUNESP
-					mmu_release_scsi_one(SCptr->SCp.have_data_in,
-							     SCptr->request_bufflen,
-							     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-				else
-					mmu_release_scsi_sgl((struct mmu_sglist *)
-							     SCptr->buffer,
-							     SCptr->use_sg - 1,
-							     ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+				if(!SCptr->use_sg) {
+			                if (esp->dma_mmu_release_scsi_one)
+			                        esp->dma_mmu_release_scsi_one (esp, SCptr);
+				} else {
+			                if (esp->dma_mmu_release_scsi_sgl)
+			                        esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+				}
 				SCptr->result = (DID_RESET << 16);
 
 				SCptr->scsi_done(SCptr);
@@ -3671,7 +3651,9 @@
 repeat:
 	again = 0;
 	for_each_esp(esp) {
+#ifndef __mips__	    
 		if(((esp)->irq & 0xf) == irq) {
+#endif		    
 			if(esp->dma_irq_p(esp)) {
 				again = 1;
 
@@ -3683,7 +3665,9 @@
 
 				esp->dma_ints_on(esp);
 			}
+#ifndef __mips__		    
 		}
+#endif	    
 	}
 	if(again)
 		goto repeat;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/NCR53C9x.h linux/drivers/scsi/NCR53C9x.h
--- v2.1.105/linux/drivers/scsi/NCR53C9x.h	Thu Mar 26 15:57:03 1998
+++ linux/drivers/scsi/NCR53C9x.h	Sat Jun 13 13:28:34 1998
@@ -107,6 +107,15 @@
         (printk ("Internal ESP driver error in file %s, line %d\n", \
 		 __FILE__, __LINE__))
 
+/*
+ * padding for register structure
+ */
+#ifdef CONFIG_JAZZ_ESP
+#define EREGS_PAD(n)
+#else
+#define EREGS_PAD(n)    unchar n[3];
+#endif
+
 /* The ESP SCSI controllers have their register sets in three
  * "classes":
  *
@@ -124,44 +133,45 @@
 struct ESP_regs {
                                 /* Access    Description              Offset */
     volatile unchar esp_tclow;  /* rw  Low bits of the transfer count 0x00   */
-                                unchar tlpad1[3];
+                                EREGS_PAD(tlpad1);
     volatile unchar esp_tcmed;  /* rw  Mid bits of the transfer count 0x04   */
-                                unchar fdpad[3];
+                                EREGS_PAD(fdpad);
     volatile unchar esp_fdata;  /* rw  FIFO data bits                 0x08   */
-                                unchar cbpad[3];
+                                EREGS_PAD(cbpad);
     volatile unchar esp_cmd;    /* rw  SCSI command bits              0x0c   */
-                                unchar stpad[3];
+                                EREGS_PAD(stpad);
     volatile unchar esp_status; /* ro  ESP status register            0x10   */
 #define esp_busid   esp_status  /* wo  Bus ID for select/reselect     0x10   */
-                                unchar irqpd[3];
+                                EREGS_PAD(irqpd);
     volatile unchar esp_intrpt; /* ro  Kind of interrupt              0x14   */
 #define esp_timeo   esp_intrpt  /* wo  Timeout value for select/resel 0x14   */
-                                unchar sspad[3];
+                                EREGS_PAD(sspad);
     volatile unchar esp_sstep;  /* ro  Sequence step register         0x18   */
 #define esp_stp     esp_sstep   /* wo  Transfer period per sync       0x18   */
-                                unchar ffpad[3];
+                                EREGS_PAD(ffpad);
     volatile unchar esp_fflags; /* ro  Bits of current FIFO info      0x1c   */
 #define esp_soff    esp_fflags  /* wo  Sync offset                    0x1c   */
-                                unchar cf1pd[3];
+                                EREGS_PAD(cf1pd);
     volatile unchar esp_cfg1;   /* rw  First configuration register   0x20   */
-                                unchar cfpad[3];
+                                EREGS_PAD(cfpad);
     volatile unchar esp_cfact;  /* wo  Clock conversion factor        0x24   */
 #define esp_status2 esp_cfact   /* ro  HME status2 register           0x24   */
-                                unchar ctpad[3];
+                                EREGS_PAD(ctpad);
     volatile unchar esp_ctest;  /* wo  Chip test register             0x28   */
-                                unchar cf2pd[3];
+                                EREGS_PAD(cf2pd);
     volatile unchar esp_cfg2;   /* rw  Second configuration register  0x2c   */
-                                unchar cf3pd[3];
+                                EREGS_PAD(cf3pd);
 
     /* The following is only found on the 53C9X series SCSI chips */
     volatile unchar esp_cfg3;   /* rw  Third configuration register   0x30  */
-                                unchar thpd[7];
-
+                                EREGS_PAD(holep);
+    volatile unchar esp_hole;   /* hole in register map               0x34  */
+                                EREGS_PAD(thpd);    
     /* The following is found on all chips except the NCR53C90 (ESP100) */
     volatile unchar esp_tchi;   /* rw  High bits of transfer count    0x38  */
 #define esp_uid     esp_tchi    /* ro  Unique ID code                 0x38  */
 #define fas_rlo     esp_tchi    /* rw  HME extended counter           0x38  */
-                                unchar fgpad[3];
+                                EREGS_PAD(fgpad);    
     volatile unchar esp_fgrnd;  /* rw  Data base for fifo             0x3c  */
 #define fas_rhi     esp_fgrnd   /* rw  HME extended counter           0x3c  */
 };
@@ -175,7 +185,8 @@
   fas100a    = 0x04,
   fast       = 0x05,
   fashme     = 0x06,
-  espunknown = 0x07
+  fas216     = 0x07,    
+  espunknown = 0x08
 };
 
 /* We get one of these for each ESP probed. */
@@ -303,6 +314,13 @@
   void (*dma_led_on)(struct NCR_ESP *);
   void (*dma_poll)(struct NCR_ESP *, unsigned char *);
   void (*dma_reset)(struct NCR_ESP *);
+    
+  /* Optional virtual DMA functions */
+  void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_advance_sg)(Scsi_Cmnd *);
 };
 
 /* Bitfield meanings for the above registers. */
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.1.105/linux/drivers/scsi/aha1542.c	Tue Jun  9 11:57:30 1998
+++ linux/drivers/scsi/aha1542.c	Tue Jun  9 01:21:50 1998
@@ -223,7 +223,7 @@
 
 /* Similar to aha1542_in, except that we wait a very short period of time.
    We use this if we know the board is alive and awake, but we are not sure
-   if the board will respond the command we are about to send or not */
+   if the board will respond to the command we are about to send or not */
 static int aha1542_in1(unsigned int base, unchar *cmdp, int len)
 {
     unsigned long flags;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c
--- v2.1.105/linux/drivers/scsi/blz1230.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/blz1230.c	Sat Jun 13 13:23:01 1998
@@ -130,6 +130,7 @@
 		esp->eregs = eregs;
 
 		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
 		esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/blz1230.h linux/drivers/scsi/blz1230.h
--- v2.1.105/linux/drivers/scsi/blz1230.h	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/blz1230.h	Sat Jun 13 13:49:32 1998
@@ -56,27 +56,17 @@
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
 
-#define SCSI_BLZ1230 {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Blizzard1230 SCSI IV", \
-/* int detect(struct SHT *) */                                 blz1230_esp_detect,             \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_BLZ1230      { proc_dir:		&proc_scsi_esp, \
+			    name:		"Blizzard1230 SCSI IV", \
+			    detect:		blz1230_esp_detect, \
+			    release:		NULL, \
+			    queuecommand:	esp_queue, \
+			    abort:		esp_abort, \
+			    reset:		esp_reset, \
+			    can_queue:          7, \
+			    this_id:		7, \
+			    sg_tablesize:	SG_ALL, \
+			    cmd_per_lun:	1, \
+			    use_clustering:	DISABLE_CLUSTERING }
 
 #endif /* BLZ1230_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c
--- v2.1.105/linux/drivers/scsi/blz2060.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/blz2060.c	Sat Jun 13 13:23:01 1998
@@ -106,6 +106,7 @@
 		esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
 		
 		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
 		esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/blz2060.h linux/drivers/scsi/blz2060.h
--- v2.1.105/linux/drivers/scsi/blz2060.h	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/blz2060.h	Sat Jun 13 13:49:32 1998
@@ -52,27 +52,17 @@
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
 
-#define SCSI_BLZ2060 {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Blizzard2060 SCSI", \
-/* int detect(struct SHT *) */                                 blz2060_esp_detect,             \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_BLZ2060      { proc_dir:		&proc_scsi_esp, \
+			    name:		"Blizzard2060 SCSI", \
+			    detect:		blz2060_esp_detect, \
+			    release:		NULL, \
+			    queuecommand:	esp_queue, \
+			    abort:		esp_abort, \
+			    reset:		esp_reset, \
+			    can_queue:          7, \
+			    this_id:		7, \
+			    sg_tablesize:	SG_ALL, \
+			    cmd_per_lun:	1, \
+			    use_clustering:	DISABLE_CLUSTERING }
 
 #endif /* BLZ2060_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c
--- v2.1.105/linux/drivers/scsi/cyberstorm.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/cyberstorm.c	Sat Jun 13 13:23:01 1998
@@ -126,6 +126,7 @@
 		esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
 		
 		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
 		esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/cyberstorm.h linux/drivers/scsi/cyberstorm.h
--- v2.1.105/linux/drivers/scsi/cyberstorm.h	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/cyberstorm.h	Sat Jun 13 13:49:32 1998
@@ -55,28 +55,18 @@
 			 int hostno, int inout);
 
 
-#define SCSI_CYBERSTORM {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "CyberStorm SCSI", \
-/* int detect(struct SHT *) */                                 cyber_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORM   { proc_dir:		&proc_scsi_esp, \
+			    name:		"CyberStorm SCSI", \
+			    detect:		cyber_esp_detect, \
+			    release:		NULL, \
+			    queuecommand:	esp_queue, \
+			    abort:		esp_abort, \
+			    reset:		esp_reset, \
+			    can_queue:          7, \
+			    this_id:		7, \
+			    sg_tablesize:	SG_ALL, \
+			    cmd_per_lun:	1, \
+			    use_clustering:	DISABLE_CLUSTERING }
 
 #endif /* CYBER_ESP_H */
 
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c
--- v2.1.105/linux/drivers/scsi/cyberstormII.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/cyberstormII.c	Sat Jun 13 13:23:01 1998
@@ -117,6 +117,7 @@
 		esp->eregs = eregs;
 		
 		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
 		esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/cyberstormII.h linux/drivers/scsi/cyberstormII.h
--- v2.1.105/linux/drivers/scsi/cyberstormII.h	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/cyberstormII.h	Sat Jun 13 13:49:32 1998
@@ -42,28 +42,18 @@
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
 
-#define SCSI_CYBERSTORMII {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "CyberStorm Mk II SCSI", \
-/* int detect(struct SHT *) */                                 cyberII_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORMII { proc_dir:		&proc_scsi_esp, \
+			    name:		"CyberStorm Mk II SCSI", \
+			    detect:		cyberII_esp_detect, \
+			    release:		NULL, \
+			    queuecommand:	esp_queue, \
+			    abort:		esp_abort, \
+			    reset:		esp_reset, \
+			    can_queue:          7, \
+			    this_id:		7, \
+			    sg_tablesize:	SG_ALL, \
+			    cmd_per_lun:	1, \
+			    use_clustering:	DISABLE_CLUSTERING }
 
 #endif /* CYBERII_ESP_H */
 
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c
--- v2.1.105/linux/drivers/scsi/fastlane.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/fastlane.c	Sat Jun 13 13:23:01 1998
@@ -5,8 +5,8 @@
  * This driver is based on the CyberStorm driver, hence the occasional
  * reference to CyberStorm.
  *
- * Betatesting & crucial adjustments by Patrik Rak 
- * (prak3264@ss1000.ms.mff.cuni.cz)
+ * Betatesting & crucial adjustments by
+ *        Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
  *
  */
 
@@ -43,8 +43,11 @@
 
 #include <asm/pgtable.h>
 
+/* Such day has just come... */
+#if 0
 /* Let this defined unless you really need to enable DMA IRQ one day */
 #define NODMAIRQ
+#endif
 
 static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
 static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
@@ -55,6 +58,7 @@
 static void dma_ints_off(struct NCR_ESP *esp);
 static void dma_ints_on(struct NCR_ESP *esp);
 static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_irq_exit(struct NCR_ESP *esp);
 static void dma_led_off(struct NCR_ESP *esp);
 static void dma_led_on(struct NCR_ESP *esp);
 static int  dma_ports_p(struct NCR_ESP *esp);
@@ -113,7 +117,7 @@
 		esp->dma_drain = 0;
 		esp->dma_invalidate = 0;
 		esp->dma_irq_entry = 0;
-		esp->dma_irq_exit = 0;
+		esp->dma_irq_exit = &dma_irq_exit;
 		esp->dma_led_on = &dma_led_on;
 		esp->dma_led_off = &dma_led_off;
 		esp->dma_poll = 0;
@@ -158,6 +162,7 @@
 		esp->edev = (void *) address;
 		
 		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
 		esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
@@ -278,39 +283,34 @@
 	enable_irq(esp->irq);
 }
 
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+	struct fastlane_dma_registers *dregs = 
+		(struct fastlane_dma_registers *) (esp->dregs);
+
+	dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+	nop();
+	dregs->ctrl_reg = ctrl_data;
+}
+
 static int dma_irq_p(struct NCR_ESP *esp)
 {
 	struct fastlane_dma_registers *dregs = 
 		(struct fastlane_dma_registers *) (esp->dregs);
-#if 0
 	unsigned char dma_status;
-	int r = 0;
 
 	dma_status = dregs->cond_reg;
 
 	if(dma_status & FASTLANE_DMA_IACT)
 		return 0;	/* not our IRQ */
 
-	/* Return 1 if ESP requested IRQ */
-	if(
+	/* Return non-zero if ESP requested IRQ */
+	return (
 #ifndef NODMAIRQ
 	   (dma_status & FASTLANE_DMA_CREQ) &&
 #endif
 	   (!(dma_status & FASTLANE_DMA_MINT)) &&
-	   ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR))
-		r = 1;
-
-	dregs->ctrl_reg = (ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI) );
-	dregs->ctrl_reg = ctrl_data;
-
-	return r;
-#else
-	int r;
-	r = (((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR;
-	dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
-	dregs->ctrl_reg = ctrl_data;
-	return r;
-#endif
+	   ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
 }
 
 static void dma_led_off(struct NCR_ESP *esp)
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/fastlane.h linux/drivers/scsi/fastlane.h
--- v2.1.105/linux/drivers/scsi/fastlane.h	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/fastlane.h	Sat Jun 13 13:49:32 1998
@@ -47,27 +47,17 @@
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
 
-#define SCSI_FASTLANE {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Fastlane SCSI", \
-/* int detect(struct SHT *) */                                 fastlane_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_FASTLANE     { proc_dir:		&proc_scsi_esp, \
+			    name:		"Fastlane SCSI", \
+			    detect:		fastlane_esp_detect, \
+			    release:		NULL, \
+			    queuecommand:	esp_queue, \
+			    abort:		esp_abort, \
+			    reset:		esp_reset, \
+			    can_queue:          7, \
+			    this_id:		7, \
+			    sg_tablesize:	SG_ALL, \
+			    cmd_per_lun:	1, \
+			    use_clustering:	DISABLE_CLUSTERING }
 
 #endif /* FASTLANE_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.105/linux/drivers/scsi/hosts.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/hosts.c	Sat Jun 13 12:59:15 1998
@@ -237,6 +237,29 @@
 #include "scsi_debug.h"
 #endif
 
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+#include "../acorn/scsi/acornscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_1
+#include "../acorn/scsi/cumana_1.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_2
+#include "../acorn/scsi/cumana_2.h"
+#endif
+
+#ifdef CONFIG_SCSI_ECOSCSI
+#include "../acorn/scsi/ecoscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_OAK1
+#include "../acorn/scsi/oak.h"
+#endif
+
+#ifdef CONFIG_SCSI_POWERTECSCSI
+#include "../acorn/scsi/powertec.h"
+#endif
 
 /*
 static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
@@ -423,6 +446,26 @@
 #endif
 #ifdef CONFIG_SCSI_PLUTO
     PLUTO,
+#endif
+#ifdef CONFIG_ARCH_ACORN
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+    ACORNSCSI_3,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_1
+    CUMANA_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_2
+    CUMANA_FAS216,
+#endif
+#ifdef CONFIG_SCSI_ECOSCSI
+    ECOSCSI_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_OAK1
+    OAK_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_POWERTECSCSI
+    POWERTECSCSI,
+#endif
 #endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.105/linux/drivers/scsi/ncr53c8xx.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/ncr53c8xx.c	Tue Jun  9 01:21:50 1998
@@ -369,8 +369,8 @@
 
 static void DELAY(long us)
 {
-	if (us/1000) mdelay(us/1000);
-	if (us%1000) udelay(us%1000);
+	for (;us>1000;us-=1000) udelay(1000);
+	if (us) udelay(us);
 }
 
 /*
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.1.105/linux/drivers/scsi/scsi_obsolete.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/scsi_obsolete.c	Sat Jun 13 13:25:12 1998
@@ -79,7 +79,7 @@
 static int scsi_reset (Scsi_Cmnd *, unsigned int);
 
 extern void scsi_old_done (Scsi_Cmnd *SCpnt);
-static int update_timeout (Scsi_Cmnd *, int);
+int update_timeout (Scsi_Cmnd *, int);
 extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
 extern void internal_cmnd (Scsi_Cmnd * SCpnt);
 
@@ -1058,7 +1058,7 @@
  * set the timer, we want to take this value into account.
  */
 
-static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+int update_timeout(Scsi_Cmnd * SCset, int timeout)
 {
   int	rtn;
 
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v2.1.105/linux/drivers/scsi/scsi_proc.c	Mon Feb 23 18:12:07 1998
+++ linux/drivers/scsi/scsi_proc.c	Sat Jun 13 12:10:31 1998
@@ -184,9 +184,9 @@
     
     if (!buf || !cmdList)                           /* bad input ?     */
 	return(NULL);
-    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
+    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
 	return(NULL);                               /* out of memory   */
-    if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
+    if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
 	kfree(handle);
 	return(NULL);                               /* out of memory   */
     }
diff -u --recursive --new-file v2.1.105/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.105/linux/drivers/scsi/sr_ioctl.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/sr_ioctl.c	Fri Jun 12 22:31:48 1998
@@ -93,7 +93,14 @@
                     printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
 		if (retries++ < 10) {
 		    /* sleep 2 sec and try again */
+		    /*
+		     * The spinlock is silly - we should really lock more of this
+		     * function, but the minimal locking required to not lock up
+		     * is around this - scsi_sleep() assumes we hold the spinlock.
+		     */
+		    spin_lock_irqsave(&io_request_lock, flags);
 		    scsi_sleep(2*HZ);
+		    spin_unlock_irqrestore(&io_request_lock, flags);
                     goto retry;
 		} else {
 		    /* 20 secs are enouth? */
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.105/linux/drivers/sound/Config.in	Tue Jun  9 11:57:30 1998
+++ linux/drivers/sound/Config.in	Sat Jun 13 10:23:52 1998
@@ -137,6 +137,19 @@
   	string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE
       fi
   fi
+
+  if [ "$CONFIG_SOUND" = "m" ]; then
+    dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
+    if [ "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
+       string '  Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE
+       string '  Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE
+    fi
+    dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND
+    if [ "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
+       string '  Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE
+       string '  Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE
+    fi
+  fi
   
   dep_tristate 'Support for Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_SGALAXY" = "y" ]; then
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.1.105/linux/drivers/sound/Makefile	Tue Jun  9 11:57:30 1998
+++ linux/drivers/sound/Makefile	Sat Jun 13 10:23:52 1998
@@ -23,8 +23,9 @@
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs	:=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
-		    opl3.o sb_card.o sequencer_syms.o sound_core.o \
-		    sound_firmware.o sound_syms.o uart401.o
+		    msnd.o opl3.o sb_card.o sequencer_syms.o \
+		    sound_core.o sound_firmware.o sound_syms.o \
+		    uart401.o
 
 
 
@@ -53,6 +54,8 @@
 obj-$(CONFIG_SOUND_MAD16)	+= mad16.o ad1848.o sb.o uart401.o
 obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
+obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
+obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_MSS)		+= ad1848.o
 obj-$(CONFIG_SOUND_OPL3SA1)	+= opl3sa.o ad1848.o uart401.o
 obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb.o uart401.o
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.1.105/linux/drivers/sound/dmasound.c	Wed Apr  8 19:36:27 1998
+++ linux/drivers/sound/dmasound.c	Sat Jun 13 13:23:01 1998
@@ -4,6 +4,7 @@
 /*
 
 OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
+Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
 
 (c) 1995 by Michael Schlueter & Michael Marte
 
@@ -85,7 +86,9 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
@@ -100,10 +103,23 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#endif /* CONFIG_PMAC_PBOOK */
+#include "awacs_defs.h"
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#endif /* CONFIG_PMAC */
 
 #include "dmasound.h"
 #include <linux/soundcard.h>
 
+#define HAS_8BIT_TABLES
 
 #ifdef MODULE
 static int chrdev_registered = 0;
@@ -143,6 +159,90 @@
 
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep.  The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+	0,	40,	79,	117,	153,	187,	218,	245,
+	269,	288,	304,	316,	323,	327,	327,	324,
+	318,	310,	299,	288,	275,	262,	249,	236,
+	224,	213,	204,	196,	190,	186,	183,	182,
+	182,	183,	186,	189,	192,	196,	200,	203,
+	206,	208,	209,	209,	209,	207,	204,	201,
+	197,	193,	188,	183,	179,	174,	170,	166,
+	163,	161,	160,	159,	159,	160,	161,	162,
+	164,	166,	168,	169,	171,	171,	171,	170,
+	169,	167,	163,	159,	155,	150,	144,	139,
+	133,	128,	122,	117,	113,	110,	107,	105,
+	103,	103,	103,	103,	104,	104,	105,	105,
+	105,	103,	101,	97,	92,	86,	78,	68,
+	58,	45,	32,	18,	3,	-11,	-26,	-41,
+	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
+	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
+	0,	16,	33,	48,	62,	75,	85,	93,
+	99,	102,	102,	100,	95,	88,	79,	68,
+	55,	41,	26,	11,	-3,	-18,	-32,	-45,
+	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
+	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
+	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
+	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
+	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
+	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
+	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
+	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
+	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
+	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
+	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
+	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
+	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
+};
+
+#define BEEP_SPEED	2	/* 22050 Hz sample rate */
+#define BEEP_BUFLEN	512
+#define BEEP_VOLUME	15	/* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct notifier_block *, unsigned long, void *);
+struct notifier_block awacs_sleep_notifier = {
+	awacs_sleep_notify
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
 
 /*** Some declarations *******************************************************/
 
@@ -150,6 +250,7 @@
 #define DMASND_TT		1
 #define DMASND_FALCON		2
 #define DMASND_AMIGA		3
+#define DMASND_AWACS		4
 
 #define MAX_CATCH_RADIUS	10
 #define MIN_BUFFERS		4
@@ -165,164 +266,164 @@
 #define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
 
 #define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
-      if (error) return error; \
- } while (0)
+	do { int error = get_user(ret, (int *)(arg)); \
+		if (error) return error; \
+	} while (0)
 #define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
 
 
 /*** Some low level helpers **************************************************/
 
-
+#ifdef HAS_8BIT_TABLES
 /* 8 bit mu-law */
 
 static char ulaw2dma8[] = {
-    -126,   -122,   -118,   -114,   -110,   -106,   -102,    -98,
-     -94,    -90,    -86,    -82,    -78,    -74,    -70,    -66,
-     -63,    -61,    -59,    -57,    -55,    -53,    -51,    -49,
-     -47,    -45,    -43,    -41,    -39,    -37,    -35,    -33,
-     -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,
-     -23,    -22,    -21,    -20,    -19,    -18,    -17,    -16,
-     -16,    -15,    -15,    -14,    -14,    -13,    -13,    -12,
-     -12,    -11,    -11,    -10,    -10,     -9,     -9,     -8,
-      -8,     -8,     -7,     -7,     -7,     -7,     -6,     -6,
-      -6,     -6,     -5,     -5,     -5,     -5,     -4,     -4,
-      -4,     -4,     -4,     -4,     -3,     -3,     -3,     -3,
-      -3,     -3,     -3,     -3,     -2,     -2,     -2,     -2,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,      0,
-     125,    121,    117,    113,    109,    105,    101,     97,
-      93,     89,     85,     81,     77,     73,     69,     65,
-      62,     60,     58,     56,     54,     52,     50,     48,
-      46,     44,     42,     40,     38,     36,     34,     32,
-      30,     29,     28,     27,     26,     25,     24,     23,
-      22,     21,     20,     19,     18,     17,     16,     15,
-      15,     14,     14,     13,     13,     12,     12,     11,
-      11,     10,     10,      9,      9,      8,      8,      7,
-       7,      7,      6,      6,      6,      6,      5,      5,
-       5,      5,      4,      4,      4,      4,      3,      3,
-       3,      3,      3,      3,      2,      2,      2,      2,
-       2,      2,      2,      2,      1,      1,      1,      1,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0
+	-126,	-122,	-118,	-114,	-110,	-106,	-102,	-98,
+	-94,	-90,	-86,	-82,	-78,	-74,	-70,	-66,
+	-63,	-61,	-59,	-57,	-55,	-53,	-51,	-49,
+	-47,	-45,	-43,	-41,	-39,	-37,	-35,	-33,
+	-31,	-30,	-29,	-28,	-27,	-26,	-25,	-24,
+	-23,	-22,	-21,	-20,	-19,	-18,	-17,	-16,
+	-16,	-15,	-15,	-14,	-14,	-13,	-13,	-12,
+	-12,	-11,	-11,	-10,	-10,	-9,	-9,	-8,
+	-8,	-8,	-7,	-7,	-7,	-7,	-6,	-6,
+	-6,	-6,	-5,	-5,	-5,	-5,	-4,	-4,
+	-4,	-4,	-4,	-4,	-3,	-3,	-3,	-3,
+	-3,	-3,	-3,	-3,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	0,
+	125,	121,	117,	113,	109,	105,	101,	97,
+	93,	89,	85,	81,	77,	73,	69,	65,
+	62,	60,	58,	56,	54,	52,	50,	48,
+	46,	44,	42,	40,	38,	36,	34,	32,
+	30,	29,	28,	27,	26,	25,	24,	23,
+	22,	21,	20,	19,	18,	17,	16,	15,
+	15,	14,	14,	13,	13,	12,	12,	11,
+	11,	10,	10,	9,	9,	8,	8,	7,
+	7,	7,	6,	6,	6,	6,	5,	5,
+	5,	5,	4,	4,	4,	4,	3,	3,
+	3,	3,	3,	3,	2,	2,	2,	2,
+	2,	2,	2,	2,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0
 };
 
 /* 8 bit A-law */
 
 static char alaw2dma8[] = {
-     -22,    -21,    -24,    -23,    -18,    -17,    -20,    -19,
-     -30,    -29,    -32,    -31,    -26,    -25,    -28,    -27,
-     -11,    -11,    -12,    -12,     -9,     -9,    -10,    -10,
-     -15,    -15,    -16,    -16,    -13,    -13,    -14,    -14,
-     -86,    -82,    -94,    -90,    -70,    -66,    -78,    -74,
-    -118,   -114,   -126,   -122,   -102,    -98,   -110,   -106,
-     -43,    -41,    -47,    -45,    -35,    -33,    -39,    -37,
-     -59,    -57,    -63,    -61,    -51,    -49,    -55,    -53,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -6,     -6,     -6,     -6,     -5,     -5,     -5,     -5,
-      -8,     -8,     -8,     -8,     -7,     -7,     -7,     -7,
-      -3,     -3,     -3,     -3,     -3,     -3,     -3,     -3,
-      -4,     -4,     -4,     -4,     -4,     -4,     -4,     -4,
-      21,     20,     23,     22,     17,     16,     19,     18,
-      29,     28,     31,     30,     25,     24,     27,     26,
-      10,     10,     11,     11,      8,      8,      9,      9,
-      14,     14,     15,     15,     12,     12,     13,     13,
-      86,     82,     94,     90,     70,     66,     78,     74,
-     118,    114,    126,    122,    102,     98,    110,    106,
-      43,     41,     47,     45,     35,     33,     39,     37,
-      59,     57,     63,     61,     51,     49,     55,     53,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       5,      5,      5,      5,      4,      4,      4,      4,
-       7,      7,      7,      7,      6,      6,      6,      6,
-       2,      2,      2,      2,      2,      2,      2,      2,
-       3,      3,      3,      3,      3,      3,      3,      3
+	-22,	-21,	-24,	-23,	-18,	-17,	-20,	-19,
+	-30,	-29,	-32,	-31,	-26,	-25,	-28,	-27,
+	-11,	-11,	-12,	-12,	-9,	-9,	-10,	-10,
+	-15,	-15,	-16,	-16,	-13,	-13,	-14,	-14,
+	-86,	-82,	-94,	-90,	-70,	-66,	-78,	-74,
+	-118,	-114,	-126,	-122,	-102,	-98,	-110,	-106,
+	-43,	-41,	-47,	-45,	-35,	-33,	-39,	-37,
+	-59,	-57,	-63,	-61,	-51,	-49,	-55,	-53,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-6,	-6,	-6,	-6,	-5,	-5,	-5,	-5,
+	-8,	-8,	-8,	-8,	-7,	-7,	-7,	-7,
+	-3,	-3,	-3,	-3,	-3,	-3,	-3,	-3,
+	-4,	-4,	-4,	-4,	-4,	-4,	-4,	-4,
+	21,	20,	23,	22,	17,	16,	19,	18,
+	29,	28,	31,	30,	25,	24,	27,	26,
+	10,	10,	11,	11,	8,	8,	9,	9,
+	14,	14,	15,	15,	12,	12,	13,	13,
+	86,	82,	94,	90,	70,	66,	78,	74,
+	118,	114,	126,	122,	102,	98,	110,	106,
+	43,	41,	47,	45,	35,	33,	39,	37,
+	59,	57,	63,	61,	51,	49,	55,	53,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	5,	5,	5,	5,	4,	4,	4,	4,
+	7,	7,	7,	7,	6,	6,	6,	6,
+	2,	2,	2,	2,	2,	2,	2,	2,
+	3,	3,	3,	3,	3,	3,	3,	3
 };
-
+#endif /* HAS_8BIT_TABLES */
 
 #ifdef HAS_16BIT_TABLES
 
 /* 16 bit mu-law */
 
-static char ulaw2dma16[] = {
-    -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-    -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-    -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-    -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
-     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
-     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
-     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
-     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
-     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
-     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
-      -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
-      -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
-      -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
-      -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
-      -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
-       -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
-     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
-     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
-     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
-     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
-      7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
-      5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
-      3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
-      2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
-      1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
-      1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
-       876,    844,    812,    780,    748,    716,    684,    652,
-       620,    588,    556,    524,    492,    460,    428,    396,
-       372,    356,    340,    324,    308,    292,    276,    260,
-       244,    228,    212,    196,    180,    164,    148,    132,
-       120,    112,    104,     96,     88,     80,     72,     64,
-        56,     48,     40,     32,     24,     16,      8,      0,
+static short ulaw2dma16[] = {
+	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
+	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
+	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
+	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
+	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
+	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
+	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
+	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
+	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
+	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
+	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
+	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
+	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
+	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
+	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
+	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
+	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
+	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
+	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
+	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
+	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
+	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
+	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
+	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
+	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
+	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
+	876,	844,	812,	780,	748,	716,	684,	652,
+	620,	588,	556,	524,	492,	460,	428,	396,
+	372,	356,	340,	324,	308,	292,	276,	260,
+	244,	228,	212,	196,	180,	164,	148,	132,
+	120,	112,	104,	96,	88,	80,	72,	64,
+	56,	48,	40,	32,	24,	16,	8,	0,
 };
 
 /* 16 bit A-law */
 
-static char alaw2dma16[] = {
-     -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
-     -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
-     -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
-     -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
-    -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-    -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-    -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
-    -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-      -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
-      -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
-       -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
-      -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
-     -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
-     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
-      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
-      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
-      5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
-      7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
-      2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
-      3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
-     22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
-     30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
-     11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
-     15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
-       344,    328,    376,    360,    280,    264,    312,    296,
-       472,    456,    504,    488,    408,    392,    440,    424,
-        88,     72,    120,    104,     24,      8,     56,     40,
-       216,    200,    248,    232,    152,    136,    184,    168,
-      1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
-      1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
-       688,    656,    752,    720,    560,    528,    624,    592,
-       944,    912,   1008,    976,    816,    784,    880,    848,
+static short alaw2dma16[] = {
+	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
+	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
+	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
+	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
+	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
+	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
+	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
+	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
+	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
+	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
+	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
+	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
+	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
+	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
+	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
+	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
+	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
+	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
+	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
+	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
+	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
+	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
+	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
+	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
+	344,	328,	376,	360,	280,	264,	312,	296,
+	472,	456,	504,	488,	408,	392,	440,	424,
+	88,	72,	120,	104,	24,	8,	56,	40,
+	216,	200,	248,	232,	152,	136,	184,	168,
+	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
+	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
+	688,	656,	752,	720,	560,	528,	624,	592,
+	944,	912,	1008,	976,	816,	784,	880,	848,
 };
 #endif /* HAS_16BIT_TABLES */
 
@@ -332,75 +433,75 @@
 /* 14 bit mu-law (LSB) */
 
 static char alaw2dma14l[] = {
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-         1,      1,      1,      1,      1,      1,      1,      1,
-         1,      1,      1,      1,      1,      1,      1,      1,
-        49,     17,     49,     17,     49,     17,     49,     17,
-        49,     17,     49,     17,     49,     17,     49,     17,
-        41,     57,      9,     25,     41,     57,      9,     25,
-        41,     57,      9,     25,     41,     57,      9,     25,
-        37,     45,     53,     61,      5,     13,     21,     29,
-        37,     45,     53,     61,      5,     13,     21,     29,
-        35,     39,     43,     47,     51,     55,     59,     63,
-         3,      7,     11,     15,     19,     23,     27,     31,
-        34,     36,     38,     40,     42,     44,     46,     48,
-        50,     52,     54,     56,     58,     60,     62,      0,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        63,     63,     63,     63,     63,     63,     63,     63,
-        63,     63,     63,     63,     63,     63,     63,     63,
-        15,     47,     15,     47,     15,     47,     15,     47,
-        15,     47,     15,     47,     15,     47,     15,     47,
-        23,      7,     55,     39,     23,      7,     55,     39,
-        23,      7,     55,     39,     23,      7,     55,     39,
-        27,     19,     11,      3,     59,     51,     43,     35,
-        27,     19,     11,      3,     59,     51,     43,     35,
-        29,     25,     21,     17,     13,      9,      5,      1,
-        61,     57,     53,     49,     45,     41,     37,     33,
-        30,     28,     26,     24,     22,     20,     18,     16,
-        14,     12,     10,      8,      6,      4,      2,      0
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	33,	33,	33,	33,	33,	33,	33,	33,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	49,	17,	49,	17,	49,	17,	49,	17,
+	49,	17,	49,	17,	49,	17,	49,	17,
+	41,	57,	9,	25,	41,	57,	9,	25,
+	41,	57,	9,	25,	41,	57,	9,	25,
+	37,	45,	53,	61,	5,	13,	21,	29,
+	37,	45,	53,	61,	5,	13,	21,	29,
+	35,	39,	43,	47,	51,	55,	59,	63,
+	3,	7,	11,	15,	19,	23,	27,	31,
+	34,	36,	38,	40,	42,	44,	46,	48,
+	50,	52,	54,	56,	58,	60,	62,	0,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	31,	31,	31,	31,	31,	31,	31,	31,
+	63,	63,	63,	63,	63,	63,	63,	63,
+	63,	63,	63,	63,	63,	63,	63,	63,
+	15,	47,	15,	47,	15,	47,	15,	47,
+	15,	47,	15,	47,	15,	47,	15,	47,
+	23,	7,	55,	39,	23,	7,	55,	39,
+	23,	7,	55,	39,	23,	7,	55,	39,
+	27,	19,	11,	3,	59,	51,	43,	35,
+	27,	19,	11,	3,	59,	51,	43,	35,
+	29,	25,	21,	17,	13,	9,	5,	1,
+	61,	57,	53,	49,	45,	41,	37,	33,
+	30,	28,	26,	24,	22,	20,	18,	16,
+	14,	12,	10,	8,	6,	4,	2,	0
 };
 
 /* 14 bit A-law (LSB) */
 
 static char alaw2dma14l[] = {
-        32,     32,     32,     32,     32,     32,     32,     32,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        16,     48,     16,     48,     16,     48,     16,     48,
-        16,     48,     16,     48,     16,     48,     16,     48,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-        42,     46,     34,     38,     58,     62,     50,     54,
-        10,     14,      2,      6,     26,     30,     18,     22,
-        42,     46,     34,     38,     58,     62,     50,     54,
-        10,     14,      2,      6,     26,     30,     18,     22,
-        40,     56,      8,     24,     40,     56,      8,     24,
-        40,     56,      8,     24,     40,     56,      8,     24,
-        20,     28,      4,     12,     52,     60,     36,     44,
-        20,     28,      4,     12,     52,     60,     36,     44,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        48,     16,     48,     16,     48,     16,     48,     16,
-        48,     16,     48,     16,     48,     16,     48,     16,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-        22,     18,     30,     26,      6,      2,     14,     10,
-        54,     50,     62,     58,     38,     34,     46,     42,
-        22,     18,     30,     26,      6,      2,     14,     10,
-        54,     50,     62,     58,     38,     34,     46,     42,
-        24,      8,     56,     40,     24,      8,     56,     40,
-        24,      8,     56,     40,     24,      8,     56,     40,
-        44,     36,     60,     52,     12,      4,     28,     20,
-        44,     36,     60,     52,     12,      4,     28,     20
+	32,	32,	32,	32,	32,	32,	32,	32,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	16,	48,	16,	48,	16,	48,	16,	48,
+	16,	48,	16,	48,	16,	48,	16,	48,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	42,	46,	34,	38,	58,	62,	50,	54,
+	10,	14,	2,	6,	26,	30,	18,	22,
+	42,	46,	34,	38,	58,	62,	50,	54,
+	10,	14,	2,	6,	26,	30,	18,	22,
+	40,	56,	8,	24,	40,	56,	8,	24,
+	40,	56,	8,	24,	40,	56,	8,	24,
+	20,	28,	4,	12,	52,	60,	36,	44,
+	20,	28,	4,	12,	52,	60,	36,	44,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	32,	32,	32,	32,	32,	32,	32,	32,
+	48,	16,	48,	16,	48,	16,	48,	16,
+	48,	16,	48,	16,	48,	16,	48,	16,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	22,	18,	30,	26,	6,	2,	14,	10,
+	54,	50,	62,	58,	38,	34,	46,	42,
+	22,	18,	30,	26,	6,	2,	14,	10,
+	54,	50,	62,	58,	38,	34,	46,	42,
+	24,	8,	56,	40,	24,	8,	56,	40,
+	24,	8,	56,	40,	24,	8,	56,	40,
+	44,	36,	60,	52,	12,	4,	28,	20,
+	44,	36,	60,	52,	12,	4,	28,	20
 };
 #endif /* HAS_14BIT_TABLES */
 
@@ -456,26 +557,48 @@
 			 u_char frame[], long *frameUsed, long frameLeft);
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+#endif /* CONFIG_PMAC */
 
 /*** Machine definitions *****************************************************/
 
 
 typedef struct {
-    int type;
-    void *(*dma_alloc)(unsigned int, int);
-    void (*dma_free)(void *, unsigned int);
-    int (*irqinit)(void);
+	int type;
+	void *(*dma_alloc)(unsigned int, int);
+	void (*dma_free)(void *, unsigned int);
+	int (*irqinit)(void);
 #ifdef MODULE
-    void (*irqcleanup)(void);
+	void (*irqcleanup)(void);
 #endif /* MODULE */
-    void (*init)(void);
-    void (*silence)(void);
-    int (*setFormat)(int);
-    int (*setVolume)(int);
-    int (*setBass)(int);
-    int (*setTreble)(int);
-    int (*setGain)(int);
-    void (*play)(void);
+	void (*init)(void);
+	void (*silence)(void);
+	int (*setFormat)(int);
+	int (*setVolume)(int);
+	int (*setBass)(int);
+	int (*setTreble)(int);
+	int (*setGain)(int);
+	void (*play)(void);
 } MACHINE;
 
 
@@ -483,38 +606,38 @@
 
 
 typedef struct {
-    int format;		/* AFMT_* */
-    int stereo;		/* 0 = mono, 1 = stereo */
-    int size;		/* 8/16 bit*/
-    int speed;		/* speed */
+	int format;		/* AFMT_* */
+	int stereo;		/* 0 = mono, 1 = stereo */
+	int size;		/* 8/16 bit*/
+	int speed;		/* speed */
 } SETTINGS;
 
 typedef struct {
-    long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
+	long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
 } TRANS;
 
 struct sound_settings {
-    MACHINE mach;	/* machine dependent things */
-    SETTINGS hard;	/* hardware settings */
-    SETTINGS soft;	/* software settings */
-    SETTINGS dsp;	/* /dev/dsp default settings */
-    TRANS *trans;	/* supported translations */
-    int volume_left;	/* volume (range is machine dependent) */
-    int volume_right;
-    int bass;		/* tone (range is machine dependent) */
-    int treble;
-    int gain;
-    int minDev;		/* minor device number currently open */
-#ifdef CONFIG_ATARI
-    int bal;		/* balance factor for expanding (not volume!) */
-    u_long data;	/* data for expanding */
+	MACHINE mach;		/* machine dependent things */
+	SETTINGS hard;		/* hardware settings */
+	SETTINGS soft;		/* software settings */
+	SETTINGS dsp;		/* /dev/dsp default settings */
+	TRANS *trans;		/* supported translations */
+	int volume_left;	/* volume (range is machine dependent) */
+	int volume_right;
+	int bass;		/* tone (range is machine dependent) */
+	int treble;
+	int gain;
+	int minDev;		/* minor device number currently open */
+#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC)
+	int bal;		/* balance factor for expanding (not volume!) */
+	u_long data;		/* data for expanding */
 #endif /* CONFIG_ATARI */
 };
 
@@ -561,6 +684,26 @@
 static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif /* MODULE */
+static void PMacSilence(void);
+static void PMacInit(void);
+static void PMacPlay(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+#endif /* CONFIG_PMAC */
 
 /*** Mid level stuff *********************************************************/
 
@@ -574,7 +717,9 @@
 #ifdef CONFIG_ATARI
 static int sound_set_bass(int bass);
 #endif /* CONFIG_ATARI */
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 static int sound_set_treble(int treble);
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
 static long sound_copy_translate(const u_char *userPtr,
 				 unsigned long userCount,
 				 u_char frame[], long *frameUsed,
@@ -603,29 +748,30 @@
  */
 
 struct sound_queue {
-    int max_count, block_size;
-    char **buffers;
-
-    /* it shouldn't be necessary to declare any of these volatile */
-    int front, rear, count;
-    int rear_size;
-    /*
-     *	The use of the playing field depends on the hardware
-     *
-     *	Atari: The number of frames that are loaded/playing
-     *
-     *	Amiga: Bit 0 is set: a frame is loaded
-     *	       Bit 1 is set: a frame is playing
-     */
-    int playing;
-    struct wait_queue *write_queue, *open_queue, *sync_queue;
-    int open_mode;
-    int busy, syncing;
+	int max_count, block_size;
+	char **buffers;
+	int max_active;
+
+	/* it shouldn't be necessary to declare any of these volatile */
+	int front, rear, count;
+	int rear_size;
+	/*
+	 *	The use of the playing field depends on the hardware
+	 *
+	 *	Atari, PMac: The number of frames that are loaded/playing
+	 *
+	 *	Amiga: Bit 0 is set: a frame is loaded
+	 *	       Bit 1 is set: a frame is playing
+	 */
+	int playing;
+	struct wait_queue *write_queue, *open_queue, *sync_queue;
+	int open_mode;
+	int busy, syncing;
 #ifdef CONFIG_ATARI
-    int ignore_int;		/* ++TeSche: used for Falcon */
+	int ignore_int;		/* ++TeSche: used for Falcon */
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-    int block_size_half, block_size_quarter;
+	int block_size_half, block_size_quarter;
 #endif /* CONFIG_AMIGA */
 };
 
@@ -648,6 +794,7 @@
 static void sq_reset(void);
 static int sq_sync(void);
 static int sq_release(void);
+static void init_settings(void);
 
 
 /*
@@ -655,9 +802,9 @@
  */
 
 struct sound_state {
-    int busy;
-    char buf[512];
-    int len, ptr;
+	int busy;
+	char buf[512];
+	int len, ptr;
 };
 
 static struct sound_state state;
@@ -681,10 +828,10 @@
 			   loff_t *ppos);
 static inline int ioctl_return(int *addr, int value)
 {
-    if (value < 0)
-	return(value);
+	if (value < 0)
+		return(value);
 
-    return put_user(value, addr);
+	return put_user(value, addr)? -EFAULT: 0;
 }
 static int unknown_minor_dev(char *fname, int dev);
 static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
@@ -730,554 +877,581 @@
 static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
 		       u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    long count, used;
-    u_char *p = &frame[*frameUsed];
-
-    count = min(userCount, frameLeft);
-    if (sound.soft.stereo)
-	count &= ~1;
-    used = count;
-    while (count > 0) {
-	u_char data;
-	get_user(data, userPtr++);
-	*p++ = table[data];
-	count--;
-    }
-    *frameUsed += used;
-    return(used);
+	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+	long count, used;
+	u_char *p = &frame[*frameUsed];
+
+	count = min(userCount, frameLeft);
+	if (sound.soft.stereo)
+		count &= ~1;
+	used = count;
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		*p++ = table[data];
+		count--;
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
 		      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    void *p = &frame[*frameUsed];
+	long count, used;
+	void *p = &frame[*frameUsed];
 
-    count = min(userCount, frameLeft);
-    if (sound.soft.stereo)
-	count &= ~1;
-    used = count;
-    copy_from_user(p, userPtr, count);
-    *frameUsed += used;
-    return(used);
+	count = min(userCount, frameLeft);
+	if (sound.soft.stereo)
+		count &= ~1;
+	used = count;
+	if (copy_from_user(p, userPtr, count))
+		return -EFAULT;
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
 		      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
+	long count, used;
 
-    if (!sound.soft.stereo) {
-	u_char *p = &frame[*frameUsed];
-	count = min(userCount, frameLeft);
-	used = count;
-	while (count > 0) {
-	    u_char data;
-	    get_user(data, userPtr++);
-	    *p++ = data ^ 0x80;
-	    count--;
-	}
-    } else {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>1;
-	used = count*2;
-	while (count > 0) {
-	    u_short data;
-	    get_user(data, ((u_short *)userPtr)++);
-	    *p++ = data ^ 0x8080;
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft);
+		used = count;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*p++ = data ^ 0x80;
+			count--;
+		}
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			u_short data;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*p++ = data ^ 0x8080;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    *p++ = data;
-	    *p++ = data;
-	    count--;
-	}
-	*frameUsed += used*2;
-    } else {
-	void *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft) & ~3;
-	used = count;
-	copy_from_user(p, userPtr, count);
-	*frameUsed += used;
-    }
-    return(used);
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		void *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~3;
+		used = count;
+		if (copy_from_user(p, userPtr, count))
+			return -EFAULT;
+		*frameUsed += used;
+	}
+	return(used);
 }
 
 
 static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data ^= 0x8000;
-	    *p++ = data;
-	    *p++ = data;
-	    count--;
-	}
-	*frameUsed += used*2;
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>2;
-	used = count*4;
-	while (count > 0) {
-	    get_user(data, ((u_int *)userPtr)++);
-	    *p++ = data ^ 0x80008000;
-	    count--;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data ^= 0x8000;
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			*p++ = data ^ 0x80008000;
+			count--;
+		}
+		*frameUsed += used;
 	}
-	*frameUsed += used;
-    }
-    return(used);
+	return(used);
 }
 
 
 static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    count = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data);
-	    *p++ = data;
-	    *p++ = data;
-	    count--;
-	}
-	*frameUsed += used*2;
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>2;
-	used = count*4;
-	while (count > 0) {
-	    get_user(data, ((u_int *)userPtr)++);
-	    data = le2be16dbl(data);
-	    *p++ = data;
-	    count--;
+	count = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data);
+			*p++ = data;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			data = le2be16dbl(data);
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used;
 	}
-	*frameUsed += used;
-    }
-    return(used);
+	return(used);
 }
 
 
 static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    count = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data) ^ 0x8000;
-	    *p++ = data;
-	    *p++ = data;
-	}
-	*frameUsed += used*2;
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	count = min(userCount, frameLeft)>>2;
-	used = count;
-	while (count > 0) {
-	    get_user(data, ((u_int *)userPtr)++);
-	    data = le2be16dbl(data) ^ 0x80008000;
-	    *p++ = data;
-	    count--;
+	count = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data) ^ 0x8000;
+			*p++ = data;
+			*p++ = data;
+		}
+		*frameUsed += used*2;
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		count = min(userCount, frameLeft)>>2;
+		used = count;
+		while (count > 0) {
+			if (get_user(data, ((u_int *)userPtr)++))
+				return -EFAULT;
+			data = le2be16dbl(data) ^ 0x80008000;
+			*p++ = data;
+			count--;
+		}
+		*frameUsed += used;
 	}
-	*frameUsed += used;
-    }
-    return(used);
+	return(used);
 }
 
 
 static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
 			u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_char *p = &frame[*frameUsed];
-	while (frameLeft) {
-	    u_char c;
-	    if (bal < 0) {
-		if (!userCount)
-		    break;
-		get_user(c, userPtr++);
-		data = table[c];
-		userCount--;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft--;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 2) {
-	    u_char c;
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(c, userPtr++);
-		data = table[c] << 8;
-		get_user(c, userPtr++);
-		data |= table[c];
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 2;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		while (frameLeft) {
+			u_char c;
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = table[c];
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 2) {
+			u_char c;
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = table[c] << 8;
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data |= table[c];
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
 		       u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_char *p = &frame[*frameUsed];
-	while (frameLeft) {
-	    if (bal < 0) {
-		if (!userCount)
-		    break;
-		get_user(data, userPtr++);
-		userCount--;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft--;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 2) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 2;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		while (frameLeft) {
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(data, userPtr++))
+					return -EFAULT;
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 2) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
 		       u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_char *p = &frame[*frameUsed];
-	while (frameLeft) {
-	    if (bal < 0) {
-		if (!userCount)
-		    break;
-		get_user(data, userPtr++);
-		data ^= 0x80;
-		userCount--;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft--;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 2) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		data ^= 0x8080;
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 2;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		while (frameLeft) {
+			if (bal < 0) {
+				if (!userCount)
+					break;
+				if (get_user(data, userPtr++))
+					return -EFAULT;
+				data ^= 0x80;
+				userCount--;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft--;
+			bal -= sSpeed;
+		}
+	} else {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 2) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x8080;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 2;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
 			  u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 4)
-		    break;
-		get_user(data, ((u_int *)userPtr)++);
-		userCount -= 4;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
 			  u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		data ^= 0x8000;
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 4)
-		    break;
-		get_user(data, ((u_int *)userPtr)++);
-		data ^= 0x80008000;
-		userCount -= 4;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x8000;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data ^= 0x80008000;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
 			  u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		data = le2be16(data);
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 4)
-		    break;
-		get_user(data, ((u_int *)userPtr)++);
-		data = le2be16dbl(data);
-		userCount -= 4;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data = le2be16(data);
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data = le2be16dbl(data);
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 
 
 static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
 			  u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-	u_short *p = (u_short *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 2)
-		    break;
-		get_user(data, ((u_short *)userPtr)++);
-		data = le2be16(data) ^ 0x8000;
-		userCount -= 2;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    } else {
-	u_long *p = (u_long *)&frame[*frameUsed];
-	while (frameLeft >= 4) {
-	    if (bal < 0) {
-		if (userCount < 4)
-		    break;
-		get_user(data, ((u_int *)userPtr)++);
-		data = le2be16dbl(data) ^ 0x80008000;
-		userCount -= 4;
-		bal += hSpeed;
-	    }
-	    *p++ = data;
-	    frameLeft -= 4;
-	    bal -= sSpeed;
-	}
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+	/* this should help gcc to stuff everything into registers */
+	u_long data = sound.data;
+	long bal = sound.bal;
+	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	long used, usedf;
+
+	used = userCount;
+	usedf = frameLeft;
+	if (!sound.soft.stereo) {
+		u_short *p = (u_short *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 2)
+					break;
+				if (get_user(data, ((u_short *)userPtr)++))
+					return -EFAULT;
+				data = le2be16(data) ^ 0x8000;
+				userCount -= 2;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	} else {
+		u_long *p = (u_long *)&frame[*frameUsed];
+		while (frameLeft >= 4) {
+			if (bal < 0) {
+				if (userCount < 4)
+					break;
+				if (get_user(data, ((u_int *)userPtr)++))
+					return -EFAULT;
+				data = le2be16dbl(data) ^ 0x80008000;
+				userCount -= 4;
+				bal += hSpeed;
+			}
+			*p++ = data;
+			frameLeft -= 4;
+			bal -= sSpeed;
+		}
+	}
+	sound.bal = bal;
+	sound.data = data;
+	used -= userCount;
+	*frameUsed += usedf-frameLeft;
+	return(used);
 }
 #endif /* CONFIG_ATARI */
 
@@ -1286,291 +1460,698 @@
 static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
 		       u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    long count, used;
+	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+	long count, used;
 
-    if (!sound.soft.stereo) {
-	u_char *p = &frame[*frameUsed];
-	count = min(userCount, frameLeft) & ~1;
-	used = count;
-	while (count > 0) {
-	    u_char data;
-	    get_user(data, userPtr++);
-	    *p++ = table[data];
-	    count--;
-	}
-    } else {
-	u_char *left = &frame[*frameUsed>>1];
-	u_char *right = left+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    u_char data;
-	    get_user(data, userPtr++);
-	    *left++ = table[data];
-	    get_user(data, userPtr++);
-	    *right++ = table[data];
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		u_char *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~1;
+		used = count;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*p++ = table[data];
+			count--;
+		}
+	} else {
+		u_char *left = &frame[*frameUsed>>1];
+		u_char *right = left+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*left++ = table[data];
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*right++ = table[data];
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
 		      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
+	long count, used;
 
-    if (!sound.soft.stereo) {
-	void *p = &frame[*frameUsed];
-	count = min(userCount, frameLeft) & ~1;
-	used = count;
-	copy_from_user(p, userPtr, count);
-    } else {
-	u_char *left = &frame[*frameUsed>>1];
-	u_char *right = left+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(*left++, userPtr++);
-	    get_user(*right++, userPtr++);
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		void *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~1;
+		used = count;
+		if (copy_from_user(p, userPtr, count))
+			return -EFAULT;
+	} else {
+		u_char *left = &frame[*frameUsed>>1];
+		u_char *right = left+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(*left++, userPtr++)
+			    || get_user(*right++, userPtr++))
+				return -EFAULT;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
 		      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
+	long count, used;
 
-    if (!sound.soft.stereo) {
-	char *p = &frame[*frameUsed];
-	count = min(userCount, frameLeft) & ~1;
-	used = count;
-	while (count > 0) {
-	    u_char data;
-	    get_user(data, userPtr++);
-	    *p++ = data ^ 0x80;
-	    count--;
-	}
-    } else {
-	u_char *left = &frame[*frameUsed>>1];
-	u_char *right = left+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    u_char data;
-	    get_user(data, userPtr++);
-	    *left++ = data ^ 0x80;
-	    get_user(data, userPtr++);
-	    *right++ = data ^ 0x80;
-	    count--;
-        }
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		char *p = &frame[*frameUsed];
+		count = min(userCount, frameLeft) & ~1;
+		used = count;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*p++ = data ^ 0x80;
+			count--;
+		}
+	} else {
+		u_char *left = &frame[*frameUsed>>1];
+		u_char *right = left+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			u_char data;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*left++ = data ^ 0x80;
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			*right++ = data ^ 0x80;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    if (!sound.soft.stereo) {
-	u_char *high = &frame[*frameUsed>>1];
-	u_char *low = high+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    *high++ = data>>8;
-	    *low++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    } else {
-	u_char *lefth = &frame[*frameUsed>>2];
-	u_char *leftl = lefth+sq.block_size_quarter;
-	u_char *righth = lefth+sq.block_size_half;
-	u_char *rightl = righth+sq.block_size_quarter;
-	count = min(userCount, frameLeft)>>2 & ~1;
-	used = count*4;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    *lefth++ = data>>8;
-	    *leftl++ = (data>>2) & 0x3f;
-	    get_user(data, ((u_short *)userPtr)++);
-	    *righth++ = data>>8;
-	    *rightl++ = (data>>2) & 0x3f;
-	    count--;
-       }
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		u_char *high = &frame[*frameUsed>>1];
+		u_char *low = high+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*high++ = data>>8;
+			*low++ = (data>>2) & 0x3f;
+			count--;
+		}
+	} else {
+		u_char *lefth = &frame[*frameUsed>>2];
+		u_char *leftl = lefth+sq.block_size_quarter;
+		u_char *righth = lefth+sq.block_size_half;
+		u_char *rightl = righth+sq.block_size_quarter;
+		count = min(userCount, frameLeft)>>2 & ~1;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*lefth++ = data>>8;
+			*leftl++ = (data>>2) & 0x3f;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			*righth++ = data>>8;
+			*rightl++ = (data>>2) & 0x3f;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    if (!sound.soft.stereo) {
-	u_char *high = &frame[*frameUsed>>1];
-	u_char *low = high+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data ^= 0x8000;
-	    *high++ = data>>8;
-	    *low++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    } else {
-	u_char *lefth = &frame[*frameUsed>>2];
-	u_char *leftl = lefth+sq.block_size_quarter;
-	u_char *righth = lefth+sq.block_size_half;
-	u_char *rightl = righth+sq.block_size_quarter;
-	count = min(userCount, frameLeft)>>2 & ~1;
-	used = count*4;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data ^= 0x8000;
-	    *lefth++ = data>>8;
-	    *leftl++ = (data>>2) & 0x3f;
-	    get_user(data, ((u_short *)userPtr)++);
-	    data ^= 0x8000;
-	    *righth++ = data>>8;
-	    *rightl++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		u_char *high = &frame[*frameUsed>>1];
+		u_char *low = high+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data ^= 0x8000;
+			*high++ = data>>8;
+			*low++ = (data>>2) & 0x3f;
+			count--;
+		}
+	} else {
+		u_char *lefth = &frame[*frameUsed>>2];
+		u_char *leftl = lefth+sq.block_size_quarter;
+		u_char *righth = lefth+sq.block_size_half;
+		u_char *rightl = righth+sq.block_size_quarter;
+		count = min(userCount, frameLeft)>>2 & ~1;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data ^= 0x8000;
+			*lefth++ = data>>8;
+			*leftl++ = (data>>2) & 0x3f;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data ^= 0x8000;
+			*righth++ = data>>8;
+			*rightl++ = (data>>2) & 0x3f;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
 
-    if (!sound.soft.stereo) {
-	u_char *high = &frame[*frameUsed>>1];
-	u_char *low = high+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data);
-	    *high++ = data>>8;
-	    *low++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    } else {
-	u_char *lefth = &frame[*frameUsed>>2];
-	u_char *leftl = lefth+sq.block_size_quarter;
-	u_char *righth = lefth+sq.block_size_half;
-	u_char *rightl = righth+sq.block_size_quarter;
-	count = min(userCount, frameLeft)>>2 & ~1;
-	used = count*4;
-	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data);
-	    *lefth++ = data>>8;
-	    *leftl++ = (data>>2) & 0x3f;
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data);
-	    *righth++ = data>>8;
-	    *rightl++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+	if (!sound.soft.stereo) {
+		u_char *high = &frame[*frameUsed>>1];
+		u_char *low = high+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data);
+			*high++ = data>>8;
+			*low++ = (data>>2) & 0x3f;
+			count--;
+		}
+	} else {
+		u_char *lefth = &frame[*frameUsed>>2];
+		u_char *leftl = lefth+sq.block_size_quarter;
+		u_char *righth = lefth+sq.block_size_half;
+		u_char *rightl = righth+sq.block_size_quarter;
+		count = min(userCount, frameLeft)>>2 & ~1;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data);
+			*lefth++ = data>>8;
+			*leftl++ = (data>>2) & 0x3f;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data);
+			*righth++ = data>>8;
+			*rightl++ = (data>>2) & 0x3f;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
 }
 
 
 static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
 			 u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+	long count, used;
+	u_long data;
+
+	if (!sound.soft.stereo) {
+		u_char *high = &frame[*frameUsed>>1];
+		u_char *low = high+sq.block_size_half;
+		count = min(userCount, frameLeft)>>1 & ~1;
+		used = count*2;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data) ^ 0x8000;
+			*high++ = data>>8;
+			*low++ = (data>>2) & 0x3f;
+			count--;
+		}
+	} else {
+		u_char *lefth = &frame[*frameUsed>>2];
+		u_char *leftl = lefth+sq.block_size_quarter;
+		u_char *righth = lefth+sq.block_size_half;
+		u_char *rightl = righth+sq.block_size_quarter;
+		count = min(userCount, frameLeft)>>2 & ~1;
+		used = count*4;
+		while (count > 0) {
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data) ^ 0x8000;
+			*lefth++ = data>>8;
+			*leftl++ = (data>>2) & 0x3f;
+			if (get_user(data, ((u_short *)userPtr)++))
+				return -EFAULT;
+			data = le2be16(data) ^ 0x8000;
+			*righth++ = data>>8;
+			*rightl++ = (data>>2) & 0x3f;
+			count--;
+		}
+	}
+	*frameUsed += used;
+	return(used);
+}
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
+{
+	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+	long count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = table[data];
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = table[data];
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
+{
+	long count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = data << 8;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = data << 8;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
 
-    if (!sound.soft.stereo) {
-	u_char *high = &frame[*frameUsed>>1];
-	u_char *low = high+sq.block_size_half;
-	count = min(userCount, frameLeft)>>1 & ~1;
-	used = count*2;
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
+{
+	long count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
 	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data) ^ 0x8000;
-	    *high++ = data>>8;
-	    *low++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    } else {
-	u_char *lefth = &frame[*frameUsed>>2];
-	u_char *leftl = lefth+sq.block_size_quarter;
-	u_char *righth = lefth+sq.block_size_half;
-	u_char *rightl = righth+sq.block_size_quarter;
-	count = min(userCount, frameLeft)>>2 & ~1;
-	used = count*4;
+		u_char data;
+		if (get_user(data, userPtr++))
+			return -EFAULT;
+		val = (data ^ 0x80) << 8;
+		*p++ = val;
+		if (stereo) {
+			if (get_user(data, userPtr++))
+				return -EFAULT;
+			val = (data ^ 0x80) << 8;
+		}
+		*p++ = val;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
+{
+	long count, used;
+	int stereo = sound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	if (!stereo) {
+		short *up = (short *) userPtr;
+		while (count > 0) {
+			short data;
+			if (get_user(data, up++))
+				return -EFAULT;
+			*fp++ = data;
+			*fp++ = data;
+			count--;
+		}
+	} else {
+		if (copy_from_user(fp, userPtr, count * 4))
+			return -EFAULT;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
+{
+	long count, used;
+	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	int stereo = sound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	short *up = (short *) userPtr;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
 	while (count > 0) {
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data) ^ 0x8000;
-	    *lefth++ = data>>8;
-	    *leftl++ = (data>>2) & 0x3f;
-	    get_user(data, ((u_short *)userPtr)++);
-	    data = le2be16(data) ^ 0x8000;
-	    *righth++ = data>>8;
-	    *rightl++ = (data>>2) & 0x3f;
-	    count--;
-	}
-    }
-    *frameUsed += used;
-    return(used);
+		int data;
+		if (get_user(data, up++))
+			return -EFAULT;
+		data ^= mask;
+		*fp++ = data;
+		if (stereo) {
+			if (get_user(data, up++))
+				return -EFAULT;
+			data ^= mask;
+		}
+		*fp++ = data;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+	unsigned short *table = (unsigned short *)
+		(sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
+	unsigned int data = sound.data;
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	int bal = sound.bal;
+	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	int utotal, ftotal;
+	int stereo = sound.soft.stereo;
+ 
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = table[c];
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + table[c];
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	sound.bal = bal;
+	sound.data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = sound.data;
+	int bal = sound.bal;
+	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	int stereo = sound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = c << 8;
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + (c << 8);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	sound.bal = bal;
+	sound.data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = sound.data;
+	int bal = sound.bal;
+	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	int stereo = sound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(c, userPtr++))
+				return -EFAULT;
+			data = (c ^ 0x80) << 8;
+			if (stereo) {
+				if (get_user(c, userPtr++))
+					return -EFAULT;
+				data = (data << 16) + ((c ^ 0x80) << 8);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	sound.bal = bal;
+	sound.data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = sound.data;
+	unsigned short *up = (unsigned short *) userPtr;
+	int bal = sound.bal;
+	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	int stereo = sound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		unsigned short c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				if (get_user(c, up++))
+					return -EFAULT;
+				data = (data << 16) + c;
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	sound.bal = bal;
+	sound.data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
+}
+
+
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	unsigned int *p = (unsigned int *) &frame[*frameUsed];
+	unsigned int data = sound.data;
+	unsigned short *up = (unsigned short *) userPtr;
+	int bal = sound.bal;
+	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+	int stereo = sound.soft.stereo;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		unsigned short c;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			if (get_user(data, up++))
+				return -EFAULT;
+			data ^= mask;
+			if (stereo) {
+				if (get_user(c, up++))
+					return -EFAULT;
+				data = (data << 16) + (c ^ mask);
+			} else
+				data = (data << 16) + data;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+	sound.bal = bal;
+	sound.data = data;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
 }
-#endif /* CONFIG_AMIGA */
+
+#endif /* CONFIG_PMAC */
 
 
 #ifdef CONFIG_ATARI
 static TRANS transTTNormal = {
-    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
+	ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
 };
 
 static TRANS transTTExpanding = {
-    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
+	ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
 };
 
 static TRANS transFalconNormal = {
-    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
-    ata_ct_s16le, ata_ct_u16le
+	ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
+	ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
 };
 
 static TRANS transFalconExpanding = {
-    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
-    ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
+	ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
+	ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
 };
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
 static TRANS transAmiga = {
-    ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
-    ami_ct_s16le, ami_ct_u16le
+	ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
+	ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
 };
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static TRANS transAwacsNormal = {
+	pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
+	pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
+};
+
+static TRANS transAwacsExpand = {
+	pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
+	pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
+};
+#endif /* CONFIG_PMAC */
 
 /*** Low level stuff *********************************************************/
 
@@ -1583,40 +2164,40 @@
 
 static void *AtaAlloc(unsigned int size, int flags)
 {
-    return( atari_stram_alloc( size, NULL, "dmasound" ));
+	return( atari_stram_alloc( size, NULL, "dmasound" ));
 }
 
 static void AtaFree(void *obj, unsigned int size)
 {
-    atari_stram_free( obj );
+	atari_stram_free( obj );
 }
 
 static int AtaIrqInit(void)
 {
-    /* Set up timer A. Timer A
-    will receive a signal upon end of playing from the sound
-    hardware. Furthermore Timer A is able to count events
-    and will cause an interrupt after a programmed number
-    of events. So all we need to keep the music playing is
-    to provide the sound hardware with new data upon
-    an interrupt from timer A. */
-    mfp.tim_ct_a = 0;		/* ++roman: Stop timer before programming! */
-    mfp.tim_dt_a = 1;		/* Cause interrupt after first event. */
-    mfp.tim_ct_a = 8;		/* Turn on event counting. */
-    /* Register interrupt handler. */
-    request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
-                "DMA sound", ata_sq_interrupt);
-    mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
-    mfp.int_mk_a |= 0x20;
-    return(1);
+	/* Set up timer A. Timer A
+	   will receive a signal upon end of playing from the sound
+	   hardware. Furthermore Timer A is able to count events
+	   and will cause an interrupt after a programmed number
+	   of events. So all we need to keep the music playing is
+	   to provide the sound hardware with new data upon
+	   an interrupt from timer A. */
+	mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */
+	mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */
+	mfp.tim_ct_a = 8;	/* Turn on event counting. */
+	/* Register interrupt handler. */
+	request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
+		    "DMA sound", ata_sq_interrupt);
+	mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
+	mfp.int_mk_a |= 0x20;
+	return(1);
 }
 
 #ifdef MODULE
 static void AtaIrqCleanUp(void)
 {
-    mfp.tim_ct_a = 0;		/* stop timer */
-    mfp.int_en_a &= ~0x20;	/* turn interrupt off */
-    free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
+	mfp.tim_ct_a = 0;	/* stop timer */
+	mfp.int_en_a &= ~0x20;	/* turn interrupt off */
+	free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
 }
 #endif /* MODULE */
 
@@ -1628,17 +2209,17 @@
 
 static int AtaSetBass(int bass)
 {
-    sound.bass = TONE_VOXWARE_TO_DB(bass);
-    atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
-    return(TONE_DB_TO_VOXWARE(sound.bass));
+	sound.bass = TONE_VOXWARE_TO_DB(bass);
+	atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
+	return(TONE_DB_TO_VOXWARE(sound.bass));
 }
 
 
 static int AtaSetTreble(int treble)
 {
-    sound.treble = TONE_VOXWARE_TO_DB(treble);
-    atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
-    return(TONE_DB_TO_VOXWARE(sound.treble));
+	sound.treble = TONE_VOXWARE_TO_DB(treble);
+	atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
+	return(TONE_DB_TO_VOXWARE(sound.treble));
 }
 
 
@@ -1650,86 +2231,86 @@
 
 static void TTSilence(void)
 {
-    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-    atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
 }
 
 
 static void TTInit(void)
 {
-    int mode, i, idx;
-    const int freq[4] = {50066, 25033, 12517, 6258};
+	int mode, i, idx;
+	const int freq[4] = {50066, 25033, 12517, 6258};
 
-    /* search a frequency that fits into the allowed error range */
+	/* search a frequency that fits into the allowed error range */
 
-    idx = -1;
-    for (i = 0; i < arraysize(freq); i++)
-	/* this isn't as much useful for a TT than for a Falcon, but
-	 * then it doesn't hurt very much to implement it for a TT too.
-	 */
-	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-	    idx = i;
-    if (idx > -1) {
-	sound.soft.speed = freq[idx];
-	sound.trans = &transTTNormal;
-    } else
-	sound.trans = &transTTExpanding;
-
-    TTSilence();
-    sound.hard = sound.soft;
-
-    if (sound.hard.speed > 50066) {
-	/* we would need to squeeze the sound, but we won't do that */
-	sound.hard.speed = 50066;
-	mode = DMASND_MODE_50KHZ;
-	sound.trans = &transTTNormal;
-    } else if (sound.hard.speed > 25033) {
-	sound.hard.speed = 50066;
-	mode = DMASND_MODE_50KHZ;
-    } else if (sound.hard.speed > 12517) {
-	sound.hard.speed = 25033;
-	mode = DMASND_MODE_25KHZ;
-    } else if (sound.hard.speed > 6258) {
-	sound.hard.speed = 12517;
-	mode = DMASND_MODE_12KHZ;
-    } else {
-	sound.hard.speed = 6258;
-	mode = DMASND_MODE_6KHZ;
-    }
-
-    tt_dmasnd.mode = (sound.hard.stereo ?
-		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-		     DMASND_MODE_8BIT | mode;
+	idx = -1;
+	for (i = 0; i < arraysize(freq); i++)
+		/* this isn't as much useful for a TT than for a Falcon, but
+		 * then it doesn't hurt very much to implement it for a TT too.
+		 */
+		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+			idx = i;
+	if (idx > -1) {
+		sound.soft.speed = freq[idx];
+		sound.trans = &transTTNormal;
+	} else
+		sound.trans = &transTTExpanding;
+
+	TTSilence();
+	sound.hard = sound.soft;
+
+	if (sound.hard.speed > 50066) {
+		/* we would need to squeeze the sound, but we won't do that */
+		sound.hard.speed = 50066;
+		mode = DMASND_MODE_50KHZ;
+		sound.trans = &transTTNormal;
+	} else if (sound.hard.speed > 25033) {
+		sound.hard.speed = 50066;
+		mode = DMASND_MODE_50KHZ;
+	} else if (sound.hard.speed > 12517) {
+		sound.hard.speed = 25033;
+		mode = DMASND_MODE_25KHZ;
+	} else if (sound.hard.speed > 6258) {
+		sound.hard.speed = 12517;
+		mode = DMASND_MODE_12KHZ;
+	} else {
+		sound.hard.speed = 6258;
+		mode = DMASND_MODE_6KHZ;
+	}
+
+	tt_dmasnd.mode = (sound.hard.stereo ?
+			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		DMASND_MODE_8BIT | mode;
 
-    sound.bal = -sound.soft.speed;
+	sound.bal = -sound.soft.speed;
 }
 
 
 static int TTSetFormat(int format)
 {
-    /* TT sound DMA supports only 8bit modes */
+	/* TT sound DMA supports only 8bit modes */
 
-    switch (format) {
+	switch (format) {
 	case AFMT_QUERY:
-	    return(sound.soft.format);
+		return(sound.soft.format);
 	case AFMT_MU_LAW:
 	case AFMT_A_LAW:
 	case AFMT_S8:
 	case AFMT_U8:
-	    break;
+		break;
 	default:
-	    format = AFMT_S8;
-    }
+		format = AFMT_S8;
+	}
 
-    sound.soft.format = format;
-    sound.soft.size = 8;
-    if (sound.minDev == SND_DEV_DSP) {
-	sound.dsp.format = format;
-	sound.dsp.size = 8;
-    }
-    TTInit();
+	sound.soft.format = format;
+	sound.soft.size = 8;
+	if (sound.minDev == SND_DEV_DSP) {
+		sound.dsp.format = format;
+		sound.dsp.size = 8;
+	}
+	TTInit();
 
-    return(format);
+	return(format);
 }
 
 
@@ -1740,12 +2321,12 @@
 
 static int TTSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
-    atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
-    sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
-    atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
-    return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-	   (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+	sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+	atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
+	sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+	atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
+	return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+	       (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
 }
 
 
@@ -1755,9 +2336,9 @@
 
 static int TTSetGain(int gain)
 {
-    sound.gain = GAIN_VOXWARE_TO_DB(gain);
-    atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
-    return GAIN_DB_TO_VOXWARE(sound.gain);
+	sound.gain = GAIN_VOXWARE_TO_DB(gain);
+	atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
+	return GAIN_DB_TO_VOXWARE(sound.gain);
 }
 
 
@@ -1769,133 +2350,133 @@
 
 static void FalconSilence(void)
 {
-    /* stop playback, set sample rate 50kHz for PSG sound */
-    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-    tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
-    tt_dmasnd.int_div = 0; /* STE compatible divider */
-    tt_dmasnd.int_ctrl = 0x0;
-    tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
-    tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
-    tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
-    tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+	/* stop playback, set sample rate 50kHz for PSG sound */
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+	tt_dmasnd.int_div = 0; /* STE compatible divider */
+	tt_dmasnd.int_ctrl = 0x0;
+	tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+	tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+	tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+	tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
 }
 
 
 static void FalconInit(void)
 {
-    int divider, i, idx;
-    const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+	int divider, i, idx;
+	const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
 
-    /* search a frequency that fits into the allowed error range */
+	/* search a frequency that fits into the allowed error range */
 
-    idx = -1;
-    for (i = 0; i < arraysize(freq); i++)
-	/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
-	 * be playable without expanding, but that now a kernel runtime
-	 * option
-	 */
-	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-	    idx = i;
-    if (idx > -1) {
-	sound.soft.speed = freq[idx];
-	sound.trans = &transFalconNormal;
-    } else
-	sound.trans = &transFalconExpanding;
-
-    FalconSilence();
-    sound.hard = sound.soft;
+	idx = -1;
+	for (i = 0; i < arraysize(freq); i++)
+		/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+		 * be playable without expanding, but that now a kernel runtime
+		 * option
+		 */
+		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+			idx = i;
+	if (idx > -1) {
+		sound.soft.speed = freq[idx];
+		sound.trans = &transFalconNormal;
+	} else
+		sound.trans = &transFalconExpanding;
 
-    if (sound.hard.size == 16) {
-	/* the Falcon can play 16bit samples only in stereo */
-	sound.hard.stereo = 1;
-    }
+	FalconSilence();
+	sound.hard = sound.soft;
 
-    if (sound.hard.speed > 49170) {
-	/* we would need to squeeze the sound, but we won't do that */
-	sound.hard.speed = 49170;
-	divider = 1;
-	sound.trans = &transFalconNormal;
-    } else if (sound.hard.speed > 32780) {
-	sound.hard.speed = 49170;
-	divider = 1;
-    } else if (sound.hard.speed > 24585) {
-	sound.hard.speed = 32780;
-	divider = 2;
-    } else if (sound.hard.speed > 19668) {
-	sound.hard.speed = 24585;
-	divider = 3;
-    } else if (sound.hard.speed > 16390) {
-	sound.hard.speed = 19668;
-	divider = 4;
-    } else if (sound.hard.speed > 12292) {
-	sound.hard.speed = 16390;
-	divider = 5;
-    } else if (sound.hard.speed > 9834) {
-	sound.hard.speed = 12292;
-	divider = 7;
-    } else if (sound.hard.speed > 8195) {
-	sound.hard.speed = 9834;
-	divider = 9;
-    } else {
-	sound.hard.speed = 8195;
-	divider = 11;
-    }
-    tt_dmasnd.int_div = divider;
-
-    /* Setup Falcon sound DMA for playback */
-    tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
-    tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
-    tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
-    tt_dmasnd.cbar_dst = 0x0000;
-    tt_dmasnd.rec_track_select = 0;
-    tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
-    tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
-    tt_dmasnd.mode = (sound.hard.stereo ?
-		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-		     ((sound.hard.size == 8) ?
-		       DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
-		     DMASND_MODE_6KHZ;
+	if (sound.hard.size == 16) {
+		/* the Falcon can play 16bit samples only in stereo */
+		sound.hard.stereo = 1;
+	}
+
+	if (sound.hard.speed > 49170) {
+		/* we would need to squeeze the sound, but we won't do that */
+		sound.hard.speed = 49170;
+		divider = 1;
+		sound.trans = &transFalconNormal;
+	} else if (sound.hard.speed > 32780) {
+		sound.hard.speed = 49170;
+		divider = 1;
+	} else if (sound.hard.speed > 24585) {
+		sound.hard.speed = 32780;
+		divider = 2;
+	} else if (sound.hard.speed > 19668) {
+		sound.hard.speed = 24585;
+		divider = 3;
+	} else if (sound.hard.speed > 16390) {
+		sound.hard.speed = 19668;
+		divider = 4;
+	} else if (sound.hard.speed > 12292) {
+		sound.hard.speed = 16390;
+		divider = 5;
+	} else if (sound.hard.speed > 9834) {
+		sound.hard.speed = 12292;
+		divider = 7;
+	} else if (sound.hard.speed > 8195) {
+		sound.hard.speed = 9834;
+		divider = 9;
+	} else {
+		sound.hard.speed = 8195;
+		divider = 11;
+	}
+	tt_dmasnd.int_div = divider;
+
+	/* Setup Falcon sound DMA for playback */
+	tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+	tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+	tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+	tt_dmasnd.cbar_dst = 0x0000;
+	tt_dmasnd.rec_track_select = 0;
+	tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+	tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+	tt_dmasnd.mode = (sound.hard.stereo ?
+			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		((sound.hard.size == 8) ?
+		 DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+		DMASND_MODE_6KHZ;
 
-    sound.bal = -sound.soft.speed;
+	sound.bal = -sound.soft.speed;
 }
 
 
 static int FalconSetFormat(int format)
 {
-    int size;
-    /* Falcon sound DMA supports 8bit and 16bit modes */
+	int size;
+	/* Falcon sound DMA supports 8bit and 16bit modes */
 
-    switch (format) {
+	switch (format) {
 	case AFMT_QUERY:
-	    return(sound.soft.format);
+		return(sound.soft.format);
 	case AFMT_MU_LAW:
 	case AFMT_A_LAW:
 	case AFMT_U8:
 	case AFMT_S8:
-	    size = 8;
-	    break;
+		size = 8;
+		break;
 	case AFMT_S16_BE:
 	case AFMT_U16_BE:
 	case AFMT_S16_LE:
 	case AFMT_U16_LE:
-	    size = 16;
-	    break;
+		size = 16;
+		break;
 	default: /* :-) */
-	    size = 8;
-	    format = AFMT_S8;
-    }
-
-    sound.soft.format = format;
-    sound.soft.size = size;
-    if (sound.minDev == SND_DEV_DSP) {
-	sound.dsp.format = format;
-	sound.dsp.size = sound.soft.size;
-    }
+		size = 8;
+		format = AFMT_S8;
+	}
+
+	sound.soft.format = format;
+	sound.soft.size = size;
+	if (sound.minDev == SND_DEV_DSP) {
+		sound.dsp.format = format;
+		sound.dsp.size = sound.soft.size;
+	}
 
-    FalconInit();
+	FalconInit();
 
-    return(format);
+	return(format);
 }
 
 
@@ -1909,164 +2490,164 @@
 
 static int FalconSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
-    sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
-    tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
-    return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-	   VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
+	sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+	sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+	tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
+	return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+	       VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
 }
 
 
 static void ata_sq_play_next_frame(int index)
 {
-    char *start, *end;
+	char *start, *end;
 
-    /* used by AtaPlay() if all doubts whether there really is something
-     * to be played are already wiped out.
-     */
-    start = sq_block_address(sq.front);
-    end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
-    /* end might not be a legal virtual address. */
-    DMASNDSetEnd(VTOP(end - 1) + 1);
-    DMASNDSetBase(VTOP(start));
+	/* used by AtaPlay() if all doubts whether there really is something
+	 * to be played are already wiped out.
+	 */
+	start = sq_block_address(sq.front);
+	end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
+	/* end might not be a legal virtual address. */
+	DMASNDSetEnd(VTOP(end - 1) + 1);
+	DMASNDSetBase(VTOP(start));
 	/* Since only an even number of samples per frame can
-	be played, we might lose one byte here. (TO DO) */
-    sq.front = (sq.front+1) % sq.max_count;
-    sq.playing++;
-    tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+	   be played, we might lose one byte here. (TO DO) */
+	sq.front = (sq.front+1) % sq.max_count;
+	sq.playing++;
+	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
 }
 
 
 static void AtaPlay(void)
 {
-    /* ++TeSche: Note that sq.playing is no longer just a flag but holds
-     * the number of frames the DMA is currently programmed for instead,
-     * may be 0, 1 (currently being played) or 2 (pre-programmed).
-     *
-     * Changes done to sq.count and sq.playing are a bit more subtle again
-     * so now I must admit I also prefer disabling the irq here rather
-     * than considering all possible situations. But the point is that
-     * disabling the irq doesn't have any bad influence on this version of
-     * the driver as we benefit from having pre-programmed the DMA
-     * wherever possible: There's no need to reload the DMA at the exact
-     * time of an interrupt but only at some time while the pre-programmed
-     * frame is playing!
-     */
-    atari_disable_irq(IRQ_MFP_TIMA);
+	/* ++TeSche: Note that sq.playing is no longer just a flag but holds
+	 * the number of frames the DMA is currently programmed for instead,
+	 * may be 0, 1 (currently being played) or 2 (pre-programmed).
+	 *
+	 * Changes done to sq.count and sq.playing are a bit more subtle again
+	 * so now I must admit I also prefer disabling the irq here rather
+	 * than considering all possible situations. But the point is that
+	 * disabling the irq doesn't have any bad influence on this version of
+	 * the driver as we benefit from having pre-programmed the DMA
+	 * wherever possible: There's no need to reload the DMA at the exact
+	 * time of an interrupt but only at some time while the pre-programmed
+	 * frame is playing!
+	 */
+	atari_disable_irq(IRQ_MFP_TIMA);
 
-    if (sq.playing == 2 ||	/* DMA is 'full' */
-	sq.count <= 0) {	/* nothing to do */
-	atari_enable_irq(IRQ_MFP_TIMA);
-	return;
-    }
+	if (sq.playing == 2 ||	/* DMA is 'full' */
+	    sq.count <= 0) {	/* nothing to do */
+		atari_enable_irq(IRQ_MFP_TIMA);
+		return;
+	}
 
-    if (sq.playing == 0) {
-	/* looks like there's nothing 'in' the DMA yet, so try
-	 * to put two frames into it (at least one is available).
-	 */
-	if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
-	    /* hmmm, the only existing frame is not
-	     * yet filled and we're not syncing?
-	     */
-	    atari_enable_irq(IRQ_MFP_TIMA);
-	    return;
-	}
-	ata_sq_play_next_frame(1);
-	if (sq.count == 1) {
-	    /* no more frames */
-	    atari_enable_irq(IRQ_MFP_TIMA);
-	    return;
-	}
-	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-	    /* hmmm, there were two frames, but the second
-	     * one is not yet filled and we're not syncing?
-	     */
-	    atari_enable_irq(IRQ_MFP_TIMA);
-	    return;
-	}
-	ata_sq_play_next_frame(2);
-    } else {
-	/* there's already a frame being played so we may only stuff
-	 * one new into the DMA, but even if this may be the last
-	 * frame existing the previous one is still on sq.count.
-	 */
-	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-	    /* hmmm, the only existing frame is not
-	     * yet filled and we're not syncing?
-	     */
-	    atari_enable_irq(IRQ_MFP_TIMA);
-	    return;
-	}
-	ata_sq_play_next_frame(2);
-    }
-    atari_enable_irq(IRQ_MFP_TIMA);
+	if (sq.playing == 0) {
+		/* looks like there's nothing 'in' the DMA yet, so try
+		 * to put two frames into it (at least one is available).
+		 */
+		if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+			/* hmmm, the only existing frame is not
+			 * yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		ata_sq_play_next_frame(1);
+		if (sq.count == 1) {
+			/* no more frames */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+			/* hmmm, there were two frames, but the second
+			 * one is not yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		ata_sq_play_next_frame(2);
+	} else {
+		/* there's already a frame being played so we may only stuff
+		 * one new into the DMA, but even if this may be the last
+		 * frame existing the previous one is still on sq.count.
+		 */
+		if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+			/* hmmm, the only existing frame is not
+			 * yet filled and we're not syncing?
+			 */
+			atari_enable_irq(IRQ_MFP_TIMA);
+			return;
+		}
+		ata_sq_play_next_frame(2);
+	}
+	atari_enable_irq(IRQ_MFP_TIMA);
 }
 
 
 static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
 #if 0
-    /* ++TeSche: if you should want to test this... */
-    static int cnt = 0;
-    if (sq.playing == 2)
-	if (++cnt == 10) {
-	    /* simulate losing an interrupt */
-	    cnt = 0;
-	    return;
-	}
+	/* ++TeSche: if you should want to test this... */
+	static int cnt = 0;
+	if (sq.playing == 2)
+		if (++cnt == 10) {
+			/* simulate losing an interrupt */
+			cnt = 0;
+			return;
+		}
 #endif
 
-    if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
-	/* ++TeSche: Falcon only: ignore first irq because it comes
-	 * immediately after starting a frame. after that, irqs come
-	 * (almost) like on the TT.
-	 */
-	sq.ignore_int = 0;
-	return;
-    }
+	if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
+		/* ++TeSche: Falcon only: ignore first irq because it comes
+		 * immediately after starting a frame. after that, irqs come
+		 * (almost) like on the TT.
+		 */
+		sq.ignore_int = 0;
+		return;
+	}
 
-    if (!sq.playing) {
-	/* playing was interrupted and sq_reset() has already cleared
-	 * the sq variables, so better don't do anything here.
-	 */
-	WAKE_UP(sq.sync_queue);
-	return;
-    }
+	if (!sq.playing) {
+		/* playing was interrupted and sq_reset() has already cleared
+		 * the sq variables, so better don't do anything here.
+		 */
+		WAKE_UP(sq.sync_queue);
+		return;
+	}
 
-    /* Probably ;) one frame is finished. Well, in fact it may be that a
-     * pre-programmed one is also finished because there has been a long
-     * delay in interrupt delivery and we've completely lost one, but
-     * there's no way to detect such a situation. In such a case the last
-     * frame will be played more than once and the situation will recover
-     * as soon as the irq gets through.
-     */
-    sq.count--;
-    sq.playing--;
+	/* Probably ;) one frame is finished. Well, in fact it may be that a
+	 * pre-programmed one is also finished because there has been a long
+	 * delay in interrupt delivery and we've completely lost one, but
+	 * there's no way to detect such a situation. In such a case the last
+	 * frame will be played more than once and the situation will recover
+	 * as soon as the irq gets through.
+	 */
+	sq.count--;
+	sq.playing--;
 
-    if (!sq.playing) {
-	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-	sq.ignore_int = 1;
-    }
+	if (!sq.playing) {
+		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+		sq.ignore_int = 1;
+	}
 
-    WAKE_UP(sq.write_queue);
+	WAKE_UP(sq.write_queue);
 	/* At least one block of the queue is free now
-	so wake up a writing process blocked because
-	of a full queue. */
+	   so wake up a writing process blocked because
+	   of a full queue. */
 
-    if ((sq.playing != 1) || (sq.count != 1))
-	/* We must be a bit carefully here: sq.count indicates the
-	 * number of buffers used and not the number of frames to
-	 * be played. If sq.count==1 and sq.playing==1 that means
-	 * the only remaining frame was already programmed earlier
-	 * (and is currently running) so we mustn't call AtaPlay()
-	 * here, otherwise we'll play one frame too much.
-	 */
-	AtaPlay();
+	if ((sq.playing != 1) || (sq.count != 1))
+		/* We must be a bit carefully here: sq.count indicates the
+		 * number of buffers used and not the number of frames to
+		 * be played. If sq.count==1 and sq.playing==1 that means
+		 * the only remaining frame was already programmed earlier
+		 * (and is currently running) so we mustn't call AtaPlay()
+		 * here, otherwise we'll play one frame too much.
+		 */
+		AtaPlay();
 
-    if (!sq.playing) WAKE_UP(sq.sync_queue);
+	if (!sq.playing) WAKE_UP(sq.sync_queue);
 	/* We are not playing after AtaPlay(), so there
-	is nothing to play any more. Wake up a process
-	waiting for audio output to drain. */
+	   is nothing to play any more. Wake up a process
+	   waiting for audio output to drain. */
 }
 #endif /* CONFIG_ATARI */
 
@@ -2080,107 +2661,107 @@
 
 static void *AmiAlloc(unsigned int size, int flags)
 {
-    return(amiga_chip_alloc((long)size));
+	return(amiga_chip_alloc((long)size));
 }
 
 static void AmiFree(void *obj, unsigned int size)
 {
-    amiga_chip_free (obj);
+	amiga_chip_free (obj);
 }
 
 static int AmiIrqInit(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
+	/* turn off DMA for audio channels */
+	custom.dmacon = AMI_AUDIO_OFF;
 
-    /* Register interrupt handler. */
-    if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
-                    "DMA sound", ami_sq_interrupt))
-	return(0);
-    return(1);
+	/* Register interrupt handler. */
+	if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
+			"DMA sound", ami_sq_interrupt))
+		return(0);
+	return(1);
 }
 
 #ifdef MODULE
 static void AmiIrqCleanUp(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
-    /* release the interrupt */
-    free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
+	/* turn off DMA for audio channels */
+	custom.dmacon = AMI_AUDIO_OFF;
+	/* release the interrupt */
+	free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
 }
 #endif /* MODULE */
 
 static void AmiSilence(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
+	/* turn off DMA for audio channels */
+	custom.dmacon = AMI_AUDIO_OFF;
 }
 
 
 static void AmiInit(void)
 {
-    int period, i;
+	int period, i;
 
-    AmiSilence();
+	AmiSilence();
 
-    if (sound.soft.speed)
-	period = amiga_colorclock/sound.soft.speed-1;
-    else
-	period = amiga_audio_min_period;
-    sound.hard = sound.soft;
-    sound.trans = &transAmiga;
-
-    if (period < amiga_audio_min_period) {
-	/* we would need to squeeze the sound, but we won't do that */
-	period = amiga_audio_min_period;
-    } else if (period > 65535) {
-	period = 65535;
-    }
-    sound.hard.speed = amiga_colorclock/(period+1);
-
-    for (i = 0; i < 4; i++)
-	custom.aud[i].audper = period;
-    amiga_audio_period = period;
+	if (sound.soft.speed)
+		period = amiga_colorclock/sound.soft.speed-1;
+	else
+		period = amiga_audio_min_period;
+	sound.hard = sound.soft;
+	sound.trans = &transAmiga;
+
+	if (period < amiga_audio_min_period) {
+		/* we would need to squeeze the sound, but we won't do that */
+		period = amiga_audio_min_period;
+	} else if (period > 65535) {
+		period = 65535;
+	}
+	sound.hard.speed = amiga_colorclock/(period+1);
+
+	for (i = 0; i < 4; i++)
+		custom.aud[i].audper = period;
+	amiga_audio_period = period;
 
-    AmiSetTreble(50);  /* recommended for newer amiga models */
+	AmiSetTreble(50);  /* recommended for newer amiga models */
 }
 
 
 static int AmiSetFormat(int format)
 {
-    int size;
+	int size;
 
-    /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+	/* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
 
-    switch (format) {
+	switch (format) {
 	case AFMT_QUERY:
-	    return(sound.soft.format);
+		return(sound.soft.format);
 	case AFMT_MU_LAW:
 	case AFMT_A_LAW:
 	case AFMT_U8:
 	case AFMT_S8:
-	    size = 8;
-	    break;
+		size = 8;
+		break;
 	case AFMT_S16_BE:
 	case AFMT_U16_BE:
 	case AFMT_S16_LE:
 	case AFMT_U16_LE:
-	    size = 16;
-	    break;
+		size = 16;
+		break;
 	default: /* :-) */
-	    size = 8;
-	    format = AFMT_S8;
-    }
-
-    sound.soft.format = format;
-    sound.soft.size = size;
-    if (sound.minDev == SND_DEV_DSP) {
-	sound.dsp.format = format;
-	sound.dsp.size = sound.soft.size;
-    }
-    AmiInit();
+		size = 8;
+		format = AFMT_S8;
+	}
+
+	sound.soft.format = format;
+	sound.soft.size = size;
+	if (sound.minDev == SND_DEV_DSP) {
+		sound.dsp.format = format;
+		sound.dsp.size = sound.soft.size;
+	}
+	AmiInit();
 
-    return(format);
+	return(format);
 }
 
 
@@ -2190,22 +2771,22 @@
 
 static int AmiSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
-    custom.aud[0].audvol = sound.volume_left;
-    sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
-    custom.aud[1].audvol = sound.volume_right;
-    return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-	   (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+	sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+	custom.aud[0].audvol = sound.volume_left;
+	sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+	custom.aud[1].audvol = sound.volume_right;
+	return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+	       (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
 }
 
 static int AmiSetTreble(int treble)
 {
-    sound.treble = treble;
-    if (treble < 50)
-	ciaa.pra &= ~0x02;
-    else
-	ciaa.pra |= 0x02;
-    return(treble);
+	sound.treble = treble;
+	if (treble < 50)
+		ciaa.pra &= ~0x02;
+	else
+		ciaa.pra |= 0x02;
+	return(treble);
 }
 
 
@@ -2216,164 +2797,550 @@
 
 static void ami_sq_play_next_frame(int index)
 {
-    u_char *start, *ch0, *ch1, *ch2, *ch3;
-    u_long size;
+	u_char *start, *ch0, *ch1, *ch2, *ch3;
+	u_long size;
 
-    /* used by AmiPlay() if all doubts whether there really is something
-     * to be played are already wiped out.
-     */
-    start = sq_block_address(sq.front);
-    size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
-    if (sound.hard.stereo) {
-	ch0 = start;
-	ch1 = start+sq.block_size_half;
-	size >>= 1;
-    } else {
-	ch0 = start;
-	ch1 = start;
-    }
-    if (sound.hard.size == 8) {
-	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-	custom.aud[0].audlen = size;
-	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-	custom.aud[1].audlen = size;
-	custom.dmacon = AMI_AUDIO_8;
-    } else {
-	size >>= 1;
-	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-	custom.aud[0].audlen = size;
-	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-	custom.aud[1].audlen = size;
-	if (sound.volume_left == 64 && sound.volume_right == 64) {
-	    /* We can play pseudo 14-bit only with the maximum volume */
-	    ch3 = ch0+sq.block_size_quarter;
-	    ch2 = ch1+sq.block_size_quarter;
-	    custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
-	    custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
-	    custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
-	    custom.aud[2].audlen = size;
-	    custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
-	    custom.aud[3].audlen = size;
-	    custom.dmacon = AMI_AUDIO_14;
-	} else
-	    custom.dmacon = AMI_AUDIO_8;
-    }
-    sq.front = (sq.front+1) % sq.max_count;
-    sq.playing |= AMI_PLAY_LOADED;
+	/* used by AmiPlay() if all doubts whether there really is something
+	 * to be played are already wiped out.
+	 */
+	start = sq_block_address(sq.front);
+	size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
+
+	if (sound.hard.stereo) {
+		ch0 = start;
+		ch1 = start+sq.block_size_half;
+		size >>= 1;
+	} else {
+		ch0 = start;
+		ch1 = start;
+	}
+	if (sound.hard.size == 8) {
+		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+		custom.aud[0].audlen = size;
+		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+		custom.aud[1].audlen = size;
+		custom.dmacon = AMI_AUDIO_8;
+	} else {
+		size >>= 1;
+		custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+		custom.aud[0].audlen = size;
+		custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+		custom.aud[1].audlen = size;
+		if (sound.volume_left == 64 && sound.volume_right == 64) {
+			/* We can play pseudo 14-bit only with the maximum volume */
+			ch3 = ch0+sq.block_size_quarter;
+			ch2 = ch1+sq.block_size_quarter;
+			custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
+			custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
+			custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+			custom.aud[2].audlen = size;
+			custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+			custom.aud[3].audlen = size;
+			custom.dmacon = AMI_AUDIO_14;
+		} else
+			custom.dmacon = AMI_AUDIO_8;
+	}
+	sq.front = (sq.front+1) % sq.max_count;
+	sq.playing |= AMI_PLAY_LOADED;
 }
 
 
 static void AmiPlay(void)
 {
-    int minframes = 1;
+	int minframes = 1;
 
-    custom.intena = IF_AUD0;
+	custom.intena = IF_AUD0;
 
-    if (sq.playing & AMI_PLAY_LOADED) {
-	/* There's already a frame loaded */
-	custom.intena = IF_SETCLR | IF_AUD0;
-	return;
-    }
+	if (sq.playing & AMI_PLAY_LOADED) {
+		/* There's already a frame loaded */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
 
-    if (sq.playing & AMI_PLAY_PLAYING)
-	/* Increase threshold: frame 1 is already being played */
-	minframes = 2;
+	if (sq.playing & AMI_PLAY_PLAYING)
+		/* Increase threshold: frame 1 is already being played */
+		minframes = 2;
 
-    if (sq.count < minframes) {
-	/* Nothing to do */
-	custom.intena = IF_SETCLR | IF_AUD0;
-	return;
-    }
+	if (sq.count < minframes) {
+		/* Nothing to do */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
 
-    if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
-	/* hmmm, the only existing frame is not
-	 * yet filled and we're not syncing?
-	 */
-	custom.intena = IF_SETCLR | IF_AUD0;
-	return;
-    }
+	if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
+		/* hmmm, the only existing frame is not
+		 * yet filled and we're not syncing?
+		 */
+		custom.intena = IF_SETCLR | IF_AUD0;
+		return;
+	}
 
-    ami_sq_play_next_frame(minframes);
+	ami_sq_play_next_frame(minframes);
 
-    custom.intena = IF_SETCLR | IF_AUD0;
+	custom.intena = IF_SETCLR | IF_AUD0;
 }
 
 
 static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-    int minframes = 1;
+	int minframes = 1;
 
-    if (!sq.playing) {
-	/* Playing was interrupted and sq_reset() has already cleared
-	 * the sq variables, so better don't do anything here.
-	 */
-	WAKE_UP(sq.sync_queue);
-	return;
-    }
+	if (!sq.playing) {
+		/* Playing was interrupted and sq_reset() has already cleared
+		 * the sq variables, so better don't do anything here.
+		 */
+		WAKE_UP(sq.sync_queue);
+		return;
+	}
 
-    if (sq.playing & AMI_PLAY_PLAYING) {
-	/* We've just finished a frame */
-	sq.count--;
-	WAKE_UP(sq.write_queue);
-    }
+	if (sq.playing & AMI_PLAY_PLAYING) {
+		/* We've just finished a frame */
+		sq.count--;
+		WAKE_UP(sq.write_queue);
+	}
 
-    if (sq.playing & AMI_PLAY_LOADED)
-	/* Increase threshold: frame 1 is already being played */
-	minframes = 2;
+	if (sq.playing & AMI_PLAY_LOADED)
+		/* Increase threshold: frame 1 is already being played */
+		minframes = 2;
 
-    /* Shift the flags */
-    sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+	/* Shift the flags */
+	sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
 
-    if (!sq.playing)
-	/* No frame is playing, disable audio DMA */
-	custom.dmacon = AMI_AUDIO_OFF;
+	if (!sq.playing)
+		/* No frame is playing, disable audio DMA */
+		custom.dmacon = AMI_AUDIO_OFF;
+
+	if (sq.count >= minframes)
+		/* Try to play the next frame */
+		AmiPlay();
 
-    if (sq.count >= minframes)
-    	/* Try to play the next frame */
-	AmiPlay();
-
-    if (!sq.playing)
-	/* Nothing to play anymore.
-	   Wake up a process waiting for audio output to drain. */
-	WAKE_UP(sq.sync_queue);
+	if (!sq.playing)
+		/* Nothing to play anymore.
+		   Wake up a process waiting for audio output to drain. */
+		WAKE_UP(sq.sync_queue);
 }
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+	return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+	kfree(ptr);
+}
+
+static int PMacIrqInit(void)
+{
+	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+		return 0;
+	return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+	/* turn off output dma */
+	out_le32(&awacs_txdma->control, RUN<<16);
+	/* disable interrupts from awacs interface */
+	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+	free_irq(awacs_irq, pmac_awacs_intr);
+	free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+	kfree(awacs_tx_cmd_space);
+	if (beep_buf)
+		kfree(beep_buf);
+	kd_mksound = orig_mksound;
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+	/* turn off output dma */
+	out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+
+static void PMacInit(void)
+{
+	int i, tolerance;
+
+	switch (sound.soft.format) {
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		sound.hard.format = AFMT_S16_LE;
+		break;
+	default:
+		sound.hard.format = AFMT_S16_BE;
+		break;
+	}
+	sound.hard.stereo = 1;
+	sound.hard.size = 16;
+
+	/*
+	 * If we have a sample rate which is within catchRadius percent
+	 * of the requested value, we don't have to expand the samples.
+	 * Otherwise choose the next higher rate.
+	 */
+	i = 8;
+	do {
+		tolerance = catchRadius * awacs_freqs[--i] / 100;
+	} while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0);
+	if (sound.soft.speed >= awacs_freqs[i] - tolerance)
+		sound.trans = &transAwacsNormal;
+	else
+		sound.trans = &transAwacsExpand;
+	sound.hard.speed = awacs_freqs[i];
+	awacs_rate_index = i;
+
+	PMacSilence();
+	out_le32(&awacs->control, MASK_IEPC | MASK_IEE | (i << 8) | 0x11);
+	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+	awacs_write(awacs_reg[1] | MASK_ADDR1);
+	out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+
+	sound.bal = -sound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+	int size;
+
+	switch (format) {
+	case AFMT_QUERY:
+		return sound.soft.format;
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+		size = 8;
+		break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+		size = 16;
+		break;
+	default: /* :-) */
+		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+		       format);
+		size = 8;
+		format = AFMT_U8;
+	}
+
+	sound.soft.format = format;
+	sound.soft.size = size;
+	if (sound.minDev == SND_DEV_DSP) {
+		sound.dsp.format = format;
+		sound.dsp.size = size;
+	}
+
+	PMacInit();
+
+	return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x)	(15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+	int volume;
+
+	volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+	volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+	return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+	int r1, rn;
+
+	if (mute && volume == 0) {
+		r1 = awacs_reg[1] | mute;
+	} else {
+		r1 = awacs_reg[1] & ~mute;
+		rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+		rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+		rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+		awacs_reg[n] = rn;
+		awacs_write((n << 12) | rn);
+		volume = awacs_get_volume(rn, lshift);
+	}
+	if (r1 != awacs_reg[1]) {
+		awacs_reg[1] = r1;
+		awacs_write(r1 | MASK_ADDR1);
+	}
+	return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+	volatile struct dbdma_cmd *cp;
+	int i, count;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (beep_playing) {
+		/* sound takes precedence over beeps */
+		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 || (awacs_rate_index << 8));
+		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+		beep_playing = 0;
+	}
+	i = sq.front + sq.playing;
+	if (i >= sq.max_count)
+		i -= sq.max_count;
+	while (sq.playing < 2 && sq.playing < sq.count) {
+		count = (sq.count == sq.playing + 1)? sq.rear_size: sq.block_size;
+		if (count < sq.block_size && !sq.syncing)
+			/* last block not yet filled, and we're not syncing. */
+			break;
+		cp = &awacs_tx_cmds[i];
+		st_le16(&cp->req_count, count);
+		st_le16(&cp->xfer_status, 0);
+		if (++i >= sq.max_count)
+			i = 0;
+		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+		if (sq.playing == 0)
+			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+		++sq.playing;
+	}
+	restore_flags(flags);
+}
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	int i = sq.front;
+	int stat;
+	volatile struct dbdma_cmd *cp;
+
+	while (sq.playing > 0) {
+		cp = &awacs_tx_cmds[i];
+		stat = ld_le16(&cp->xfer_status);
+		if ((stat & ACTIVE) == 0)
+			break;	/* this frame is still going */
+		--sq.count;
+		--sq.playing;
+		if (++i >= sq.max_count)
+			i = 0;
+	}
+	if (i != sq.front)
+		WAKE_UP(sq.write_queue);
+	sq.front = i;
+
+	PMacPlay();
+
+	if (!sq.playing)
+		WAKE_UP(sq.sync_queue);
+}
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	int ctrl = in_le32(&awacs->control);
+
+	if (ctrl & MASK_PORTCHG) {
+		/* do something when headphone is plugged/unplugged? */
+	}
+	if (ctrl & MASK_CNTLERR) {
+		printk(KERN_ERR "AWACS: error, status = %x\n",
+		       in_le32(&awacs->codec_stat));
+	}
+	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+	out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+		;	/* XXX should have timeout */
+	out_le32(&awacs->codec_ctrl, val);
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (beep_playing) {
+		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+		beep_playing = 0;
+	}
+	restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+	NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+	unsigned long flags;
+	int srate = awacs_freqs[BEEP_SPEED];
+	int period, ncycles, nsamples;
+	int i, j, f;
+	short *p;
+	static int beep_hz_cache;
+	static int beep_nsamples_cache;
+	static int beep_volume_cache;
+
+	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+		/* this is a hack for broken X server code */
+		hz = 750;
+		ticks = 12;
+#else
+		/* cancel beep currently playing */
+		awacs_nosound(0);
+		return;
+#endif
+	}
+	save_flags(flags); cli();
+	del_timer(&beep_timer);
+	if (ticks) {
+		beep_timer.expires = jiffies + ticks;
+		add_timer(&beep_timer);
+	}
+	if (beep_playing || sq.playing || beep_buf == NULL) {
+		restore_flags(flags);
+		return;		/* too hard, sorry :-( */
+	}
+	beep_playing = 1;
+	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+	restore_flags(flags);
+
+	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+		nsamples = beep_nsamples_cache;
+	} else {
+		period = srate * 256 / hz;	/* fixed point */
+		ncycles = BEEP_BUFLEN * 256 / period;
+		nsamples = (period * ncycles) >> 8;
+		f = ncycles * 65536 / nsamples;
+		j = 0;
+		p = beep_buf;
+		for (i = 0; i < nsamples; ++i, p += 2) {
+			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+			j = (j + f) & 0xffff;
+		}
+		beep_hz_cache = hz;
+		beep_volume_cache = beep_volume;
+		beep_nsamples_cache = nsamples;
+	}
+
+	st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+	st_le16(&beep_dbdma_cmd->xfer_status, 0);
+	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+
+	save_flags(flags); cli();
+	if (beep_playing) {	/* i.e. haven't been terminated already */
+		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (BEEP_SPEED << 8));
+		out_le32(&awacs->byteswap, 0);
+		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+	}
+	restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct notifier_block *this,
+			      unsigned long code, void *x)
+{
+	switch (code) {
+	case PBOOK_SLEEP:
+		/* XXX we should stop any dma in progress when going to sleep
+		   and restart it when we wake. */
+		PMacSilence();
+		break;
+	case PBOOK_WAKE:
+		out_le32(&awacs->control, MASK_IEPC | MASK_IEE |
+			 (awacs_rate_index << 8) | 0x11);
+		awacs_write(awacs_reg[0] | MASK_ADDR0);
+		awacs_write(awacs_reg[1] | MASK_ADDR1);
+		awacs_write(awacs_reg[2] | MASK_ADDR2);
+		awacs_write(awacs_reg[4] | MASK_ADDR4);
+		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+	}
+	return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
 
 /*** Machine definitions *****************************************************/
 
 
 #ifdef CONFIG_ATARI
 static MACHINE machTT = {
-    DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
+	DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-    AtaIrqCleanUp,
+	AtaIrqCleanUp,
 #endif /* MODULE */
-    TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble,
-    TTSetGain,
-    AtaPlay
+	TTInit, TTSilence, TTSetFormat, TTSetVolume,
+	AtaSetBass, AtaSetTreble, TTSetGain,
+	AtaPlay
 };
 
 static MACHINE machFalcon = {
-    DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
+	DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-    AtaIrqCleanUp,
+	AtaIrqCleanUp,
 #endif /* MODULE */
-    FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass,
-    AtaSetTreble, NULL, AtaPlay
+	FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
+	AtaSetBass, AtaSetTreble, NULL,
+	AtaPlay
 };
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
 static MACHINE machAmiga = {
-    DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+	DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+#ifdef MODULE
+	AmiIrqCleanUp,
+#endif /* MODULE */
+	AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
+	NULL, AmiSetTreble, NULL,
+	AmiPlay
+};
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static MACHINE machPMac = {
+	DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
 #ifdef MODULE
-    AmiIrqCleanUp,
+	PMacIrqCleanup,
 #endif /* MODULE */
-    AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble,
-    NULL,
-    AmiPlay
+	PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
+	NULL, NULL, NULL,	/* bass, treble, gain */
+	PMacPlay
 };
 #endif /* CONFIG_AMIGA */
 
@@ -2383,78 +3350,79 @@
 
 static void sound_silence(void)
 {
-    /* update hardware settings one more */
-    (*sound.mach.init)();
+	/* update hardware settings one more */
+	(*sound.mach.init)();
 
-    (*sound.mach.silence)();
+	(*sound.mach.silence)();
 }
 
 
 static void sound_init(void)
 {
-    (*sound.mach.init)();
+	(*sound.mach.init)();
 }
 
 
 static int sound_set_format(int format)
 {
-    return(*sound.mach.setFormat)(format);
+	return(*sound.mach.setFormat)(format);
 }
 
 
 static int sound_set_speed(int speed)
 {
-    if (speed < 0)
-	return(sound.soft.speed);
+	if (speed < 0)
+		return(sound.soft.speed);
 
-    sound.soft.speed = speed;
-    (*sound.mach.init)();
-    if (sound.minDev == SND_DEV_DSP)
-	sound.dsp.speed = sound.soft.speed;
+	sound.soft.speed = speed;
+	(*sound.mach.init)();
+	if (sound.minDev == SND_DEV_DSP)
+		sound.dsp.speed = sound.soft.speed;
 
-    return(sound.soft.speed);
+	return(sound.soft.speed);
 }
 
 
 static int sound_set_stereo(int stereo)
 {
-    if (stereo < 0)
-	return(sound.soft.stereo);
+	if (stereo < 0)
+		return(sound.soft.stereo);
 
-    stereo = !!stereo;    /* should be 0 or 1 now */
+	stereo = !!stereo;    /* should be 0 or 1 now */
 
-    sound.soft.stereo = stereo;
-    if (sound.minDev == SND_DEV_DSP)
-	sound.dsp.stereo = stereo;
-    (*sound.mach.init)();
+	sound.soft.stereo = stereo;
+	if (sound.minDev == SND_DEV_DSP)
+		sound.dsp.stereo = stereo;
+	(*sound.mach.init)();
 
-    return(stereo);
+	return(stereo);
 }
 
 
 static int sound_set_volume(int volume)
 {
-    return(*sound.mach.setVolume)(volume);
+	return(*sound.mach.setVolume)(volume);
 }
 
 
 #ifdef CONFIG_ATARI
 static int sound_set_bass(int bass)
 {
-    return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
+	return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
 }
 
 static int sound_set_gain(int gain)
 {
-    return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
+	return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
 }
 #endif /* CONFIG_ATARI */
 
-
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 static int sound_set_treble(int treble)
 {
-    return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
+	return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
 }
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
 
 
 static long sound_copy_translate(const u_char *userPtr,
@@ -2462,38 +3430,38 @@
 				 u_char frame[], long *frameUsed,
 				 long frameLeft)
 {
-    long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
+	long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
 
-    switch (sound.soft.format) {
+	switch (sound.soft.format) {
 	case AFMT_MU_LAW:
-	    ct_func = sound.trans->ct_ulaw;
-	    break;
+		ct_func = sound.trans->ct_ulaw;
+		break;
 	case AFMT_A_LAW:
-	    ct_func = sound.trans->ct_alaw;
-	    break;
+		ct_func = sound.trans->ct_alaw;
+		break;
 	case AFMT_S8:
-	    ct_func = sound.trans->ct_s8;
-	    break;
+		ct_func = sound.trans->ct_s8;
+		break;
 	case AFMT_U8:
-	    ct_func = sound.trans->ct_u8;
-	    break;
+		ct_func = sound.trans->ct_u8;
+		break;
 	case AFMT_S16_BE:
-	    ct_func = sound.trans->ct_s16be;
-	    break;
+		ct_func = sound.trans->ct_s16be;
+		break;
 	case AFMT_U16_BE:
-	    ct_func = sound.trans->ct_u16be;
-	    break;
+		ct_func = sound.trans->ct_u16be;
+		break;
 	case AFMT_S16_LE:
-	    ct_func = sound.trans->ct_s16le;
-	    break;
+		ct_func = sound.trans->ct_s16le;
+		break;
 	case AFMT_U16_LE:
-	    ct_func = sound.trans->ct_u16le;
-	    break;
-    }
-    if (ct_func)
-	return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
-    else
-	return(0);
+		ct_func = sound.trans->ct_u16le;
+		break;
+	}
+	if (ct_func)
+		return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+	else
+		return(0);
 }
 
 
@@ -2509,201 +3477,308 @@
 
 static void mixer_init(void)
 {
-    mixer.busy = 0;
-    sound.treble = 0;
-    sound.bass = 0;
-    switch (sound.mach.type) {
+	mixer.busy = 0;
+	sound.treble = 0;
+	sound.bass = 0;
+	switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
 	case DMASND_TT:
-	    atari_microwire_cmd(MW_LM1992_VOLUME(0));
-	    sound.volume_left = 0;
-	    atari_microwire_cmd(MW_LM1992_BALLEFT(0));
-	    sound.volume_right = 0;
-	    atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
-	    atari_microwire_cmd(MW_LM1992_TREBLE(0));
-	    atari_microwire_cmd(MW_LM1992_BASS(0));
-	    break;
+		atari_microwire_cmd(MW_LM1992_VOLUME(0));
+		sound.volume_left = 0;
+		atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+		sound.volume_right = 0;
+		atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+		atari_microwire_cmd(MW_LM1992_TREBLE(0));
+		atari_microwire_cmd(MW_LM1992_BASS(0));
+		break;
 	case DMASND_FALCON:
-	    sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
-	    sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
-	    break;
+		sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+		sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+		break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 	case DMASND_AMIGA:
-	    sound.volume_left = 64;
-	    sound.volume_right = 64;
-	    custom.aud[0].audvol = sound.volume_left;
-	    custom.aud[3].audvol = 1;			/* For pseudo 14bit */
-	    custom.aud[1].audvol = sound.volume_right;
-	    custom.aud[2].audvol = 1;			/* For pseudo 14bit */
-	    sound.treble = 50;
-	    break;
+		sound.volume_left = 64;
+		sound.volume_right = 64;
+		custom.aud[0].audvol = sound.volume_left;
+		custom.aud[3].audvol = 1;	/* For pseudo 14bit */
+		custom.aud[1].audvol = sound.volume_right;
+		custom.aud[2].audvol = 1;	/* For pseudo 14bit */
+		sound.treble = 50;
+		break;
 #endif /* CONFIG_AMIGA */
-    }
+	}
 }
 
 
 static int mixer_open(int open_mode)
 {
-    if (mixer.busy)
-	return(-EBUSY);
-    mixer.busy = 1;
-    return(0);
+	mixer.busy = 1;
+	return(0);
 }
 
 
 static int mixer_release(void)
 {
-    mixer.busy = 0;
-    return(0);
+	mixer.busy = 0;
+	return(0);
 }
 
 
 static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg)
 {
-    int data;
-    switch (sound.mach.type) {
+	int data;
+	switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
 	case DMASND_FALCON:
-	    switch (cmd) {
+		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
 		case SOUND_MIXER_READ_RECMASK:
-		    return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+			return(IOCTL_OUT(arg, SOUND_MASK_MIC));
 		case SOUND_MIXER_READ_STEREODEVS:
-		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
 		case SOUND_MIXER_READ_CAPS:
-		    return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+			return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
 		case SOUND_MIXER_READ_VOLUME:
-		    return(IOCTL_OUT(arg,
-			VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-			VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+			return(IOCTL_OUT(arg,
+				VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+				VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
 		case SOUND_MIXER_WRITE_MIC:
-		    IOCTL_IN(arg, data);
-		    tt_dmasnd.input_gain =
-			RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
-			RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
-		    /* fall thru, return set value */
+			IOCTL_IN(arg, data);
+			tt_dmasnd.input_gain =
+				RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+				RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+			/* fall thru, return set value */
 		case SOUND_MIXER_READ_MIC:
-		    return(IOCTL_OUT(arg,
-			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
-			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+			return(IOCTL_OUT(arg,
+				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
 		case SOUND_MIXER_READ_SPEAKER:
-		    {
-			int porta;
-			cli();
-			sound_ym.rd_data_reg_sel = 14;
-			porta = sound_ym.rd_data_reg_sel;
-			sti();
-			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-		    }
+			{
+				int porta;
+				cli();
+				sound_ym.rd_data_reg_sel = 14;
+				porta = sound_ym.rd_data_reg_sel;
+				sti();
+				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+			}
 		case SOUND_MIXER_WRITE_VOLUME:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_volume(data)));
-		case SOUND_MIXER_WRITE_SPEAKER:
-		    {
-			int porta;
 			IOCTL_IN(arg, data);
-			cli();
-			sound_ym.rd_data_reg_sel = 14;
-			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-				(data < 50 ? 0x40 : 0);
-			sound_ym.wd_data = porta;
-			sti();
-			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-		    }
-	    }
-	    break;
+			return(IOCTL_OUT(arg, sound_set_volume(data)));
+		case SOUND_MIXER_WRITE_SPEAKER:
+			{
+				int porta;
+				IOCTL_IN(arg, data);
+				cli();
+				sound_ym.rd_data_reg_sel = 14;
+				porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+					(data < 50 ? 0x40 : 0);
+				sound_ym.wd_data = porta;
+				sti();
+				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+			}
+		}
+		break;
 
 	case DMASND_TT:
-	    switch (cmd) {
+		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-		    return(IOCTL_OUT(arg,
-			SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
-			(MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
+			return(IOCTL_OUT(arg,
+					 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+					 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
 		case SOUND_MIXER_READ_RECMASK:
-		    return(IOCTL_OUT(arg, 0));
+			return(IOCTL_OUT(arg, 0));
 		case SOUND_MIXER_READ_STEREODEVS:
-		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
 		case SOUND_MIXER_READ_VOLUME:
-		    return(IOCTL_OUT(arg,
-			VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-			(VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+			return(IOCTL_OUT(arg,
+					 VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+					 (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
 		case SOUND_MIXER_READ_BASS:
-		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+			return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
 		case SOUND_MIXER_READ_TREBLE:
-		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+			return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
 		case SOUND_MIXER_READ_OGAIN:
-		    return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
+			return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
 		case SOUND_MIXER_READ_SPEAKER:
-		    {
-			int porta;
-			if (MACH_IS_TT) {
-			    cli();
-			    sound_ym.rd_data_reg_sel = 14;
-			    porta = sound_ym.rd_data_reg_sel;
-			    sti();
-			    return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-			} else
-			    return(-EINVAL);
-		    }
+			{
+				int porta;
+				if (MACH_IS_TT) {
+					cli();
+					sound_ym.rd_data_reg_sel = 14;
+					porta = sound_ym.rd_data_reg_sel;
+					sti();
+					return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+				} else
+					return(-EINVAL);
+			}
 		case SOUND_MIXER_WRITE_VOLUME:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_volume(data)));
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_volume(data)));
 		case SOUND_MIXER_WRITE_BASS:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_bass(data)));
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_bass(data)));
 		case SOUND_MIXER_WRITE_TREBLE:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_treble(data)));
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_treble(data)));
 		case SOUND_MIXER_WRITE_OGAIN:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_gain(data)));
-		case SOUND_MIXER_WRITE_SPEAKER:
-		    if (MACH_IS_TT) {
-			int porta;
 			IOCTL_IN(arg, data);
-			cli();
-			sound_ym.rd_data_reg_sel = 14;
-			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-				(data < 50 ? 0x40 : 0);
-			sound_ym.wd_data = porta;
-			sti();
-			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-		    } else
-			return(-EINVAL);
-	    }
-	    break;
+			return(IOCTL_OUT(arg, sound_set_gain(data)));
+		case SOUND_MIXER_WRITE_SPEAKER:
+			if (MACH_IS_TT) {
+				int porta;
+				IOCTL_IN(arg, data);
+				cli();
+				sound_ym.rd_data_reg_sel = 14;
+				porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+					(data < 50 ? 0x40 : 0);
+				sound_ym.wd_data = porta;
+				sti();
+				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+			} else
+				return(-EINVAL);
+		}
+		break;
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
 	case DMASND_AMIGA:
-	    switch (cmd) {
+		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
 		case SOUND_MIXER_READ_RECMASK:
-		    return(IOCTL_OUT(arg, 0));
+			return(IOCTL_OUT(arg, 0));
 		case SOUND_MIXER_READ_STEREODEVS:
-		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
 		case SOUND_MIXER_READ_VOLUME:
-		    return(IOCTL_OUT(arg,
-			VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-			VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+			return(IOCTL_OUT(arg,
+				VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+				VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
 		case SOUND_MIXER_WRITE_VOLUME:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_volume(data)));
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_volume(data)));
 		case SOUND_MIXER_READ_TREBLE:
-		    return(IOCTL_OUT(arg, sound.treble));
+			return(IOCTL_OUT(arg, sound.treble));
 		case SOUND_MIXER_WRITE_TREBLE:
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_treble(data)));
-	    }
-	    break;
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_treble(data)));
+		}
+		break;
 #endif /* CONFIG_AMIGA */
-    }
 
-    return(-EINVAL);
+#ifdef CONFIG_PMAC
+	case DMASND_AWACS:
+		switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+				| SOUND_MASK_LINE | SOUND_MASK_MIC
+				| SOUND_MASK_CD | SOUND_MASK_RECLEV
+				| SOUND_MASK_ALTPCM;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECMASK:
+			data = SOUND_MASK_LINE | SOUND_MASK_MIC
+				| SOUND_MASK_CD;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECSRC:
+			data = 0;
+			if (awacs_reg[0] & MASK_MUX_AUDIN)
+				data |= SOUND_MASK_LINE;
+			if (awacs_reg[0] & MASK_MUX_MIC)
+				data |= SOUND_MASK_MIC;
+			if (awacs_reg[0] & MASK_MUX_CD)
+				data |= SOUND_MASK_CD;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECSRC:
+			IOCTL_IN(arg, data);
+			data &= (SOUND_MASK_LINE
+				 | SOUND_MASK_MIC | SOUND_MASK_CD);
+			awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+					| MASK_MUX_AUDIN);
+			if (data & SOUND_MASK_LINE)
+				awacs_reg[0] |= MASK_MUX_AUDIN;
+			if (data & SOUND_MASK_MIC)
+				awacs_reg[0] |= MASK_MUX_MIC;
+			if (data & SOUND_MASK_CD)
+				awacs_reg[0] |= MASK_MUX_CD;
+			awacs_write(awacs_reg[0] | MASK_ADDR0);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_STEREODEVS:
+			data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+				| SOUND_MASK_RECLEV;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_CAPS:
+			return IOCTL_OUT(arg, 0);
+		case SOUND_MIXER_READ_VOLUME:
+			data = (awacs_reg[1] & MASK_AMUTE)? 0:
+				awacs_get_volume(awacs_reg[2], 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_VOLUME:
+			IOCTL_IN(arg, data);
+			return IOCTL_OUT(arg, sound_set_volume(data));
+		case SOUND_MIXER_READ_SPEAKER:
+			data = (awacs_reg[1] & MASK_CMUTE)? 0:
+				awacs_get_volume(awacs_reg[4], 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_SPEAKER:
+			IOCTL_IN(arg, data);
+			data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
+			IOCTL_IN(arg, data);
+			beep_volume = data & 0xff;
+			/* fall through */
+		case SOUND_MIXER_READ_ALTPCM:
+			return IOCTL_OUT(arg, beep_volume);
+		case SOUND_MIXER_WRITE_LINE:
+			IOCTL_IN(arg, data);
+			awacs_reg[0] &= ~MASK_MUX_AUDIN;
+			if ((data & 0xff) >= 50)
+				awacs_reg[0] |= MASK_MUX_AUDIN;
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_LINE:
+			data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_MIC:
+			IOCTL_IN(arg, data);
+			data &= 0xff;
+			awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+			if (data >= 25) {
+				awacs_reg[0] |= MASK_MUX_MIC;
+				if (data >= 75)
+					awacs_reg[0] |= MASK_GAINLINE;
+			}
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_MIC:
+			data = (awacs_reg[0] & MASK_MUX_MIC)?
+				(awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_CD:
+			IOCTL_IN(arg, data);
+			awacs_reg[0] &= ~MASK_MUX_CD;
+			if ((data & 0xff) >= 50)
+				awacs_reg[0] |= MASK_MUX_CD;
+			awacs_write(MASK_ADDR0 | awacs_reg[0]);
+			/* fall through */
+		case SOUND_MIXER_READ_CD:
+			data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_WRITE_RECLEV:
+			IOCTL_IN(arg, data);
+			data = awacs_volume_setter(data, 0, 0, 4);
+			return IOCTL_OUT(arg, data);
+		case SOUND_MIXER_READ_RECLEV:
+			data = awacs_get_volume(awacs_reg[0], 4);
+			return IOCTL_OUT(arg, data);
+		}
+		break;
+#endif
+	}
+
+	return(-EINVAL);
 }
 
 
@@ -2715,62 +3790,88 @@
 
 static void sq_init(int numBufs, int bufSize, char **buffers)
 {
-    sq.max_count = numBufs;
-    sq.block_size = bufSize;
-    sq.buffers = buffers;
-
-    sq.front = sq.count = 0;
-    sq.rear = -1;
-    sq.write_queue = sq.open_queue = sq.sync_queue = 0;
-    sq.busy = 0;
-    sq.syncing = 0;
+#ifdef CONFIG_PMAC
+	int i;
+	volatile struct dbdma_cmd *cp;
+#endif /* CONFIG_PMAC */
+
+	sq.max_count = numBufs;
+	sq.max_active = numBufs;
+	sq.block_size = bufSize;
+	sq.buffers = buffers;
+
+	sq.front = sq.count = 0;
+	sq.rear = -1;
+	sq.write_queue = sq.open_queue = sq.sync_queue = 0;
+	sq.busy = 0;
+	sq.syncing = 0;
 
-    sq.playing = 0;
+	sq.playing = 0;
 
 #ifdef CONFIG_ATARI
-    sq.ignore_int = 0;
+	sq.ignore_int = 0;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-    sq.block_size_half = sq.block_size>>1;
-    sq.block_size_quarter = sq.block_size_half>>1;
+	sq.block_size_half = sq.block_size>>1;
+	sq.block_size_quarter = sq.block_size_half>>1;
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+	cp = awacs_tx_cmds;
+	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
+	for (i = 0; i < numBufs; ++i, ++cp) {
+		st_le32(&cp->phy_addr, virt_to_bus(buffers[i]));
+	}
+	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+#endif /* CONFIG_PMAC */
+}
+
+static void
+init_settings(void)
+{
+	/* whatever you like as startup mode for /dev/dsp,
+	 * (/dev/audio hasn't got a startup mode). note that
+	 * once changed a new open() will *not* restore these!
+	 */
+	sound.dsp.format = AFMT_U8;
+	sound.dsp.stereo = 0;
+	sound.dsp.size = 8;
 
-    sound_silence();
-
-    /* whatever you like as startup mode for /dev/dsp,
-     * (/dev/audio hasn't got a startup mode). note that
-     * once changed a new open() will *not* restore these!
-     */
-    sound.dsp.format = AFMT_S8;
-    sound.dsp.stereo = 0;
-    sound.dsp.size = 8;
-
-    /* set minimum rate possible without expanding */
-    switch (sound.mach.type) {
+	/* set minimum rate possible without expanding */
+	switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
 	case DMASND_TT:
-	    sound.dsp.speed = 6258;
-	    break;
+		sound.dsp.speed = 6258;
+		break;
 	case DMASND_FALCON:
-	    sound.dsp.speed = 8195;
-	    break;
+		sound.dsp.speed = 8195;
+		break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 	case DMASND_AMIGA:
-	    sound.dsp.speed = 8000;
-	    break;
+		sound.dsp.speed = 8000;
+		break;
 #endif /* CONFIG_AMIGA */
-    }
+#ifdef CONFIG_PMAC
+	case DMASND_AWACS:
+		sound.dsp.speed = 8000;
+		break;
+#endif /* CONFIG_PMAC */
+	}
+
+	/* before the first open to /dev/dsp this wouldn't be set */
+	sound.soft = sound.dsp;
+	sound.hard = sound.dsp;
 
-    /* before the first open to /dev/dsp this wouldn't be set */
-    sound.soft = sound.dsp;
-    sound.hard = sound.dsp;
+	sound_silence();
 }
 
 
 static void sq_play(void)
 {
-    (*sound.mach.play)();
+	(*sound.mach.play)();
 }
 
 
@@ -2778,133 +3879,139 @@
 
 static long sq_write(const char *src, unsigned long uLeft)
 {
-    long uWritten = 0;
-    u_char *dest;
-    long uUsed, bUsed, bLeft;
-
-    /* ++TeSche: Is something like this necessary?
-     * Hey, that's an honest question! Or does any other part of the
-     * filesystem already checks this situation? I really don't know.
-     */
-    if (uLeft == 0)
-	return(0);
+	long uWritten = 0;
+	u_char *dest;
+	long uUsed, bUsed, bLeft;
+
+	/* ++TeSche: Is something like this necessary?
+	 * Hey, that's an honest question! Or does any other part of the
+	 * filesystem already checks this situation? I really don't know.
+	 */
+	if (uLeft == 0)
+		return(0);
 
-    /* The interrupt doesn't start to play the last, incomplete frame.
-     * Thus we can append to it without disabling the interrupts! (Note
-     * also that sq.rear isn't affected by the interrupt.)
-     */
-
-    if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
-	dest = sq_block_address(sq.rear);
-	bUsed = sq.rear_size;
-	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-	src += uUsed;
-	uWritten += uUsed;
-	uLeft -= uUsed;
-	sq.rear_size = bUsed;
-    }
-
-    do {
-	while (sq.count == sq.max_count) {
-	    sq_play();
-	    if (NON_BLOCKING(sq.open_mode))
-		return(uWritten > 0 ? uWritten : -EAGAIN);
-	    SLEEP(sq.write_queue, ONE_SECOND);
-	    if (SIGNAL_RECEIVED)
-		return(uWritten > 0 ? uWritten : -EINTR);
-	}
-
-	/* Here, we can avoid disabling the interrupt by first
-	 * copying and translating the data, and then updating
-	 * the sq variables. Until this is done, the interrupt
-	 * won't see the new frame and we can work on it
-	 * undisturbed.
+	/* The interrupt doesn't start to play the last, incomplete frame.
+	 * Thus we can append to it without disabling the interrupts! (Note
+	 * also that sq.rear isn't affected by the interrupt.)
 	 */
 
-	dest = sq_block_address((sq.rear+1) % sq.max_count);
-	bUsed = 0;
-	bLeft = sq.block_size;
-	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-	src += uUsed;
-	uWritten += uUsed;
-	uLeft -= uUsed;
-	if (bUsed) {
-	    sq.rear = (sq.rear+1) % sq.max_count;
-	    sq.rear_size = bUsed;
-	    sq.count++;
-	}
-    } while (bUsed);   /* uUsed may have been 0 */
+	if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
+		dest = sq_block_address(sq.rear);
+		bUsed = sq.rear_size;
+		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+		if (uUsed <= 0)
+			return uUsed;
+		src += uUsed;
+		uWritten += uUsed;
+		uLeft -= uUsed;
+		sq.rear_size = bUsed;
+	}
+
+	do {
+		while (sq.count == sq.max_active) {
+			sq_play();
+			if (NON_BLOCKING(sq.open_mode))
+				return(uWritten > 0 ? uWritten : -EAGAIN);
+			SLEEP(sq.write_queue, ONE_SECOND);
+			if (SIGNAL_RECEIVED)
+				return(uWritten > 0 ? uWritten : -EINTR);
+		}
 
-    sq_play();
+		/* Here, we can avoid disabling the interrupt by first
+		 * copying and translating the data, and then updating
+		 * the sq variables. Until this is done, the interrupt
+		 * won't see the new frame and we can work on it
+		 * undisturbed.
+		 */
+
+		dest = sq_block_address((sq.rear+1) % sq.max_count);
+		bUsed = 0;
+		bLeft = sq.block_size;
+		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+		if (uUsed <= 0)
+			break;
+		src += uUsed;
+		uWritten += uUsed;
+		uLeft -= uUsed;
+		if (bUsed) {
+			sq.rear = (sq.rear+1) % sq.max_count;
+			sq.rear_size = bUsed;
+			sq.count++;
+		}
+	} while (bUsed);   /* uUsed may have been 0 */
 
-    return(uWritten);
+	sq_play();
+
+	return(uUsed < 0? uUsed: uWritten);
 }
 
 
 static int sq_open(int open_mode)
 {
-    if (sq.busy) {
-	if (NON_BLOCKING(open_mode))
-	    return(-EBUSY);
-	while (sq.busy) {
-	    SLEEP(sq.open_queue, ONE_SECOND);
-	    if (SIGNAL_RECEIVED)
-		return(-EINTR);
-	}
-    }
-    sq.open_mode = open_mode;
-    sq.busy = 1;
+	if (sq.busy) {
+		if (NON_BLOCKING(open_mode))
+			return(-EBUSY);
+		while (sq.busy) {
+			SLEEP(sq.open_queue, ONE_SECOND);
+			if (SIGNAL_RECEIVED)
+				return(-EINTR);
+		}
+	}
+	sq_init(numBufs, bufSize << 10, sound_buffers);
+	sq.open_mode = open_mode;
+	sq.busy = 1;
 #ifdef CONFIG_ATARI
-    sq.ignore_int = 1;
+	sq.ignore_int = 1;
 #endif /* CONFIG_ATARI */
-    return(0);
+	return(0);
 }
 
 
 static void sq_reset(void)
 {
-    sound_silence();
-    sq.playing = 0;
-    sq.count = 0;
-    sq.front = (sq.rear+1) % sq.max_count;
+	sound_silence();
+	sq.playing = 0;
+	sq.count = 0;
+	sq.front = (sq.rear+1) % sq.max_count;
 }
 
 
 static int sq_sync(void)
 {
-    int rc = 0;
+	int rc = 0;
 
-    sq.syncing = 1;
-    sq_play();	/* there may be an incomplete frame waiting */
+	sq.syncing = 1;
+	sq_play();	/* there may be an incomplete frame waiting */
 
-    while (sq.playing) {
-	SLEEP(sq.sync_queue, ONE_SECOND);
-	if (SIGNAL_RECEIVED) {
-	    /* While waiting for audio output to drain, an interrupt occurred.
-	       Stop audio output immediately and clear the queue. */
-	    sq_reset();
-	    rc = -EINTR;
-	    break;
+	while (sq.playing) {
+		SLEEP(sq.sync_queue, ONE_SECOND);
+		if (SIGNAL_RECEIVED) {
+			/* While waiting for audio output to drain, an
+			 * interrupt occurred.  Stop audio output immediately
+			 * and clear the queue. */
+			sq_reset();
+			rc = -EINTR;
+			break;
+		}
 	}
-    }
 
-    sq.syncing = 0;
-    return(rc);
+	sq.syncing = 0;
+	return(rc);
 }
 
 
 static int sq_release(void)
 {
-    int rc = 0;
-    if (sq.busy) {
-	rc = sq_sync();
-	sq.busy = 0;
-	WAKE_UP(sq.open_queue);
-	/* Wake up a process waiting for the queue being released.
-	   Note: There may be several processes waiting for a call to open()
-		 returning. */
-    }
-    return(rc);
+	int rc = 0;
+	if (sq.busy) {
+		rc = sq_sync();
+		sq.busy = 0;
+		WAKE_UP(sq.open_queue);
+		/* Wake up a process waiting for the queue being released.
+		 * Note: There may be several processes waiting for a call
+		 * to open() returning. */
+	}
+	return(rc);
 }
 
 
@@ -2916,7 +4023,7 @@
 
 static void state_init(void)
 {
-    state.busy = 0;
+	state.busy = 0;
 }
 
 
@@ -2924,118 +4031,125 @@
 
 static int state_open(int open_mode)
 {
-    char *buffer = state.buf, *mach = "";
-    int len = 0;
+	char *buffer = state.buf, *mach = "";
+	int len = 0;
 
-    if (state.busy)
-	return(-EBUSY);
+	if (state.busy)
+		return(-EBUSY);
 
-    state.ptr = 0;
-    state.busy = 1;
+	state.ptr = 0;
+	state.busy = 1;
 
-    switch (sound.mach.type) {
+	switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
 	case DMASND_TT:
 	case DMASND_FALCON:
-	    mach = "Atari ";
-	    break;
+		mach = "Atari ";
+		break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 	case DMASND_AMIGA:
-	    mach = "Amiga ";
-	    break;
+		mach = "Amiga ";
+		break;
 #endif /* CONFIG_AMIGA */
-    }
-    len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
+#ifdef CONFIG_PMAC
+	case DMASND_AWACS:
+		mach = "PowerMac ";
+		break;
+#endif /* CONFIG_PMAC */
+	}
+	len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
 
-    len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-    switch (sound.soft.format) {
+	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+	switch (sound.soft.format) {
 	case AFMT_MU_LAW:
-	    len += sprintf(buffer+len, " (mu-law)");
-	    break;
+		len += sprintf(buffer+len, " (mu-law)");
+		break;
 	case AFMT_A_LAW:
-	    len += sprintf(buffer+len, " (A-law)");
-	    break;
+		len += sprintf(buffer+len, " (A-law)");
+		break;
 	case AFMT_U8:
-	    len += sprintf(buffer+len, " (unsigned 8 bit)");
-	    break;
+		len += sprintf(buffer+len, " (unsigned 8 bit)");
+		break;
 	case AFMT_S8:
-	    len += sprintf(buffer+len, " (signed 8 bit)");
-	    break;
+		len += sprintf(buffer+len, " (signed 8 bit)");
+		break;
 	case AFMT_S16_BE:
-	    len += sprintf(buffer+len, " (signed 16 bit big)");
-	    break;
+		len += sprintf(buffer+len, " (signed 16 bit big)");
+		break;
 	case AFMT_U16_BE:
-	    len += sprintf(buffer+len, " (unsigned 16 bit big)");
-	    break;
+		len += sprintf(buffer+len, " (unsigned 16 bit big)");
+		break;
 	case AFMT_S16_LE:
-	    len += sprintf(buffer+len, " (signed 16 bit little)");
-	    break;
+		len += sprintf(buffer+len, " (signed 16 bit little)");
+		break;
 	case AFMT_U16_LE:
-	    len += sprintf(buffer+len, " (unsigned 16 bit little)");
-	    break;
-    }
-    len += sprintf(buffer+len, "\n");
-    len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-		   sound.soft.speed, sound.hard.speed);
-    len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-		   sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-    switch (sound.mach.type) {
+		len += sprintf(buffer+len, " (unsigned 16 bit little)");
+		break;
+	}
+	len += sprintf(buffer+len, "\n");
+	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+		       sound.soft.speed, sound.hard.speed);
+	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+		       sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
+	switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
 	case DMASND_TT:
-	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
-			   sound.volume_left);
-	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
-			   sound.volume_right);
-	    len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
-			   sound.bass);
-	    len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
-			   sound.treble);
-	    break;
+		len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+			       sound.volume_left);
+		len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+			       sound.volume_right);
+		len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+			       sound.bass);
+		len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+			       sound.treble);
+		break;
 	case DMASND_FALCON:
-	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
-			   sound.volume_left);
-	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
-			   sound.volume_right);
-	    break;
+		len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+			       sound.volume_left);
+		len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+			       sound.volume_right);
+		break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 	case DMASND_AMIGA:
-	    len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
-			   sound.volume_left);
-	    len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
-			   sound.volume_right);
-	    break;
+		len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+			       sound.volume_left);
+		len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+			       sound.volume_right);
+		break;
 #endif /* CONFIG_AMIGA */
-    }
-    len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n",
-		   sq.block_size, sq.max_count);
-    len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-		   sq.rear_size);
-    len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
-		   sq.playing, sq.syncing);
-    state.len = len;
-    return(0);
+	}
+	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+		       " sq.max_active = %d\n",
+		       sq.block_size, sq.max_count, sq.max_active);
+	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
+		       sq.rear_size);
+	len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
+		       sq.playing, sq.syncing);
+	state.len = len;
+	return(0);
 }
 
 
 static int state_release(void)
 {
-    state.busy = 0;
-    return(0);
+	state.busy = 0;
+	return(0);
 }
 
 
 static long state_read(char *dest, unsigned long count)
 {
-    int n = state.len-state.ptr;
-    if (n > count)
-	n = count;
-    if (n <= 0)
-	return(0);
-    copy_to_user(dest, &state.buf[state.ptr], n);
-    state.ptr += n;
-    return(n);
+	int n = state.len-state.ptr;
+	if (n > count)
+		n = count;
+	if (n <= 0)
+		return(0);
+	if (copy_to_user(dest, &state.buf[state.ptr], n))
+		return -EFAULT;
+	state.ptr += n;
+	return(n);
 }
 
 
@@ -3045,230 +4159,252 @@
 
 static int sound_open(struct inode *inode, struct file *file)
 {
-    int dev = MINOR(inode->i_rdev) & 0x0f;
-    int rc = 0;
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+	int rc = 0;
 
-    switch (dev) {
+	switch (dev) {
 	case SND_DEV_STATUS:
-	    rc = state_open(file->f_flags);
-	    break;
+		rc = state_open(file->f_flags);
+		break;
 	case SND_DEV_CTL:
-	    rc = mixer_open(file->f_flags);
-	    break;
+		rc = mixer_open(file->f_flags);
+		break;
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO:
-	    rc = sq_open(file->f_flags);
-	    if (rc == 0) {
-		sound.minDev = dev;
-		sound.soft = sound.dsp;
-		sound.hard = sound.dsp;
-		sound_init();
-		if (dev == SND_DEV_AUDIO) {
-		    sound_set_speed(8000);
-		    sound_set_stereo(0);
-		    sound_set_format(AFMT_MU_LAW);
+		rc = sq_open(file->f_flags);
+		if (rc == 0) {
+			sound.minDev = dev;
+			sound.soft = sound.dsp;
+			sound.hard = sound.dsp;
+			sound_init();
+			if (dev == SND_DEV_AUDIO) {
+				sound_set_speed(8000);
+				sound_set_stereo(0);
+				sound_set_format(AFMT_MU_LAW);
+			}
 		}
-	    }
-	    break;
+		break;
 	default:
-	    rc = -ENXIO;
-    }
+		rc = -ENXIO;
+	}
 #ifdef MODULE
-    if (rc >= 0)
-	MOD_INC_USE_COUNT;
+	if (rc >= 0)
+		MOD_INC_USE_COUNT;
 #endif
-    return(rc);
+	return(rc);
 }
 
 
 static int sound_fsync(struct file *filp, struct dentry *dentry)
 {
-    int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
+	int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
 
-    switch (dev) {
+	switch (dev) {
 	case SND_DEV_STATUS:
 	case SND_DEV_CTL:
-	    return(0);
+		return(0);
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO:
-	    return(sq_sync());
+		return(sq_sync());
 	default:
-	    return(unknown_minor_dev("sound_fsync", dev));
-    }
+		return(unknown_minor_dev("sound_fsync", dev));
+	}
 }
 
 
 static int sound_release(struct inode *inode, struct file *file)
 {
-    int dev = MINOR(inode->i_rdev);
+	int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+	switch (dev & 0x0f) {
 	case SND_DEV_STATUS:
-	    state_release();
-	    break;
+		state_release();
+		break;
 	case SND_DEV_CTL:
-	    mixer_release();
-	    break;
+		mixer_release();
+		break;
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO:
-	    sq_release();
-	    sound.soft = sound.dsp;
-	    sound.hard = sound.dsp;
-	    sound_silence();
-	    break;
+		sq_release();
+		sound.soft = sound.dsp;
+		sound.hard = sound.dsp;
+		sound_silence();
+		break;
 	default:
-	    return unknown_minor_dev("sound_release", dev);
-    }
+		return unknown_minor_dev("sound_release", dev);
+	}
 #ifdef MODULE
-    MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 #endif
-    return 0;
+	return 0;
 }
 
 
 static long long sound_lseek(struct file *file, long long offset, int orig)
 {
-    return -ESPIPE;
+	return -ESPIPE;
 }
 
 
 static ssize_t sound_read(struct file *file, char *buf, size_t count,
 			  loff_t *ppos)
 {
-    struct inode *inode = file->f_dentry->d_inode;
-    int dev = MINOR(inode->i_rdev);
+	struct inode *inode = file->f_dentry->d_inode;
+	int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+	switch (dev & 0x0f) {
 	case SND_DEV_STATUS:
-	    return(state_read(buf, count));
+		return(state_read(buf, count));
 	case SND_DEV_CTL:
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO:
-	    return(-EPERM);
+		return(-EPERM);
 	default:
-	    return(unknown_minor_dev("sound_read", dev));
-    }
+		return(unknown_minor_dev("sound_read", dev));
+	}
 }
 
 
 static ssize_t sound_write(struct file *file, const char *buf, size_t count,
 			   loff_t *ppos)
 {
-    struct inode *inode = file->f_dentry->d_inode;
-    int dev = MINOR(inode->i_rdev);
+	struct inode *inode = file->f_dentry->d_inode;
+	int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+	switch (dev & 0x0f) {
 	case SND_DEV_STATUS:
 	case SND_DEV_CTL:
-	    return(-EPERM);
+		return(-EPERM);
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO:
-	    return(sq_write(buf, count));
+		return(sq_write(buf, count));
 	default:
-	    return(unknown_minor_dev("sound_write", dev));
-    }
+		return(unknown_minor_dev("sound_write", dev));
+	}
 }
 
 
 static int unknown_minor_dev(char *fname, int dev)
 {
-    /* printk("%s: Unknown minor device %d\n", fname, dev); */
-    return(-ENXIO);
+	/* printk("%s: Unknown minor device %d\n", fname, dev); */
+	return(-ENXIO);
 }
 
 
 static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg)
 {
-    int dev = MINOR(inode->i_rdev);
-    u_long fmt;
-    int data;
+	int dev = MINOR(inode->i_rdev);
+	u_long fmt;
+	int data;
+	int size, nbufs;
 
-    switch (dev & 0x0f) {
+	switch (dev & 0x0f) {
 	case SND_DEV_STATUS:
-	    return(-EPERM);
+		return(-EPERM);
 	case SND_DEV_CTL:
-	    return(mixer_ioctl(inode, file, cmd, arg));
+		return(mixer_ioctl(inode, file, cmd, arg));
 	case SND_DEV_AUDIO:
 	case SND_DEV_DSP:
-	    switch (cmd) {
+		switch (cmd) {
 		case SNDCTL_DSP_RESET:
-		    sq_reset();
-		    return(0);
+			sq_reset();
+			return(0);
 		case SNDCTL_DSP_POST:
 		case SNDCTL_DSP_SYNC:
-		    return(sound_fsync(file, file->f_dentry));
+			return(sound_fsync(file, file->f_dentry));
 
-		/* ++TeSche: before changing any of these it's probably wise to
-		 * wait until sound playing has settled down
-		 */
+			/* ++TeSche: before changing any of these it's
+			 * probably wise to wait until sound playing has
+			 * settled down. */
 		case SNDCTL_DSP_SPEED:
-		    sound_fsync(file, file->f_dentry);
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_speed(data)));
+			sound_fsync(file, file->f_dentry);
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_speed(data)));
 		case SNDCTL_DSP_STEREO:
-		    sound_fsync(file, file->f_dentry);
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_stereo(data)));
+			sound_fsync(file, file->f_dentry);
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_stereo(data)));
 		case SOUND_PCM_WRITE_CHANNELS:
-		    sound_fsync(file, file->f_dentry);
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
+			sound_fsync(file, file->f_dentry);
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
 		case SNDCTL_DSP_SETFMT:
-		    sound_fsync(file, file->f_dentry);
-		    IOCTL_IN(arg, data);
-		    return(IOCTL_OUT(arg, sound_set_format(data)));
+			sound_fsync(file, file->f_dentry);
+			IOCTL_IN(arg, data);
+			return(IOCTL_OUT(arg, sound_set_format(data)));
 		case SNDCTL_DSP_GETFMTS:
-		    fmt = 0;
-		    if (sound.trans) {
-			if (sound.trans->ct_ulaw)
-			    fmt |= AFMT_MU_LAW;
-			if (sound.trans->ct_alaw)
-			    fmt |= AFMT_A_LAW;
-			if (sound.trans->ct_s8)
-			    fmt |= AFMT_S8;
-			if (sound.trans->ct_u8)
-			    fmt |= AFMT_U8;
-			if (sound.trans->ct_s16be)
-			    fmt |= AFMT_S16_BE;
-			if (sound.trans->ct_u16be)
-			    fmt |= AFMT_U16_BE;
-			if (sound.trans->ct_s16le)
-			    fmt |= AFMT_S16_LE;
-			if (sound.trans->ct_u16le)
-			    fmt |= AFMT_U16_LE;
-		    }
-		    return(IOCTL_OUT(arg, fmt));
+			fmt = 0;
+			if (sound.trans) {
+				if (sound.trans->ct_ulaw)
+					fmt |= AFMT_MU_LAW;
+				if (sound.trans->ct_alaw)
+					fmt |= AFMT_A_LAW;
+				if (sound.trans->ct_s8)
+					fmt |= AFMT_S8;
+				if (sound.trans->ct_u8)
+					fmt |= AFMT_U8;
+				if (sound.trans->ct_s16be)
+					fmt |= AFMT_S16_BE;
+				if (sound.trans->ct_u16be)
+					fmt |= AFMT_U16_BE;
+				if (sound.trans->ct_s16le)
+					fmt |= AFMT_S16_LE;
+				if (sound.trans->ct_u16le)
+					fmt |= AFMT_U16_LE;
+			}
+			return(IOCTL_OUT(arg, fmt));
 		case SNDCTL_DSP_GETBLKSIZE:
-		    return(IOCTL_OUT(arg, 10240));
+			size = sq.block_size
+				* sound.soft.size * (sound.soft.stereo + 1)
+				/ (sound.hard.size * (sound.hard.stereo + 1));
+			return(IOCTL_OUT(arg, size));
 		case SNDCTL_DSP_SUBDIVIDE:
+			break;
 		case SNDCTL_DSP_SETFRAGMENT:
-		    break;
+			if (sq.count || sq.playing || sq.syncing)
+				return -EINVAL;
+			IOCTL_IN(arg, size);
+			nbufs = size >> 16;
+			if (nbufs < 2 || nbufs > numBufs)
+				nbufs = numBufs;
+			size &= 0xffff;
+			if (size >= 8 && size <= 30) {
+				size = 1 << size;
+				size *= sound.hard.size * (sound.hard.stereo + 1);
+				size /= sound.soft.size * (sound.soft.stereo + 1);
+				if (size > (bufSize << 10))
+					size = bufSize << 10;
+			} else
+				size = bufSize << 10;
+			sq_init(numBufs, size, sound_buffers);
+			sq.max_active = nbufs;
+			break;
 
 		default:
-		    return(mixer_ioctl(inode, file, cmd, arg));
-	    }
-	    break;
+			return(mixer_ioctl(inode, file, cmd, arg));
+		}
+		break;
 
 	default:
-	    return(unknown_minor_dev("sound_ioctl", dev));
-    }
-    return(-EINVAL);
+		return(unknown_minor_dev("sound_ioctl", dev));
+	}
+	return(-EINVAL);
 }
 
 
 static struct file_operations sound_fops =
 {
-    sound_lseek,
-    sound_read,
-    sound_write,
-    NULL,
-    NULL,                      /* select */
-    sound_ioctl,
-    NULL,
-    sound_open,
-    sound_release,
-    sound_fsync
+	sound_lseek,
+	sound_read,
+	sound_write,
+	NULL,
+	NULL,                      /* select */
+	sound_ioctl,
+	NULL,
+	sound_open,
+	sound_release,
+	sound_fsync
 };
 
 
@@ -3278,87 +4414,142 @@
 
 void soundcard_init(void)
 {
-    int has_sound = 0;
-    int i;
+	int has_sound = 0;
+	int i;
 
-    switch (m68k_machtype) {
+#ifdef __mc68000__
+	switch (m68k_machtype) {
 #ifdef CONFIG_ATARI
 	case MACH_ATARI:
-	    if (ATARIHW_PRESENT(PCM_8BIT)) {
-		if (ATARIHW_PRESENT(CODEC))
-		    sound.mach = machFalcon;
-		else if (ATARIHW_PRESENT(MICROWIRE))
-		    sound.mach = machTT;
-		else
-		    break;
-		if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
-		    has_sound = 1;
-		else
-		    printk("DMA sound driver: Timer A interrupt already in use\n");
-	    }
-	    break;
+		if (ATARIHW_PRESENT(PCM_8BIT)) {
+			if (ATARIHW_PRESENT(CODEC))
+				sound.mach = machFalcon;
+			else if (ATARIHW_PRESENT(MICROWIRE))
+				sound.mach = machTT;
+			else
+				break;
+			if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+				has_sound = 1;
+			else
+				printk("DMA sound driver: Timer A interrupt already in use\n");
+		}
+		break;
 
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 	case MACH_AMIGA:
-	    if (AMIGAHW_PRESENT(AMI_AUDIO)) {
-		sound.mach = machAmiga;
-		has_sound = 1;
-	    }
-	    break;
+		if (AMIGAHW_PRESENT(AMI_AUDIO)) {
+			sound.mach = machAmiga;
+			has_sound = 1;
+		}
+		break;
 #endif /* CONFIG_AMIGA */
-    }
-    if (!has_sound)
-	return;
+	}
+#endif /* __mc68000__ */
 
-    /* Set up sound queue, /dev/audio and /dev/dsp. */
-    sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
-    if (!sound_buffers) {
-out_of_memory:
-	printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
-	return;
-    }
-    for (i = 0; i < numBufs; i++) {
-	sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
-	if (!sound_buffers[i]) {
-	    while (i--)
-		sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-	    kfree (sound_buffers);
-	    sound_buffers = 0;
-	    goto out_of_memory;
-        }
-    }
+#ifdef CONFIG_PMAC
+	struct device_node *np;
+
+	np = find_devices("awacs");
+	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+		int vol;
+		sound.mach = machPMac;
+		has_sound = 1;
+		awacs = (volatile struct awacs_regs *)
+			ioremap(np->addrs[0].address, 0x80);
+		awacs_txdma = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[1].address, 0x100);
+		awacs_rxdma = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[2].address, 0x100);
+		awacs_irq = np->intrs[0].line;
+		awacs_tx_irq = np->intrs[1].line;
+		awacs_rx_irq = np->intrs[2].line;
+		awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
+					     GFP_KERNEL);
+		if (awacs_tx_cmd_space == NULL)
+			goto out_of_memory;
+		awacs_tx_cmds = (volatile struct dbdma_cmd *)
+			DBDMA_ALIGN(awacs_tx_cmd_space);
+		awacs_reg[0] = MASK_MUX_CD;
+		awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+		/* get default volume from nvram */
+		vol = (~nvram_read_byte(0x1308) & 7) << 1;
+		awacs_reg[2] = vol + (vol << 6);
+		awacs_reg[4] = vol + (vol << 6);
+		awacs_write(awacs_reg[0] + MASK_ADDR0);
+		awacs_write(awacs_reg[1] + MASK_ADDR1);
+		awacs_write(awacs_reg[2] + MASK_ADDR2);
+		awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+		/* Initialize beep stuff */
+		beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
+		orig_mksound = kd_mksound;
+		kd_mksound = awacs_mksound;
+		beep_buf = (short *) kmalloc(BEEP_BUFLEN * 2, GFP_KERNEL);
+		if (beep_buf == NULL)
+			printk(KERN_WARNING "dmasound: no memory for "
+			       "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+		notifier_chain_register(&sleep_notifier_list,
+					&awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+	}
+#endif /* CONFIG_PMAC */
+
+	if (!has_sound)
+		return;
+
+	/* Set up sound queue, /dev/audio and /dev/dsp. */
+	sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
+	if (!sound_buffers) {
+	out_of_memory:
+		printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
+		return;
+	}
+	for (i = 0; i < numBufs; i++) {
+		sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
+		if (!sound_buffers[i]) {
+			while (i--)
+				sound.mach.dma_free (sound_buffers[i], bufSize << 10);
+			kfree (sound_buffers);
+			sound_buffers = 0;
+			goto out_of_memory;
+		}
+	}
 
 #ifndef MODULE
-    /* Register driver with the VFS. */
-    register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+	/* Register driver with the VFS. */
+	register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
 #endif
 
-    sq_init(numBufs, bufSize << 10, sound_buffers);
+	sq_init(numBufs, bufSize << 10, sound_buffers);
 
-    /* Set up /dev/sndstat. */
-    state_init();
+	/* Set default settings. */
+	init_settings();
 
-    /* Set up /dev/mixer. */
-    mixer_init();
+	/* Set up /dev/sndstat. */
+	state_init();
 
-    if (!sound.mach.irqinit()) {
-	printk("DMA sound driver: Interrupt initialization failed\n");
-	return;
-    }
+	/* Set up /dev/mixer. */
+	mixer_init();
+
+	if (!sound.mach.irqinit()) {
+		printk("DMA sound driver: Interrupt initialization failed\n");
+		return;
+	}
 #ifdef MODULE
-    irq_installed = 1;
+	irq_installed = 1;
 #endif
 
-    printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
-	   bufSize);
+	printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
+	       bufSize);
 
-    return;
+	return;
 }
 
 void sound_setup(char *str, int *ints)
 {
-    /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
+	/* ++Martin: stub, could possibly be merged with soundcard.c et al later */
 }
 
 
@@ -3366,30 +4557,30 @@
 
 void dmasound_setup(char *str, int *ints)
 {
-    /* check the bootstrap parameter for "dmasound=" */
+	/* check the bootstrap parameter for "dmasound=" */
 
-    switch (ints[0]) {
+	switch (ints[0]) {
 	case 3:
-	    if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-		printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
-	    else
-		catchRadius = ints[3];
-	    /* fall through */
+		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+			printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+		else
+			catchRadius = ints[3];
+		/* fall through */
 	case 2:
-	    if (ints[1] < MIN_BUFFERS)
-		printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
-	    else
-		numBufs = ints[1];
-	    if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-		printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
-	    else
-		bufSize = ints[2];
-	    break;
+		if (ints[1] < MIN_BUFFERS)
+			printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+		else
+			numBufs = ints[1];
+		if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+			printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+		else
+			bufSize = ints[2];
+		break;
 	case 0:
-	    break;
+		break;
 	default:
-	    printk("dmasound_setup: illegal number of arguments\n");
-    }
+		printk("dmasound_setup: illegal number of arguments\n");
+	}
 }
 
 
@@ -3399,48 +4590,48 @@
 
 int init_module(void)
 {
-    int err, i = 0;
-    int ints[MAXARGS+1];
+	int err, i = 0;
+	int ints[MAXARGS+1];
+
+	while (i < MAXARGS && dmasound[i])
+		ints[i + 1] = dmasound[i++];
+	ints[0] = i;
 
-    while (i < MAXARGS && dmasound[i])
-	ints[i + 1] = dmasound[i++];
-    ints[0] = i;
-
-    if (i)
-	dmasound_setup("dmasound=", ints);
-
-    err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-    if (err) {
-	printk("dmasound: driver already loaded/included in kernel\n");
-	return err;
-    }
-    chrdev_registered = 1;
-    soundcard_init();
+	if (i)
+		dmasound_setup("dmasound=", ints);
+
+	err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+	if (err) {
+		printk("dmasound: driver already loaded/included in kernel\n");
+		return err;
+	}
+	chrdev_registered = 1;
+	soundcard_init();
 
-    return 0;
+	return 0;
 }
 
 
 void cleanup_module(void)
 {
-    int i;
+	int i;
 
-    if (MOD_IN_USE)
-	return;
+	if (MOD_IN_USE)
+		return;
 
-    if (chrdev_registered)
-	unregister_chrdev(SOUND_MAJOR, "sound");
+	if (chrdev_registered)
+		unregister_chrdev(SOUND_MAJOR, "sound");
 
-    if (irq_installed) {
-	sound_silence();
-	sound.mach.irqcleanup();
-    }
+	if (irq_installed) {
+		sound_silence();
+		sound.mach.irqcleanup();
+	}
 
-    if (sound_buffers) {
-	for (i = 0; i < numBufs; i++)
-	    sound.mach.dma_free(sound_buffers[i], bufSize << 10);
-	kfree(sound_buffers);
-    }
+	if (sound_buffers) {
+		for (i = 0; i < numBufs; i++)
+			sound.mach.dma_free(sound_buffers[i], bufSize << 10);
+		kfree(sound_buffers);
+	}
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.1.105/linux/drivers/sound/gus_wave.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/sound/gus_wave.c	Sat Jun 13 10:23:52 1998
@@ -3128,30 +3128,24 @@
 	
 	if ((gus_mem_size > 0) & !gus_no_wave_dma)
 	{
-		if ((dev = sound_alloc_audiodev()) != -1)
+		hw_config->slots[4] = -1;
+		if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
+					"Ultrasound",
+					&gus_audio_driver,
+					sizeof(struct audio_driver),
+					NEEDS_RESTART |
+		                   	((!iw_mode && dma2 != dma && dma2 != -1) ?
+						DMA_DUPLEX : 0),
+					AFMT_U8 | AFMT_S16_LE,
+					NULL, dma, dma2)) < 0)
 		{
-			hw_config->slots[4] = dev;
-			if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
-							    "Ultrasound",
-						       &gus_audio_driver,
-					     sizeof(struct audio_driver),
-							  NEEDS_RESTART |
-								                   ((!iw_mode && dma2 != dma && dma2 != -1) ?
-							 DMA_DUPLEX : 0),
-						   AFMT_U8 | AFMT_S16_LE,
-								   NULL,
-								   dma,
-							      dma2)) < 0)
-			{
-				return;
-			}
+			return;
+		}
 
-			audio_devs[gus_devnum]->min_fragment = 9;	/* 512k */
-			audio_devs[gus_devnum]->max_fragment = 11;	/* 8k (must match size of bounce_buf */
-			audio_devs[gus_devnum]->mixer_dev = -1;	/* Next mixer# */
-			audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
-		} else
-			printk(KERN_WARNING "GUS: Too many audio devices available\n");
+		audio_devs[gus_devnum]->min_fragment = 9;	/* 512k */
+		audio_devs[gus_devnum]->max_fragment = 11;	/* 8k (must match size of bounce_buf */
+		audio_devs[gus_devnum]->mixer_dev = -1;	/* Next mixer# */
+		audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
 	}
 	
 	/*
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c
--- v2.1.105/linux/drivers/sound/msnd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd.c	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,382 @@
+/*********************************************************************
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ * $Id: msnd.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include "msnd.h"
+
+#define LOGNAME			"msnd"
+
+#define MSND_MAX_DEVS		4
+
+static multisound_dev_t		*devs[MSND_MAX_DEVS];
+static int			num_devs;
+
+int msnd_register(multisound_dev_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MSND_MAX_DEVS; ++i)
+		if (devs[i] == NULL)
+			break;
+
+	if (i == MSND_MAX_DEVS)
+		return -ENOMEM;
+	
+	devs[i] = dev;
+	++num_devs;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+void msnd_unregister(multisound_dev_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MSND_MAX_DEVS; ++i)
+		if (devs[i] == dev)
+			break;
+
+	if (i == MSND_MAX_DEVS) {
+		printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n");
+		return;
+	}
+
+	devs[i] = NULL;
+	--num_devs;
+
+	MOD_DEC_USE_COUNT;
+}
+
+int msnd_get_num_devs(void)
+{
+	return num_devs;
+}
+
+multisound_dev_t *msnd_get_dev(int j)
+{
+	int i;
+
+	for (i = 0; i < MSND_MAX_DEVS && j; ++i)
+		if (devs[i] != NULL)
+			--j;
+	
+	if (i == MSND_MAX_DEVS || j != 0)
+		return NULL;
+
+	return devs[i];
+}
+
+void msnd_fifo_init(msnd_fifo *f)
+{
+	f->data = NULL;
+}
+
+void msnd_fifo_free(msnd_fifo *f)
+{
+	if (f->data) {
+		vfree(f->data);
+		f->data = NULL;
+	}
+}
+
+int msnd_fifo_alloc(msnd_fifo *f, size_t n)
+{
+	msnd_fifo_free(f);
+	f->data = (char *)vmalloc(n);
+	f->n = n;
+	f->tail = 0;
+	f->head = 0;
+	f->len = 0;
+
+	if (!f->data)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void msnd_fifo_make_empty(msnd_fifo *f)
+{
+	f->len = f->tail = f->head = 0;
+}
+
+int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
+{
+	int count = 0;
+
+	if (f->len == f->n)
+		return 0;
+	
+	while ((count < len) && (f->len != f->n)) {
+		
+		int nwritten;
+		
+		if (f->head <= f->tail) {
+			nwritten = len - count;
+			if (nwritten > f->n - f->tail)
+				nwritten = f->n - f->tail;
+		}
+		else {
+			nwritten = f->head - f->tail;
+			if (nwritten > len - count)
+				nwritten = len - count;
+		}
+
+		if (user) {
+			if (copy_from_user(f->data + f->tail, buf, nwritten))
+				return -EFAULT;
+		} else
+			memcpy(f->data + f->tail, buf, nwritten);
+
+		count += nwritten;
+		buf += nwritten;
+		f->len += nwritten;
+		f->tail += nwritten;
+		f->tail %= f->n;
+	}
+	
+	return count;
+}
+
+int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
+{
+	int count = 0;
+
+	if (f->len == 0)
+		return f->len;
+	
+	while ((count < len) && (f->len > 0)) {
+		
+		int nread;
+		
+		if (f->tail <= f->head) {
+			nread = len - count;
+			if (nread > f->n - f->head)
+				nread = f->n - f->head;
+		}
+		else {
+			nread = f->tail - f->head;
+			if (nread > len - count)
+				nread = len - count;
+		}
+		
+		if (user) {
+			if (copy_to_user(buf, f->data + f->head, nread))
+				return -EFAULT;
+		} else
+			memcpy(buf, f->data + f->head, nread);
+		
+		count += nread;
+		buf += nread;
+		f->len -= nread;
+		f->head += nread;
+		f->head %= f->n;
+	}
+	
+	return count;
+}
+
+int msnd_wait_TXDE(multisound_dev_t *dev)
+{
+	register unsigned int io = dev->io;
+	register int timeout = 5000;
+    
+	while(timeout-- > 0)
+		if (inb(io + HP_ISR) & HPISR_TXDE)
+			return 0;
+
+	return -EIO;
+}
+
+int msnd_wait_HC0(multisound_dev_t *dev)
+{
+	register unsigned int io = dev->io;
+	register int timeout = 25000;
+
+	while(timeout-- > 0)
+		if (!(inb(io + HP_CVR) & HPCVR_HC))
+			return 0;
+
+	return -EIO;
+}
+
+int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&dev->lock, flags);
+	if (msnd_wait_HC0(dev) == 0) {
+
+		outb(cmd, dev->io + HP_CVR);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n");
+	
+	return -EIO;
+}
+
+int msnd_send_word(multisound_dev_t *dev, unsigned char high,
+		   unsigned char mid, unsigned char low)
+{
+	register unsigned int io = dev->io;
+
+	if (msnd_wait_TXDE(dev) == 0) {
+		
+		outb(high, io + HP_TXH);
+		outb(mid, io + HP_TXM);
+		outb(low, io + HP_TXL);
+		return 0;
+	}
+
+	printk(KERN_WARNING LOGNAME ": Send host word timeout\n");
+
+	return -EIO;
+}
+
+int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
+{
+	int i;
+
+	if (len % 3 != 0) {
+		
+		printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");		
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i += 3)
+		if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
+			return -EIO;
+
+	inb(dev->io + HP_RXL);
+	inb(dev->io + HP_CVR);
+
+	return 0;
+}
+
+int msnd_enable_irq(multisound_dev_t *dev)
+{
+	printk(KERN_INFO LOGNAME ": enable_irq: count %d\n", dev->irq_ref);
+
+	if (dev->irq_ref++ != 0)
+		return 0;
+
+	printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
+
+	if (msnd_wait_TXDE(dev) == 0) {
+
+		unsigned long flags;
+		
+		spin_lock_irqsave(&dev->lock, flags);
+		
+		outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+
+		if (dev->type == msndClassic)
+			outb(dev->irqid, dev->io + HP_IRQM);
+
+		outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+		outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+int msnd_disable_irq(multisound_dev_t *dev)
+{
+	unsigned long flags;
+
+	printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref);
+
+	if (--dev->irq_ref > 0)
+		return 0;
+
+	if (dev->irq_ref < 0)
+		dev->irq_ref = 0;
+
+	printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+	outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+	
+	if (dev->type == msndClassic)
+		outb(HPIRQ_NONE, dev->io + HP_IRQM);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(msnd_register);
+EXPORT_SYMBOL(msnd_unregister);
+EXPORT_SYMBOL(msnd_get_num_devs);
+EXPORT_SYMBOL(msnd_get_dev);
+
+EXPORT_SYMBOL(msnd_fifo_init);
+EXPORT_SYMBOL(msnd_fifo_free);
+EXPORT_SYMBOL(msnd_fifo_alloc);
+EXPORT_SYMBOL(msnd_fifo_make_empty);
+EXPORT_SYMBOL(msnd_fifo_write);
+EXPORT_SYMBOL(msnd_fifo_read);
+
+EXPORT_SYMBOL(msnd_wait_TXDE);
+EXPORT_SYMBOL(msnd_wait_HC0);
+EXPORT_SYMBOL(msnd_send_dsp_cmd);
+EXPORT_SYMBOL(msnd_send_word);
+EXPORT_SYMBOL(msnd_upload_host);
+
+EXPORT_SYMBOL(msnd_enable_irq);
+EXPORT_SYMBOL(msnd_disable_irq);
+
+#ifdef MODULE
+MODULE_AUTHOR				("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION			("Turtle Beach MultiSound Driver Base");
+
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd.h linux/drivers/sound/msnd.h
--- v2.1.105/linux/drivers/sound/msnd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd.h	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,259 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define VERSION			"0.6"
+
+#define DEFSAMPLERATE		44100
+#define DEFSAMPLESIZE		16
+#define DEFCHANNELS		2
+
+#define DEFFIFOSIZE		64
+
+#define SNDCARD_MSND		38
+
+#define SRAM_BANK_SIZE		0x8000
+#define SRAM_CNTL_START		0x7F00
+
+#define DSP_BASE_ADDR		0x4000
+#define DSP_BANK_BASE		0x4000
+
+#define	HP_ICR			0x00
+#define	HP_CVR			0x01
+#define	HP_ISR			0x02
+#define	HP_IVR			0x03
+#define HP_NU			0x04
+#define HP_INFO			0x04
+#define	HP_TXH			0x05
+#define	HP_RXH			0x05
+#define	HP_TXM			0x06
+#define	HP_RXM			0x06
+#define	HP_TXL			0x07
+#define	HP_RXL			0x07
+
+#define HP_ICR_DEF		0x00
+#define HP_CVR_DEF		0x12
+#define HP_ISR_DEF		0x06
+#define HP_IVR_DEF		0x0f
+#define HP_NU_DEF		0x00
+
+#define	HP_IRQM			0x09
+
+#define	HPR_BLRC		0x08
+#define	HPR_SPR1		0x09
+#define	HPR_SPR2		0x0A
+#define	HPR_TCL0		0x0B
+#define	HPR_TCL1		0x0C
+#define	HPR_TCL2		0x0D
+#define	HPR_TCL3		0x0E
+#define	HPR_TCL4		0x0F
+
+#define	HPICR_INIT		0x80
+#define HPICR_HM1		0x40
+#define HPICR_HM0		0x20
+#define HPICR_HF1		0x10
+#define HPICR_HF0		0x08
+#define	HPICR_TREQ		0x02
+#define	HPICR_RREQ		0x01
+
+#define HPCVR_HC		0x80
+
+#define	HPISR_HREQ		0x80
+#define HPISR_DMA		0x40
+#define HPISR_HF3		0x10
+#define HPISR_HF2		0x08
+#define	HPISR_TRDY		0x04
+#define	HPISR_TXDE		0x02
+#define	HPISR_RXDF		0x01
+
+#define	HPIO_290		0
+#define	HPIO_260		1
+#define	HPIO_250		2
+#define	HPIO_240		3
+#define	HPIO_230		4
+#define	HPIO_220		5
+#define	HPIO_210		6
+#define	HPIO_3E0		7
+
+#define	HPMEM_NONE		0
+#define	HPMEM_B000		1
+#define	HPMEM_C800		2
+#define	HPMEM_D000		3
+#define	HPMEM_D400		4
+#define	HPMEM_D800		5
+#define	HPMEM_E000		6
+#define	HPMEM_E800		7
+
+#define	HPIRQ_NONE		0
+#define HPIRQ_5			1
+#define HPIRQ_7			2
+#define HPIRQ_9			3
+#define HPIRQ_10		4
+#define HPIRQ_11		5
+#define HPIRQ_12		6
+#define HPIRQ_15		7
+
+#define	HIMT_PLAY_DONE		0x00
+#define	HIMT_RECORD_DONE	0x01
+#define	HIMT_MIDI_EOS		0x02
+#define	HIMT_MIDI_OUT		0x03
+
+#define	HIMT_MIDI_IN_UCHAR	0x0E
+#define	HIMT_DSP		0x0F
+
+#define HIWORD(l)		((WORD)((((DWORD)(l)) >> 16) & 0xFFFF ))
+#define LOWORD(l)		((WORD)(DWORD)(l))
+#define HIBYTE(w)		((BYTE)(((WORD)(w) >> 8 ) & 0xFF ))
+#define LOBYTE(w)		((BYTE)(w))
+#define MAKELONG(low,hi)	((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16)))
+#define MAKEWORD(low,hi)	((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w)	(USHORT)((w)/2)
+#define PCTODSP_BASED(w)	(USHORT)(((w)/2) + DSP_BASE_ADDR)
+
+#ifdef SLOWIO
+#  define outb			outb_p
+#  define inb			inb_p
+#endif
+
+typedef unsigned char		BYTE;
+typedef unsigned short		USHORT;
+typedef unsigned short		WORD;
+typedef unsigned int		DWORD;
+typedef 
+struct DAQueueDataStruct *	LPDAQD;
+
+#define GCC_PACKED		__attribute__ ((packed))
+
+struct JobQueueStruct {
+	WORD wStart;
+	WORD wSize;
+	WORD wHead;
+	WORD wTail;
+} GCC_PACKED;
+
+struct DAQueueDataStruct {
+	WORD wStart;
+	WORD wSize;
+	WORD wFormat;
+	WORD wSampleSize;
+	WORD wChannels;
+	WORD wSampleRate;
+	WORD wIntMsg;
+	WORD wFlags;
+} GCC_PACKED;
+
+typedef struct {
+	size_t n, len;
+	char *data;
+	int head, tail;
+} msnd_fifo;
+
+typedef struct multisound_dev {
+
+	char *name;
+	int dsp_minor, mixer_minor;
+
+	/* Hardware resources */
+	unsigned int io, numio;
+	int memid, irqid;
+	int irq, irq_ref;
+	unsigned char info;
+	char *base;
+	spinlock_t lock;
+
+	/* MultiSound DDK variables */
+	enum { msndClassic, msndPinnacle } type;
+	struct SMA0_CommonData *SMA;	/* diff. structure for classic vs. pinnacle */
+	struct DAQueueDataStruct *CurDAQD;
+	struct DAQueueDataStruct *CurDARQD;
+	WORD *pwDSPQData , *pwMIDQData , *pwMODQData;
+	struct JobQueueStruct *DAPQ , *DARQ , *MODQ , *MIDQ , *DSPQ;
+
+	/* State variables */
+	mode_t mode;
+	unsigned long flags;
+#define F_BANKONE			0
+#define F_INTERRUPT			1
+#define F_WRITING			2
+#define F_WRITEBLOCK			3
+#define F_READING			4
+#define F_READBLOCK			5
+#define F_AUDIO_INUSE			6
+#define F_EXT_MIDI_INUSE		7
+#define F_INT_MIDI_INUSE		8
+	struct wait_queue *writeblock, *readblock;
+	unsigned long recsrc;
+	int left_levels[16];
+	int right_levels[16];
+	int calibrate_signal;
+	int sample_size;
+	int sample_rate;
+	int channels;
+	void (*inc_ref)(void);
+	void (*dec_ref)(void);
+
+	/* Digital audio FIFOs */
+	int fifosize;
+	msnd_fifo DAPF, DARF;
+	int lastbank;
+
+	/* MIDI in callback */
+	void (*midi_in_interrupt)(struct multisound_dev *);
+
+} multisound_dev_t;
+
+#ifndef mdelay
+#  define mdelay(a)		udelay((a) * 1000)
+#endif
+
+int				msnd_register(multisound_dev_t *dev);
+void				msnd_unregister(multisound_dev_t *dev);
+int				msnd_get_num_devs(void);
+multisound_dev_t *		msnd_get_dev(int i);
+
+void				msnd_fifo_init(msnd_fifo *f);
+void				msnd_fifo_free(msnd_fifo *f);
+int				msnd_fifo_alloc(msnd_fifo *f, size_t n);
+void				msnd_fifo_make_empty(msnd_fifo *f);
+int				msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user);
+int				msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user);
+
+int				msnd_wait_TXDE(multisound_dev_t *dev);
+int				msnd_wait_HC0(multisound_dev_t *dev);
+int				msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd);
+int				msnd_send_word(multisound_dev_t *dev, unsigned char high,
+					       unsigned char mid, unsigned char low);
+int				msnd_upload_host(multisound_dev_t *dev, char *bin, int len);
+int				msnd_enable_irq(multisound_dev_t *dev);
+int				msnd_disable_irq(multisound_dev_t *dev);
+
+#endif /* __MSND_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd_classic.c linux/drivers/sound/msnd_classic.c
--- v2.1.105/linux/drivers/sound/msnd_classic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd_classic.c	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,1306 @@
+/*********************************************************************
+ *
+ * msnd_classic.c - Support for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ * $Id: msnd_classic.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#define SLOWIO
+#include "msnd.h"
+#include "msnd_classic.h"
+
+#define LOGNAME				"msnd_classic"
+#define DEVNAME				dev.name
+#define MIXERMINOR			dev.mixer_minor
+#define DSPMINOR			dev.dsp_minor
+
+multisound_dev_t			dev;
+
+#ifndef HAVE_DSPCODEH
+static char				*dspini, *permini;
+static int				sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	msnd_fifo_make_empty(&dev.DAPF);
+	dev.DAPQ->wHead = 0;
+	dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+	dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+	for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+		writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+		writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}
+
+	dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	msnd_fifo_make_empty(&dev.DARF);
+	dev.DARQ->wHead = 0;
+	dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+	dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+	outb(HPBLKSEL_1, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+		writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+		writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}
+}
+
+static void reset_queues(void)
+{
+	dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+	reset_play_queue();
+	reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+	int val, i, data;
+	LPDAQD lpDAQ, lpDARQ;
+
+	lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+	lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+	switch (cmd) {
+	case SNDCTL_DSP_SUBDIVIDE:
+	case SNDCTL_DSP_SETFRAGMENT:
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+		return -EINVAL;
+
+	case SNDCTL_DSP_SYNC:
+	case SNDCTL_DSP_RESET:
+
+		reset_play_queue();
+		reset_record_queue();
+
+		return 0;
+		
+	case SNDCTL_DSP_GETBLKSIZE:
+
+		if (put_user(dev.fifosize / 4, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_NONBLOCK:
+
+		dev.mode |= O_NONBLOCK;
+
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+
+		val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_SAMPLESIZE:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		switch (val) {
+		case 16:
+		case 8:
+			data = val;
+			break;
+		default:
+			data = DEFSAMPLESIZE;
+			break;
+		}
+
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wSampleSize = data;
+			lpDARQ->wSampleSize = data;
+		}
+		
+		dev.sample_size = data;
+		
+		if (put_user(data, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_SPEED:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (val < 8000)
+			val = 8000;
+
+		if (val > 48000)
+			val = 48000;
+
+		data = val;
+
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wSampleRate = data;
+			lpDARQ->wSampleRate = data;
+		}
+		
+		dev.sample_rate = data;
+
+		if (put_user(data, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_CHANNELS:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+			
+		switch (val) {
+		case 1:
+		case 2:
+			data = val;
+			break;
+		default:
+			val = data = 2;
+			break;
+		}
+									
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wChannels = data;
+			lpDARQ->wChannels = data;
+		}
+
+		dev.channels = data;
+
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_STEREO:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+			
+		switch (val) {
+		case 0:
+			data = 1;
+			break;
+		default:
+			val = 1;
+		case 1:
+			data = 2;
+			break;
+		}
+									
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wChannels = data;
+			lpDARQ->wChannels = data;
+		}
+
+		dev.channels = data;
+
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+	if (d > 31)
+		return -EINVAL;
+
+	switch (d) {
+	case SOUND_MIXER_VOLUME:
+	case SOUND_MIXER_SYNTH:
+	case SOUND_MIXER_PCM:
+	case SOUND_MIXER_LINE:
+	case SOUND_MIXER_MIC:
+	case SOUND_MIXER_IMIX:
+	case SOUND_MIXER_LINE1:
+		return (dev.left_levels[d] >> 8) * 100 / 0xff | 
+			(((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+	default:
+		return 0;
+	}
+}
+
+#define update_vol(a,b,s)								\
+	writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s,	\
+	       &dev.SMA->b##Left);							\
+	writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s,	\
+	       &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+	int left = value & 0x000000ff;
+	int right = (value & 0x0000ff00) >> 8;
+	int bLeft, bRight;
+	int wLeft, wRight;
+
+	if (d > 31)
+		return -EINVAL;
+
+	bLeft = left * 0xff / 100;
+	wLeft = left * 0xffff / 100;
+
+	bRight = right * 0xff / 100;
+	wRight = right * 0xffff / 100;
+
+	dev.left_levels[d] = wLeft;
+	dev.right_levels[d] = wRight;
+
+	switch (d) {
+	case SOUND_MIXER_VOLUME:		/* master volume */
+		writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+		writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+		break;
+
+		/* pot controls */
+	case SOUND_MIXER_LINE:			/* aux pot control */
+		writeb(bLeft, &dev.SMA->bInPotPosLeft);
+		writeb(bRight, &dev.SMA->bInPotPosRight);
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+		break;
+
+	case SOUND_MIXER_LINE1:			/* line pot control */
+		writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+		writeb(bRight, &dev.SMA->bAuxPotPosRight);
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+		break;
+
+		/* digital controls */
+	case SOUND_MIXER_SYNTH:			/* synth vol (dsp mix) */
+	case SOUND_MIXER_PCM:			/* pcm vol (dsp mix) */
+	case SOUND_MIXER_IMIX:			/* input monitor (dsp mix) */
+		break;
+
+	default:
+		return 0;
+	}
+
+	/* update digital controls for master volume */
+	update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+	update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+	
+	return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+	if (recsrc == 0)
+		dev.recsrc = 0;
+	else
+#endif
+		dev.recsrc ^= recsrc;
+
+	return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+	int val = 0;
+
+	if (((cmd >> 8) & 0xff) == 'M') {
+		
+		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+			switch (cmd & 0xff) {
+			case SOUND_MIXER_RECSRC:
+				if (get_user(val, (int *)arg))
+					return -EFAULT;
+				val = set_recsrc(val);
+				break;
+				
+			default:
+				if (get_user(val, (int *)arg))
+					return -EFAULT;
+				val = mixer_set(cmd & 0xff, val);
+				break;
+			}
+
+			return put_user(val, (int *)arg);
+		}
+		else {
+			switch (cmd & 0xff) {
+			case SOUND_MIXER_RECSRC:
+				val = dev.recsrc;
+				break;
+				
+			case SOUND_MIXER_DEVMASK:
+			case SOUND_MIXER_STEREODEVS:
+				val =   SOUND_MASK_VOLUME |
+					SOUND_MASK_PCM |
+					SOUND_MASK_LINE |
+					SOUND_MASK_IMIX |
+					SOUND_MASK_LINE1;
+				break;
+				  
+			case SOUND_MIXER_RECMASK:
+				val = 0;
+				break;
+				  
+			case SOUND_MIXER_CAPS:
+				val =   SOUND_CAP_EXCL_INPUT;
+				break;
+				
+			default:
+				if ((val = mixer_get(cmd & 0xff)) < 0)
+					return -EINVAL;
+				break;
+			}
+		}
+
+		return put_user(val, (int *)arg); 
+	}
+
+	return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int minor = MINOR(inode->i_rdev);
+
+	if (minor == DSPMINOR)
+		return dsp_ioctl(cmd, arg);
+	else if (minor == MIXERMINOR)
+		return mixer_ioctl(cmd, arg);
+
+	return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+	mdelay(1);
+	if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+		msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+		msnd_disable_irq(&dev);
+
+	}
+	mdelay(1);
+	if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+		msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+		msnd_disable_irq(&dev);
+
+	}
+	mdelay(1);
+	reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+	dev.mode = file->f_mode;
+	set_bit(F_AUDIO_INUSE, &dev.flags);
+	reset_queues();
+	return 0;
+}
+
+static int dsp_close(void)
+{
+	dsp_halt();
+	clear_bit(F_AUDIO_INUSE, &dev.flags);
+	return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	int err = 0;
+
+	if (minor == DSPMINOR) {
+
+		if (test_bit(F_AUDIO_INUSE, &dev.flags))
+			return -EBUSY;
+
+		err = dsp_open(file);
+	}
+	else if (minor == MIXERMINOR) {
+		/* nothing */
+	} else
+		err = -EINVAL;
+	
+	if (err >= 0)
+		MOD_INC_USE_COUNT;
+
+	return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	int err = 0;
+
+	if (minor == DSPMINOR) {
+		err = dsp_close();
+	}
+	else if (minor == MIXERMINOR) {
+		/* nothing */
+	} else
+		err = -EINVAL;
+
+	if (err >= 0)
+		MOD_DEC_USE_COUNT;
+	
+	return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+	return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+	return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+	int err = 0;
+	int count = len;
+
+	while (count > 0) {
+		
+		int n;
+
+		if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+			printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+			return n;
+		}
+
+		buf += n;
+		count -= n;
+		
+		if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+			reset_record_queue();
+			msnd_enable_irq(&dev);
+			msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+		}
+
+		if (dev.mode & O_NONBLOCK)
+			return count == len ? -EAGAIN : len - count;
+
+		if (count > 0) {
+
+			set_bit(F_READBLOCK, &dev.flags);
+			interruptible_sleep_on(&dev.readblock);
+			clear_bit(F_READBLOCK, &dev.flags);
+
+			if (signal_pending(current))
+				err = -EINTR;
+
+		}
+
+		if (err != 0)
+			return err;
+	}
+
+	return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+	int err = 0;
+	int count = len;
+
+	while (count > 0) {
+
+		int n;
+
+		if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+			printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+			return n;
+		}
+
+		buf += n;
+		count -= n;
+
+		if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+			
+			reset_play_queue();
+			msnd_enable_irq(&dev);
+			msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+		}
+
+		if (dev.mode & O_NONBLOCK)
+			return count == len ? -EAGAIN : len - count;
+
+		if (count > 0) {
+			
+			set_bit(F_WRITEBLOCK, &dev.flags);
+			interruptible_sleep_on(&dev.writeblock);
+			clear_bit(F_WRITEBLOCK, &dev.flags);
+
+			if (signal_pending(current))
+				err = -EINTR;
+
+		}
+
+		if (err != 0)
+			return err;
+	}
+	
+	return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	if (minor == DSPMINOR) {
+
+		return dsp_read(buf, count);
+
+	} else
+		return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	if (minor == DSPMINOR) {
+
+		return dsp_write(buf, count);
+
+	} else
+		return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+	switch (HIBYTE(wMessage)) {
+	case HIMT_PLAY_DONE:
+		
+		if (dev.lastbank == LOBYTE(wMessage))
+			break;
+		
+		dev.lastbank = LOBYTE(wMessage);
+
+		dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+		if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+			dev.DAPQ->wTail = 0;
+
+		if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+			dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+		if (dev.lastbank < 3) {
+
+			if (DAPF_to_bank(dev.lastbank) > 0) {
+
+				mdelay(1);
+				msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+			} 
+			else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+				memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+				clear_bit(F_WRITING, &dev.flags);
+				msnd_disable_irq(&dev);
+
+			}
+		}
+
+		if (test_bit(F_WRITEBLOCK, &dev.flags))
+			wake_up_interruptible(&dev.writeblock);
+		
+		break;
+
+	case HIMT_RECORD_DONE: {
+
+		WORD wTemp;
+		
+		wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+		if (wTemp > dev.DARQ->wSize)
+			wTemp = 0;
+
+		while (wTemp == dev.DARQ->wHead);
+
+		dev.DARQ->wTail = wTemp;
+
+		outb(HPBLKSEL_1, dev.io + HP_BLKS);
+		if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+		    !test_bit(F_READBLOCK, &dev.flags)) {
+
+			memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+			clear_bit(F_READING, &dev.flags);
+			msnd_disable_irq(&dev);
+
+		}
+		outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+		if (test_bit(F_READBLOCK, &dev.flags))
+			wake_up_interruptible(&dev.readblock);
+
+		} break;
+
+	case HIMT_DSP:
+		switch (LOBYTE(wMessage)) {
+		case HIDSP_INT_PLAY_UNDER:
+			printk(KERN_INFO LOGNAME ": Write underflow\n");
+			reset_play_queue();
+			break;
+
+		case HIDSP_INT_RECORD_OVER:
+			printk(KERN_INFO LOGNAME ": Read overflow\n");
+			reset_record_queue();
+			break;
+
+		default:
+			printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+			break;
+		}
+		break;
+
+        case HIMT_MIDI_IN_UCHAR:
+		if (dev.midi_in_interrupt)
+			(*dev.midi_in_interrupt)(&dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (test_bit(F_INTERRUPT, &dev.flags) || 
+	    ((multisound_dev_t *)dev_id != &dev))
+		return;
+
+	set_bit(F_INTERRUPT, &dev.flags);
+	
+	if (test_bit(F_BANKONE, &dev.flags))
+		outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	inb(dev.io + HP_RXL);
+ 
+	while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+		eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+		if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+			dev.DSPQ->wHead = 0;
+	}
+
+	if (test_bit(F_BANKONE, &dev.flags))
+		outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+	clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+	NULL,
+	dev_read,
+	dev_write,
+	NULL,
+	NULL,
+	dev_ioctl,
+	NULL,
+	dev_open,
+	dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+	int timeout = 20000;
+		
+	outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+	
+	mdelay(1);
+
+	dev.info = inb(dev.io + HP_INFO);
+
+	outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+	mdelay(1);
+
+	while (timeout-- > 0) {
+
+		if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+			return 0;
+		
+		mdelay(1);
+	}
+
+	printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+	return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+	if (check_region(dev.io, dev.numio)) {
+		
+		printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+		return -ENODEV;
+	}
+
+	request_region(dev.io, dev.numio, "probing");
+
+	if (reset_dsp() < 0) {
+		
+		release_region(dev.io, dev.numio);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+	dev.name = "Classic/Tahiti/Monterey";
+
+	printk(KERN_INFO LOGNAME ": Turtle Beach %s, "
+	       "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+	       dev.name,
+	       dev.io, dev.io + dev.numio - 1,
+	       dev.irq,
+	       dev.base, dev.base + 0x7fff);
+
+	release_region(dev.io, dev.numio);
+	
+	return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	outb(dev.memid, dev.io + HP_MEMM);
+
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, 0x8000);
+	
+	outb(HPBLKSEL_1, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, 0x8000);
+	
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+	dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+	dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+	dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+	dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+	dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+	dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+	dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+	dev.sample_size = DEFSAMPLESIZE;
+	dev.sample_rate = DEFSAMPLERATE;
+	dev.channels = DEFCHANNELS;
+
+	for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+		
+		writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+		writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+	}
+
+	for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+		writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+		writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}	
+
+	dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+	dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+	dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+	writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+	writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+	writew(0, &dev.MIDQ->wHead);
+	writew(0, &dev.MIDQ->wTail);
+
+	writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+	writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+	writew(0, &dev.MODQ->wHead);
+	writew(0, &dev.MODQ->wTail);
+
+	writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+	writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+	writew(0, &dev.DAPQ->wHead);
+	writew(0, &dev.DAPQ->wTail);
+
+	writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+	writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+	writew(0, &dev.DARQ->wHead);
+	writew(0, &dev.DARQ->wTail);
+
+	writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+	writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+	writew(0, &dev.DSPQ->wHead);
+	writew(0, &dev.DSPQ->wTail);
+
+	writew(0, &dev.SMA->wCurrPlayBytes);
+	writew(0, &dev.SMA->wCurrRecordBytes);
+
+	writew(0, &dev.SMA->wCurrPlayVolLeft);
+	writew(0, &dev.SMA->wCurrPlayVolRight);
+
+	writew(0, &dev.SMA->wCurrInVolLeft);
+	writew(0, &dev.SMA->wCurrInVolRight);
+
+	writew(0, &dev.SMA->wCurrMastVolLeft);
+	writew(0, &dev.SMA->wCurrMastVolRight);
+
+	writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+	writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+	writew(0x303, &dev.SMA->wCurrInputTagBits);
+	writew(0, &dev.SMA->wCurrLeftPeak);
+	writew(0, &dev.SMA->wCurrRightPeak);
+
+	writeb(0, &dev.SMA->bInPotPosRight);
+	writeb(0, &dev.SMA->bInPotPosLeft);
+
+	writeb(0, &dev.SMA->bAuxPotPosRight);
+	writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+	writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+	return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+	if (!dev.calibrate_signal) {
+
+		printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+		writew(readw(&dev.SMA->wCurrHostStatusFlags)
+		       | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+	}
+	else {
+
+		printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+		writew(readw(&dev.SMA->wCurrHostStatusFlags)
+		       & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+	}
+	
+	writew(srate, &dev.SMA->wCalFreqAtoD);
+
+	if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+	    msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + HZ;
+		schedule();
+		current->timeout = 0;
+		printk("successful\n");
+		return 0;
+	}
+
+	printk("failed\n");
+
+	return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+	printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else	
+	printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+	INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+	if (!INITCODE) {
+		printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+		return -EBUSY;
+	}
+
+	PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+	if (!PERMCODE) {
+		printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+		vfree(INITCODE);
+		return -EBUSY;
+	}
+#endif
+	memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+	if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+		return -ENODEV;
+	}
+
+#ifndef HAVE_DSPCODEH
+	vfree(INITCODE);
+	vfree(PERMCODE);
+#endif
+
+	return 0;
+}
+
+__initfunc(static void reset_proteus(void))
+{
+	outb(HPPRORESET_ON, dev.io + HP_PROR);
+	mdelay(TIME_PRO_RESET);
+	outb(HPPRORESET_OFF, dev.io + HP_PROR);
+	mdelay(TIME_PRO_RESET_DONE);
+}
+
+__initfunc(static int initialize(void))
+{
+	int err, timeout;
+
+	outb(HPWAITSTATE_0, dev.io + HP_WAIT);
+	outb(HPBITMODE_16, dev.io + HP_BITM);
+
+	reset_proteus();
+
+	if ((err = init_sma()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+		return err;
+	}
+
+	if ((err = reset_dsp()) < 0)
+		return err;
+	
+	if ((err = upload_dsp_code()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+		return err;
+
+	} else
+		printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+	timeout = 2000;
+
+	while (readw(dev.base)) {
+		
+		mdelay(1);
+		if (--timeout < 0)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+	int err;
+
+	printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+	if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+		return err;
+	
+	}
+
+	request_region(dev.io, dev.numio, DEVNAME);
+
+        if ((err = initialize()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return err;
+
+	}
+
+	if ((err = msnd_register(&dev)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return err;
+	}
+
+	if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+		msnd_unregister(&dev);
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return DSPMINOR;
+	}
+
+	if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+		unregister_sound_mixer(MIXERMINOR);
+		msnd_unregister(&dev);
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return MIXERMINOR;
+	}
+	printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+	calibrate_adc(dev.sample_rate);
+	set_recsrc(0);
+	
+	return 0;
+}
+
+static void unload_multisound(void)
+{
+	release_region(dev.io, dev.numio);
+	free_irq(dev.irq, &dev);
+	unregister_sound_mixer(MIXERMINOR);
+	unregister_sound_dsp(DSPMINOR);
+	msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR				("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION			("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM				(io, "i");
+MODULE_PARM				(irq, "i");
+MODULE_PARM				(mem, "i");
+MODULE_PARM				(major, "i");
+MODULE_PARM				(fifosize, "i");
+MODULE_PARM				(calibrate_signal, "i");
+
+static int io __initdata =		-1;
+static int irq __initdata =		-1;
+static int mem __initdata =		-1;
+static int fifosize __initdata =	DEFFIFOSIZE;
+static int
+calibrate_signal __initdata =		0;
+
+int init_module(void)
+{
+	int err;
+
+	printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+	       VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+	
+	if (io == -1 || irq == -1 || mem == -1) {
+
+		printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+	}
+		
+	if (io == -1 ||
+	    !(io == 0x290 ||
+	      io == 0x260 ||
+	      io == 0x250 ||
+	      io == 0x240 ||
+	      io == 0x230 ||
+	      io == 0x220 ||
+	      io == 0x210 ||
+	      io == 0x3e0)) {
+
+		printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+		return -EINVAL;
+	}
+	
+	if (irq == -1 ||
+	    !(irq == 5 ||
+	      irq == 7 ||
+	      irq == 9 ||
+	      irq == 10 ||
+	      irq == 11 ||
+	      irq == 12)) {
+		
+		printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+		return -EINVAL;
+	}
+
+	if (mem == -1 ||
+	    !(mem == 0xb0000 ||
+	      mem == 0xc8000 ||
+	      mem == 0xd0000 ||
+	      mem == 0xd8000 ||
+	      mem == 0xe0000 ||
+	      mem == 0xe8000)) {
+		
+		printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+		       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+		return -EINVAL;
+	}
+
+	switch (irq) {
+	case 5: dev.irqid = HPIRQ_5; break;
+	case 7: dev.irqid = HPIRQ_7; break;
+	case 9: dev.irqid = HPIRQ_9; break;
+	case 10: dev.irqid = HPIRQ_10; break;
+	case 11: dev.irqid = HPIRQ_11; break;
+	case 12: dev.irqid = HPIRQ_12; break;
+	}
+
+	switch (mem) {
+	case 0xb0000: dev.memid = HPMEM_B000; break;
+	case 0xc8000: dev.memid = HPMEM_C800; break;
+	case 0xd0000: dev.memid = HPMEM_D000; break;
+	case 0xd8000: dev.memid = HPMEM_D800; break;
+	case 0xe0000: dev.memid = HPMEM_E000; break;
+	case 0xe8000: dev.memid = HPMEM_E800; break;
+	}
+
+	if (fifosize < 16)
+		fifosize = 16;
+
+	if (fifosize > 768)
+		fifosize = 768;
+
+	dev.type = msndClassic;
+	dev.io = io;
+	dev.numio = DSP_NUMIO;
+	dev.irq = irq;
+	dev.base = phys_to_virt(mem);
+	dev.fifosize = fifosize * 1024;
+	dev.calibrate_signal = calibrate_signal ? 1 : 0;
+	dev.recsrc = 0;
+	dev.inc_ref = mod_inc_ref;
+	dev.dec_ref = mod_dec_ref;
+
+	init_waitqueue(&dev.writeblock);
+	init_waitqueue(&dev.readblock);
+	msnd_fifo_init(&dev.DAPF);
+	msnd_fifo_init(&dev.DARF);
+	spin_lock_init(&dev.lock);
+
+	printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+	if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+		return err;
+	}
+
+	if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+		msnd_fifo_free(&dev.DAPF);
+		return err;
+	}
+
+	if ((err = probe_multisound()) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Probe failed\n");
+		msnd_fifo_free(&dev.DAPF);
+		msnd_fifo_free(&dev.DARF);
+		return err;
+
+	}
+	
+	if ((err = attach_multisound()) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Attach failed\n");
+		msnd_fifo_free(&dev.DAPF);
+		msnd_fifo_free(&dev.DARF);
+		return err;
+
+	}
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	printk(KERN_INFO LOGNAME ": Unloading\n");
+
+	unload_multisound();
+
+	msnd_fifo_free(&dev.DAPF);
+	msnd_fifo_free(&dev.DARF);
+
+}
+#endif
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd_classic.h linux/drivers/sound/msnd_classic.h
--- v2.1.105/linux/drivers/sound/msnd_classic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd_classic.h	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,191 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: msnd_classic.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO		0x10
+
+#define	HP_MEMM			0x08
+
+#define	HP_BITM			0x0E
+#define	HP_WAIT			0x0D
+#define	HP_DSPR			0x0A
+#define	HP_PROR			0x0B
+#define	HP_BLKS			0x0C
+
+#define	HPPRORESET_OFF		0
+#define HPPRORESET_ON		1
+
+#define HPDSPRESET_OFF		0
+#define HPDSPRESET_ON		1
+
+#define HPBLKSEL_0		0
+#define HPBLKSEL_1		1
+
+#define HPWAITSTATE_0		0
+#define HPWAITSTATE_1		1
+
+#define HPBITMODE_16		0
+#define HPBITMODE_8		1
+
+#define	HIDSP_INT_PLAY_UNDER	0x00
+#define	HIDSP_INT_RECORD_OVER	0x01
+#define	HIDSP_INPUT_CLIPPING	0x02
+#define	HIDSP_MIDI_IN_OVER	0x10
+#define	HIDSP_MIDI_OVERRUN_ERR  0x13
+
+#define	HDEX_BASE	       	0x92
+#define	HDEX_PLAY_START		(0 + HDEX_BASE)
+#define	HDEX_PLAY_STOP		(1 + HDEX_BASE)
+#define	HDEX_PLAY_PAUSE		(2 + HDEX_BASE)
+#define	HDEX_PLAY_RESUME	(3 + HDEX_BASE)
+#define	HDEX_RECORD_START	(4 + HDEX_BASE)
+#define	HDEX_RECORD_STOP	(5 + HDEX_BASE)
+#define	HDEX_MIDI_IN_START 	(6 + HDEX_BASE)
+#define	HDEX_MIDI_IN_STOP	(7 + HDEX_BASE)
+#define	HDEX_MIDI_OUT_START	(8 + HDEX_BASE)
+#define	HDEX_MIDI_OUT_STOP	(9 + HDEX_BASE)
+#define	HDEX_AUX_REQ		(10 + HDEX_BASE)
+
+#define	HDEXAR_CLEAR_PEAKS	1
+#define	HDEXAR_IN_SET_POTS	2
+#define	HDEXAR_AUX_SET_POTS	3
+#define	HDEXAR_CAL_A_TO_D	4
+#define	HDEXAR_RD_EXT_DSP_BITS	5
+
+#define TIME_PRO_RESET_DONE	0x028A
+#define TIME_PRO_SYSEX		0x0040
+#define TIME_PRO_RESET		0x0032
+
+#define AGND			0x01
+#define SIGNAL			0x02
+
+#define EXT_DSP_BIT_DCAL	0x0001
+#define EXT_DSP_BIT_MIDI_CON	0x0002
+
+#define BUFFSIZE		0x8000
+#define HOSTQ_SIZE		0x40
+
+#define SRAM_CNTL_START		0x7F00
+#define SMA_STRUCT_START	0x7F40
+
+#define DAP_BUFF_SIZE		0x2400
+#define DAR_BUFF_SIZE		0x2000
+
+#define DAPQ_STRUCT_SIZE	0x10
+#define DARQ_STRUCT_SIZE	0x10
+#define DAPQ_BUFF_SIZE		(3 * 0x10)
+#define DARQ_BUFF_SIZE		(3 * 0x10)
+#define MODQ_BUFF_SIZE		0x400
+#define MIDQ_BUFF_SIZE		0x200
+#define DSPQ_BUFF_SIZE		0x40
+
+#define DAPQ_DATA_BUFF		0x6C00
+#define DARQ_DATA_BUFF		0x6C30
+#define MODQ_DATA_BUFF		0x6C60
+#define MIDQ_DATA_BUFF		0x7060
+#define DSPQ_DATA_BUFF		0x7260
+
+#define DAPQ_OFFSET		SRAM_CNTL_START
+#define DARQ_OFFSET		(SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET		(SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET		(SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET		(SRAM_CNTL_START + 0x20)
+
+#define MOP_PROTEUS		0x10
+#define MOP_EXTOUT		0x32
+#define MOP_EXTTHRU		0x02
+#define MOP_OUTMASK		0x01
+
+#define MIP_EXTIN		0x01
+#define MIP_PROTEUS		0x00
+#define MIP_INMASK		0x32
+
+struct SMA0_CommonData {
+	WORD wCurrPlayBytes;
+	WORD wCurrRecordBytes;
+	WORD wCurrPlayVolLeft;
+	WORD wCurrPlayVolRight;
+	WORD wCurrInVolLeft;
+	WORD wCurrInVolRight;
+	WORD wUser_3;
+	WORD wUser_4;
+	DWORD dwUser_5;
+	DWORD dwUser_6;
+	WORD wUser_7;
+	WORD wReserved_A;
+	WORD wReserved_B;
+	WORD wReserved_C;
+	WORD wReserved_D;
+	WORD wReserved_E;
+	WORD wReserved_F;
+	WORD wReserved_G;
+	WORD wReserved_H;
+	WORD wCurrDSPStatusFlags;
+	WORD wCurrHostStatusFlags;
+	WORD wCurrInputTagBits;
+	WORD wCurrLeftPeak;
+	WORD wCurrRightPeak;
+	WORD wExtDSPbits;
+	BYTE bExtHostbits;
+	BYTE bBoardLevel;
+	BYTE bInPotPosRight;
+	BYTE bInPotPosLeft;
+	BYTE bAuxPotPosRight;
+	BYTE bAuxPotPosLeft;
+	WORD wCurrMastVolLeft;
+	WORD wCurrMastVolRight;
+	BYTE bUser_12;
+	BYTE bUser_13;
+	WORD wUser_14;
+	WORD wUser_15;
+	WORD wCalFreqAtoD;
+	WORD wUser_16;
+	WORD wUser_17;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+#  include "msndperm.c"
+#  include "msndinit.c"
+#  define PERMCODE		msndperm
+#  define INITCODE		msndinit
+#  define PERMCODESIZE		sizeof(msndperm)
+#  define INITCODESIZE		sizeof(msndinit)
+#else
+#  define PERMCODEFILE		CONFIG_MSNDCLAS_PERM_FILE
+#  define INITCODEFILE		CONFIG_MSNDCLAS_INIT_FILE
+#  define PERMCODE		dspini
+#  define INITCODE		permini
+#  define PERMCODESIZE		sizeof_dspini
+#  define INITCODESIZE		sizeof_permini
+#endif
+#define LONGNAME		"MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c
--- v2.1.105/linux/drivers/sound/msnd_pinnacle.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd_pinnacle.c	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,1338 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.c - Support for Turtle Beach Pinnacle and Fiji
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ * $Id: msnd_pinnacle.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+#define LOGNAME				"msnd_pinnacle"
+#define DEVNAME				dev.name
+#define MIXERMINOR			dev.mixer_minor
+#define DSPMINOR			dev.dsp_minor
+
+multisound_dev_t			dev;
+
+#ifndef HAVE_DSPCODEH
+static char				*dspini, *permini;
+static int				sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	msnd_fifo_make_empty(&dev.DAPF);
+	dev.DAPQ->wHead = 0;
+	dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+	dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+	for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+		writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+		writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}
+
+	dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	msnd_fifo_make_empty(&dev.DARF);
+	dev.DARQ->wHead = 0;
+	dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+	dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+	outb(HPBLKSEL_1, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+		writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+		writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}
+}
+
+static void reset_queues(void)
+{
+	dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+	reset_play_queue();
+	reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+	int val, i, data;
+	LPDAQD lpDAQ, lpDARQ;
+
+	lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+	lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+	switch (cmd) {
+	case SNDCTL_DSP_SUBDIVIDE:
+	case SNDCTL_DSP_SETFRAGMENT:
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+		return -EINVAL;
+
+	case SNDCTL_DSP_SYNC:
+	case SNDCTL_DSP_RESET:
+
+		reset_play_queue();
+		reset_record_queue();
+
+		return 0;
+		
+	case SNDCTL_DSP_GETBLKSIZE:
+
+		if (put_user(dev.fifosize / 4, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_NONBLOCK:
+
+		dev.mode |= O_NONBLOCK;
+
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+
+		val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_SAMPLESIZE:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		switch (val) {
+		case 16:
+		case 8:
+			data = val;
+			break;
+		default:
+			data = DEFSAMPLESIZE;
+			break;
+		}
+
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wSampleSize = data;
+			lpDARQ->wSampleSize = data;
+		}
+		
+		dev.sample_size = data;
+		
+		if (put_user(data, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_SPEED:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (val < 8000)
+			val = 8000;
+
+		if (val > 48000)
+			val = 48000;
+
+		data = val;
+
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wSampleRate = data;
+			lpDARQ->wSampleRate = data;
+		}
+		
+		dev.sample_rate = data;
+
+		if (put_user(data, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_CHANNELS:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+			
+		switch (val) {
+		case 1:
+		case 2:
+			data = val;
+			break;
+		default:
+			val = data = 2;
+			break;
+		}
+									
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wChannels = data;
+			lpDARQ->wChannels = data;
+		}
+
+		dev.channels = data;
+
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case SNDCTL_DSP_STEREO:
+			
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+			
+		switch (val) {
+		case 0:
+			data = 1;
+			break;
+		default:
+			val = 1;
+		case 1:
+			data = 2;
+			break;
+		}
+									
+		for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+			lpDAQ->wChannels = data;
+			lpDARQ->wChannels = data;
+		}
+
+		dev.channels = data;
+
+		if (put_user(val, (int *)arg))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+	if (d > 31)
+		return -EINVAL;
+
+	switch (d) {
+	case SOUND_MIXER_VOLUME:
+	case SOUND_MIXER_SYNTH:
+	case SOUND_MIXER_PCM:
+	case SOUND_MIXER_LINE:
+	case SOUND_MIXER_MIC:
+	case SOUND_MIXER_IMIX:
+	case SOUND_MIXER_LINE1:
+		return (dev.left_levels[d] >> 8) * 100 / 0xff | 
+			(((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+	default:
+		return 0;
+	}
+}
+
+#define update_vol(a,b,s)								\
+	writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s,	\
+	       &dev.SMA->b##Left);							\
+	writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s,	\
+	       &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+	int left = value & 0x000000ff;
+	int right = (value & 0x0000ff00) >> 8;
+	int bLeft, bRight;
+	int wLeft, wRight;
+
+	if (d > 31)
+		return -EINVAL;
+
+	bLeft = left * 0xff / 100;
+	wLeft = left * 0xffff / 100;
+
+	bRight = right * 0xff / 100;
+	wRight = right * 0xffff / 100;
+
+	dev.left_levels[d] = wLeft;
+	dev.right_levels[d] = wRight;
+
+	switch (d) {
+	case SOUND_MIXER_VOLUME:		/* master volume */
+		writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+		writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+		break;
+
+		/* pot controls */
+	case SOUND_MIXER_LINE:			/* aux pot control */
+		writeb(bLeft, &dev.SMA->bInPotPosLeft);
+		writeb(bRight, &dev.SMA->bInPotPosRight);
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+		break;
+
+	case SOUND_MIXER_MIC:			/* mic pot control */
+		writeb(bLeft, &dev.SMA->bMicPotPosLeft);
+		writeb(bRight, &dev.SMA->bMicPotPosRight);
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+		break;
+
+	case SOUND_MIXER_LINE1:			/* line pot control */
+		writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+		writeb(bRight, &dev.SMA->bAuxPotPosRight);
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+		break;
+
+		/* digital controls */
+	case SOUND_MIXER_SYNTH:			/* synth vol (dsp mix) */
+	case SOUND_MIXER_PCM:			/* pcm vol (dsp mix) */
+	case SOUND_MIXER_IMIX:			/* input monitor (dsp mix) */
+		break;
+
+	default:
+		return 0;
+	}
+
+	/* update digital controls for master volume */
+	update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+	update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+	update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1);
+	
+	return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+	if (recsrc == 0)
+		dev.recsrc = 0;
+	else
+#endif
+		dev.recsrc ^= recsrc;
+
+	if (dev.recsrc & SOUND_MASK_LINE) {
+
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+	}
+	else if (dev.recsrc & SOUND_MASK_SYNTH) {
+
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+	}
+	else {
+#ifdef HAVE_NORECSRC
+		/* Select no input (?) */
+		dev.recsrc = 0;
+#else
+		dev.recsrc = SOUND_MASK_LINE;
+		if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+			msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+#endif
+	}
+
+	return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+	int val = 0;
+
+	if (((cmd >> 8) & 0xff) == 'M') {
+		
+		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+			switch (cmd & 0xff) {
+			case SOUND_MIXER_RECSRC:
+				if (get_user(val, (int *)arg))
+					return -EFAULT;
+				val = set_recsrc(val);
+				break;
+				
+			default:
+				if (get_user(val, (int *)arg))
+					return -EFAULT;
+				val = mixer_set(cmd & 0xff, val);
+				break;
+			}
+
+			return put_user(val, (int *)arg);
+		}
+		else {
+			switch (cmd & 0xff) {
+			case SOUND_MIXER_RECSRC:
+				val = dev.recsrc;
+				break;
+				
+			case SOUND_MIXER_DEVMASK:
+			case SOUND_MIXER_STEREODEVS:
+				val =   SOUND_MASK_VOLUME |
+					SOUND_MASK_SYNTH |
+					SOUND_MASK_PCM |
+					SOUND_MASK_LINE |
+					SOUND_MASK_IMIX |
+					SOUND_MASK_MIC;
+				break;
+				  
+			case SOUND_MIXER_RECMASK:
+				val =   SOUND_MASK_LINE |
+					SOUND_MASK_SYNTH;
+				break;
+				  
+			case SOUND_MIXER_CAPS:
+				val =   SOUND_CAP_EXCL_INPUT;
+				break;
+				
+			default:
+				if ((val = mixer_get(cmd & 0xff)) < 0)
+					return -EINVAL;
+				break;
+			}
+		}
+
+		return put_user(val, (int *)arg); 
+	}
+
+	return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int minor = MINOR(inode->i_rdev);
+
+	if (minor == DSPMINOR)
+		return dsp_ioctl(cmd, arg);
+	else if (minor == MIXERMINOR)
+		return mixer_ioctl(cmd, arg);
+
+	return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+	mdelay(1);
+	if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+		msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+		msnd_disable_irq(&dev);
+
+	}
+	mdelay(1);
+	if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+		msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+		msnd_disable_irq(&dev);
+
+	}
+	mdelay(1);
+	reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+	dev.mode = file->f_mode;
+	set_bit(F_AUDIO_INUSE, &dev.flags);
+	reset_queues();
+	return 0;
+}
+
+static int dsp_close(void)
+{
+	dsp_halt();
+	clear_bit(F_AUDIO_INUSE, &dev.flags);
+	return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	int err = 0;
+
+	if (minor == DSPMINOR) {
+
+		if (test_bit(F_AUDIO_INUSE, &dev.flags))
+			return -EBUSY;
+
+		err = dsp_open(file);
+	}
+	else if (minor == MIXERMINOR) {
+		/* nothing */
+	} else
+		err = -EINVAL;
+	
+	if (err >= 0)
+		MOD_INC_USE_COUNT;
+
+	return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	int err = 0;
+
+	if (minor == DSPMINOR) {
+		err = dsp_close();
+	}
+	else if (minor == MIXERMINOR) {
+		/* nothing */
+	} else
+		err = -EINVAL;
+
+	if (err >= 0)
+		MOD_DEC_USE_COUNT;
+	
+	return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+	return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+	return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+	int err = 0;
+	int count = len;
+
+	while (count > 0) {
+		
+		int n;
+
+		if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+			printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+			return n;
+		}
+
+		buf += n;
+		count -= n;
+		
+		if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+			reset_record_queue();
+			msnd_enable_irq(&dev);
+			msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+		}
+
+		if (dev.mode & O_NONBLOCK)
+			return count == len ? -EAGAIN : len - count;
+
+		if (count > 0) {
+
+			set_bit(F_READBLOCK, &dev.flags);
+			interruptible_sleep_on(&dev.readblock);
+			clear_bit(F_READBLOCK, &dev.flags);
+
+			if (signal_pending(current))
+				err = -EINTR;
+
+		}
+
+		if (err != 0)
+			return err;
+	}
+
+	return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+	int err = 0;
+	int count = len;
+
+	while (count > 0) {
+
+		int n;
+
+		if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+			printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+			return n;
+		}
+
+		buf += n;
+		count -= n;
+
+		if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+			
+			reset_play_queue();
+			msnd_enable_irq(&dev);
+			msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+		}
+
+		if (dev.mode & O_NONBLOCK)
+			return count == len ? -EAGAIN : len - count;
+
+		if (count > 0) {
+			
+			set_bit(F_WRITEBLOCK, &dev.flags);
+			interruptible_sleep_on(&dev.writeblock);
+			clear_bit(F_WRITEBLOCK, &dev.flags);
+
+			if (signal_pending(current))
+				err = -EINTR;
+
+		}
+
+		if (err != 0)
+			return err;
+	}
+	
+	return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	if (minor == DSPMINOR) {
+
+		return dsp_read(buf, count);
+
+	} else
+		return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	if (minor == DSPMINOR) {
+
+		return dsp_write(buf, count);
+
+	} else
+		return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+	switch (HIBYTE(wMessage)) {
+	case HIMT_PLAY_DONE:
+		
+		if (dev.lastbank == LOBYTE(wMessage))
+			break;
+		
+		dev.lastbank = LOBYTE(wMessage);
+
+		dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+		if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+			dev.DAPQ->wTail = 0;
+
+		if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+			dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+		if (dev.lastbank < 3) {
+
+			if (DAPF_to_bank(dev.lastbank) > 0) {
+
+				mdelay(1);
+				msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+			} 
+			else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+				memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+				clear_bit(F_WRITING, &dev.flags);
+				msnd_disable_irq(&dev);
+
+			}
+		}
+
+		if (test_bit(F_WRITEBLOCK, &dev.flags))
+			wake_up_interruptible(&dev.writeblock);
+		
+		break;
+
+	case HIMT_RECORD_DONE: {
+
+		WORD wTemp;
+		
+		wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+		if (wTemp > dev.DARQ->wSize)
+			wTemp = 0;
+
+		while (wTemp == dev.DARQ->wHead);
+
+		dev.DARQ->wTail = wTemp;
+
+		outb(HPBLKSEL_1, dev.io + HP_BLKS);
+		if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+		    !test_bit(F_READBLOCK, &dev.flags)) {
+
+			memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+			clear_bit(F_READING, &dev.flags);
+			msnd_disable_irq(&dev);
+
+		}
+		outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+		if (test_bit(F_READBLOCK, &dev.flags))
+			wake_up_interruptible(&dev.readblock);
+
+		} break;
+
+	case HIMT_DSP:
+		switch (LOBYTE(wMessage)) {
+		case HIDSP_PLAY_UNDER:
+		case HIDSP_INT_PLAY_UNDER:
+			printk(KERN_INFO LOGNAME ": Write underflow\n");
+			reset_play_queue();
+			break;
+
+		case HIDSP_INT_RECORD_OVER:
+			printk(KERN_INFO LOGNAME ": Read overflow\n");
+			reset_record_queue();
+			break;
+
+		default:
+			printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+			break;
+		}
+		break;
+
+        case HIMT_MIDI_IN_UCHAR:
+		if (dev.midi_in_interrupt)
+			(*dev.midi_in_interrupt)(&dev);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (test_bit(F_INTERRUPT, &dev.flags) || 
+	    ((multisound_dev_t *)dev_id != &dev))
+		return;
+
+	set_bit(F_INTERRUPT, &dev.flags);
+	
+	if (test_bit(F_BANKONE, &dev.flags))
+		outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	inb(dev.io + HP_RXL);
+ 
+	while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+		eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+		if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+			dev.DSPQ->wHead = 0;
+	}
+
+	if (test_bit(F_BANKONE, &dev.flags))
+		outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+	clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+	NULL,
+	dev_read,
+	dev_write,
+	NULL,
+	NULL,
+	dev_ioctl,
+	NULL,
+	dev_open,
+	dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+	int timeout = 20000;
+		
+	outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+	
+	mdelay(1);
+
+	dev.info = inb(dev.io + HP_INFO);
+
+	outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+	mdelay(1);
+
+	while (timeout-- > 0) {
+
+		if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+			return 0;
+		
+		mdelay(1);
+	}
+
+	printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+	return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+	char *xv, *rev = NULL;
+	char *pin = "Pinnacle", *fiji = "Fiji";
+	char *pinfiji = "Pinnacle/Fiji";
+
+	if (check_region(dev.io, dev.numio)) {
+		
+		printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+		return -ENODEV;
+	}
+
+	request_region(dev.io, dev.numio, "probing");
+
+	if (reset_dsp() < 0) {
+		
+		release_region(dev.io, dev.numio);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+	switch (dev.info >> 4) {
+	case 0xf: xv = "<= 1.15"; break;
+	case 0x1: xv = "1.18/1.2"; break;
+	case 0x2: xv = "1.3"; break;
+	case 0x3: xv = "1.4"; break;
+	default: xv = "unknown"; break;
+	}
+		
+	switch (dev.info & 0x7) {
+	case 0x0: rev = "I"; dev.name = pin; break;
+	case 0x1: rev = "F"; dev.name = pin; break;
+	case 0x2: rev = "G"; dev.name = pin; break;
+	case 0x3: rev = "H"; dev.name = pin; break;
+	case 0x4: rev = "E"; dev.name = fiji; break;
+	case 0x5: rev = "C"; dev.name = fiji; break;
+	case 0x6: rev = "D"; dev.name = fiji; break;
+	case 0x7:
+		rev = "A-B (Fiji) or A-E (Pinnacle)";
+		dev.name = pinfiji;
+		break;
+	}
+
+	printk(KERN_INFO LOGNAME ": Turtle Beach %s revision %s, Xilinx version %s, "
+	       "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+	       dev.name,
+	       rev, xv,
+	       dev.io, dev.io + dev.numio - 1,
+	       dev.irq,
+	       dev.base, dev.base + 0x7fff);
+
+	release_region(dev.io, dev.numio);
+	
+	return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+	int n;
+	LPDAQD lpDAQ;
+
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, 0x8000);
+	
+	outb(HPBLKSEL_1, dev.io + HP_BLKS);
+	memset_io(dev.base, 0, 0x8000);
+	
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+	dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+	dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+	dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+	dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+	dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+	dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+	dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+	dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+	dev.sample_size = DEFSAMPLESIZE;
+	dev.sample_rate = DEFSAMPLERATE;
+	dev.channels = DEFCHANNELS;
+
+	for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+		
+		writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+		writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+	}
+
+	for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+		writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+		writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+		writew(1, &lpDAQ->wFormat);
+		writew(dev.sample_size, &lpDAQ->wSampleSize);
+		writew(dev.channels, &lpDAQ->wChannels);
+		writew(dev.sample_rate, &lpDAQ->wSampleRate);
+		writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+		writew(n + 1, &lpDAQ->wFlags);
+
+	}	
+
+	dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+	dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+	dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+	writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+	writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+	writew(0, &dev.MIDQ->wHead);
+	writew(0, &dev.MIDQ->wTail);
+
+	writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+	writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+	writew(0, &dev.MODQ->wHead);
+	writew(0, &dev.MODQ->wTail);
+
+	writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+	writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+	writew(0, &dev.DAPQ->wHead);
+	writew(0, &dev.DAPQ->wTail);
+
+	writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+	writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+	writew(0, &dev.DARQ->wHead);
+	writew(0, &dev.DARQ->wTail);
+
+	writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+	writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+	writew(0, &dev.DSPQ->wHead);
+	writew(0, &dev.DSPQ->wTail);
+
+	writew(0, &dev.SMA->wCurrPlayBytes);
+	writew(0, &dev.SMA->wCurrRecordBytes);
+
+	writew(0, &dev.SMA->wCurrPlayVolLeft);
+	writew(0, &dev.SMA->wCurrPlayVolRight);
+
+	writew(0, &dev.SMA->wCurrInVolLeft);
+	writew(0, &dev.SMA->wCurrInVolRight);
+
+	writew(0, &dev.SMA->wCurrMastVolLeft);
+	writew(0, &dev.SMA->wCurrMastVolRight);
+
+	writel(0x00010000, &dev.SMA->dwCurrPlayPitch);
+	writel(0x00000001, &dev.SMA->dwCurrPlayRate);
+
+	writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+	writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+	writew(0x303, &dev.SMA->wCurrInputTagBits);
+	writew(0, &dev.SMA->wCurrLeftPeak);
+	writew(0, &dev.SMA->wCurrRightPeak);
+
+	writeb(0, &dev.SMA->bInPotPosRight);
+	writeb(0, &dev.SMA->bInPotPosLeft);
+
+	writeb(0, &dev.SMA->bAuxPotPosRight);
+	writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+	writew(1, &dev.SMA->wCurrPlayFormat);
+	writew(dev.sample_size, &dev.SMA->wCurrPlaySampleSize);
+	writew(dev.channels, &dev.SMA->wCurrPlayChannels);
+	writew(dev.sample_rate, &dev.SMA->wCurrPlaySampleRate);
+	writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+	return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+	if (!dev.calibrate_signal) {
+
+		printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+		writew(readw(&dev.SMA->wCurrHostStatusFlags)
+		       | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+	}
+	else {
+
+		printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+		writew(readw(&dev.SMA->wCurrHostStatusFlags)
+		       & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+	}
+	
+	writew(srate, &dev.SMA->wCalFreqAtoD);
+
+	if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+	    msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + HZ;
+		schedule();
+		current->timeout = 0;
+		printk("successful\n");
+		return 0;
+	}
+
+	printk("failed\n");
+
+	return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+	outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+	printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else	
+	printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+	INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+	if (!INITCODE) {
+		printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+		return -EBUSY;
+	}
+
+	PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+	if (!PERMCODE) {
+		printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+		vfree(INITCODE);
+		return -EBUSY;
+	}
+#endif
+	memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+	if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+		return -ENODEV;
+	}
+
+#ifndef HAVE_DSPCODEH
+	vfree(INITCODE);
+	vfree(PERMCODE);
+#endif
+
+	return 0;
+}
+
+__initfunc(static int initialize(void))
+{
+	int err, timeout;
+
+	if ((err = init_sma()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+		return err;
+	}
+
+	if ((err = reset_dsp()) < 0)
+		return err;
+	
+	if ((err = upload_dsp_code()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+		return err;
+
+	} else
+		printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+	timeout = 2000;
+
+	while (readw(dev.base)) {
+		
+		mdelay(1);
+		if (--timeout < 0)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+	int err;
+
+	printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+	if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+		return err;
+	
+	}
+
+	request_region(dev.io, dev.numio, DEVNAME);
+
+        if ((err = initialize()) < 0) {
+
+		printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return err;
+
+	}
+
+	if ((err = msnd_register(&dev)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return err;
+	}
+
+	if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+		msnd_unregister(&dev);
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return DSPMINOR;
+	}
+
+	if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+		unregister_sound_mixer(MIXERMINOR);
+		msnd_unregister(&dev);
+		release_region(dev.io, dev.numio);
+		free_irq(dev.irq, &dev);
+		return MIXERMINOR;
+	}
+	printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+	calibrate_adc(dev.sample_rate);
+	set_recsrc(0);
+	
+	return 0;
+}
+
+static void unload_multisound(void)
+{
+	release_region(dev.io, dev.numio);
+	free_irq(dev.irq, &dev);
+	unregister_sound_mixer(MIXERMINOR);
+	unregister_sound_dsp(DSPMINOR);
+	msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR				("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION			("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM				(io, "i");
+MODULE_PARM				(irq, "i");
+MODULE_PARM				(mem, "i");
+MODULE_PARM				(major, "i");
+MODULE_PARM				(fifosize, "i");
+MODULE_PARM				(calibrate_signal, "i");
+
+static int io __initdata =		-1;
+static int irq __initdata =		-1;
+static int mem __initdata =		-1;
+static int fifosize __initdata =	DEFFIFOSIZE;
+static int
+calibrate_signal __initdata =		0;
+
+int init_module(void)
+{
+	int err;
+
+	printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+	       VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+	
+	if (io == -1 || irq == -1 || mem == -1) {
+
+		printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+	}
+		
+	if (io == -1 ||
+	    !(io == 0x290 ||
+	      io == 0x260 ||
+	      io == 0x250 ||
+	      io == 0x240 ||
+	      io == 0x230 ||
+	      io == 0x220 ||
+	      io == 0x210 ||
+	      io == 0x3e0)) {
+
+		printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+		return -EINVAL;
+	}
+	
+	if (irq == -1 ||
+	    !(irq == 5 ||
+	      irq == 7 ||
+	      irq == 9 ||
+	      irq == 10 ||
+	      irq == 11 ||
+	      irq == 12)) {
+		
+		printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+		return -EINVAL;
+	}
+
+	if (mem == -1 ||
+	    !(mem == 0xb0000 ||
+	      mem == 0xc8000 ||
+	      mem == 0xd0000 ||
+	      mem == 0xd8000 ||
+	      mem == 0xe0000 ||
+	      mem == 0xe8000)) {
+		
+		printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+		       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+		return -EINVAL;
+	}
+
+	if (fifosize < 16)
+		fifosize = 16;
+
+	if (fifosize > 768)
+		fifosize = 768;
+
+	dev.type = msndPinnacle;
+	dev.io = io;
+	dev.numio = DSP_NUMIO;
+	dev.irq = irq;
+	dev.base = phys_to_virt(mem);
+	dev.fifosize = fifosize * 1024;
+	dev.calibrate_signal = calibrate_signal ? 1 : 0;
+	dev.recsrc = 0;
+	dev.inc_ref = mod_inc_ref;
+	dev.dec_ref = mod_dec_ref;
+
+	init_waitqueue(&dev.writeblock);
+	init_waitqueue(&dev.readblock);
+	msnd_fifo_init(&dev.DAPF);
+	msnd_fifo_init(&dev.DARF);
+	spin_lock_init(&dev.lock);
+
+	printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+	if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+		return err;
+	}
+
+	if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+		
+		printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+		msnd_fifo_free(&dev.DAPF);
+		return err;
+	}
+
+	if ((err = probe_multisound()) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Probe failed\n");
+		msnd_fifo_free(&dev.DAPF);
+		msnd_fifo_free(&dev.DARF);
+		return err;
+
+	}
+	
+	if ((err = attach_multisound()) < 0) {
+
+		printk(KERN_ERR LOGNAME ": Attach failed\n");
+		msnd_fifo_free(&dev.DAPF);
+		msnd_fifo_free(&dev.DARF);
+		return err;
+
+	}
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	printk(KERN_INFO LOGNAME ": Unloading\n");
+
+	unload_multisound();
+
+	msnd_fifo_free(&dev.DAPF);
+	msnd_fifo_free(&dev.DARF);
+
+}
+#endif
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/msnd_pinnacle.h linux/drivers/sound/msnd_pinnacle.h
--- v2.1.105/linux/drivers/sound/msnd_pinnacle.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/msnd_pinnacle.h	Sat Jun 13 10:23:52 1998
@@ -0,0 +1,247 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_pinnacle.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO		0x08
+
+#define	HP_DSPR			0x04
+#define	HP_BLKS			0x04
+
+#define HPDSPRESET_OFF		2
+#define HPDSPRESET_ON		0
+
+#define HPBLKSEL_0		2
+#define HPBLKSEL_1		3
+
+#define	HIMT_DAT_OFF		0x03
+
+#define	HIDSP_PLAY_UNDER	0x00
+#define	HIDSP_INT_PLAY_UNDER	0x01
+#define	HIDSP_SSI_TX_UNDER  	0x02
+#define HIDSP_RECQ_OVERFLOW	0x08
+#define HIDSP_INT_RECORD_OVER	0x09
+#define HIDSP_SSI_RX_OVERFLOW	0x0a
+
+#define	HIDSP_MIDI_IN_OVER	0x10
+
+#define	HIDSP_MIDI_FRAME_ERR	0x11
+#define	HIDSP_MIDI_PARITY_ERR	0x12
+#define	HIDSP_MIDI_OVERRUN_ERR	0x13
+
+#define HIDSP_INPUT_CLIPPING	0x20
+#define	HIDSP_MIX_CLIPPING	0x30
+#define HIDSP_DAT_IN_OFF	0x21
+
+#define	HDEX_BASE	       	0x92
+#define	HDEX_PLAY_START		(0 + HDEX_BASE)
+#define	HDEX_PLAY_STOP		(1 + HDEX_BASE)
+#define	HDEX_PLAY_PAUSE		(2 + HDEX_BASE)
+#define	HDEX_PLAY_RESUME	(3 + HDEX_BASE)
+#define	HDEX_RECORD_START	(4 + HDEX_BASE)
+#define	HDEX_RECORD_STOP	(5 + HDEX_BASE)
+#define	HDEX_MIDI_IN_START 	(6 + HDEX_BASE)
+#define	HDEX_MIDI_IN_STOP	(7 + HDEX_BASE)
+#define	HDEX_MIDI_OUT_START	(8 + HDEX_BASE)
+#define	HDEX_MIDI_OUT_STOP	(9 + HDEX_BASE)
+#define	HDEX_AUX_REQ		(10 + HDEX_BASE)
+
+#define	HDEXAR_SET_ANA_IN	0
+#define	HDEXAR_CLEAR_PEAKS	1
+#define	HDEXAR_IN_SET_POTS	2
+#define	HDEXAR_AUX_SET_POTS	3
+#define	HDEXAR_CAL_A_TO_D	4
+#define	HDEXAR_RD_EXT_DSP_BITS	5
+
+#define	HDEXAR_SET_SYNTH_IN     4
+#define	HDEXAR_READ_DAT_IN      5
+#define	HDEXAR_MIC_SET_POTS     6
+#define	HDEXAR_SET_DAT_IN       7
+
+#define HDEXAR_SET_SYNTH_48     8
+#define HDEXAR_SET_SYNTH_44     9
+
+#define TIME_PRO_RESET_DONE	0x028A
+#define TIME_PRO_SYSEX		0x001E
+#define TIME_PRO_RESET		0x0032
+
+#define AGND			0x01
+#define SIGNAL			0x02
+
+#define EXT_DSP_BIT_DCAL	0x0001
+#define EXT_DSP_BIT_MIDI_CON	0x0002
+
+#define BUFFSIZE		0x8000
+#define HOSTQ_SIZE		0x40
+
+#define SRAM_CNTL_START		0x7F00
+#define SMA_STRUCT_START	0x7F40
+
+#define DAP_BUFF_SIZE		0x2400
+#define DAR_BUFF_SIZE		0x2000
+
+#define DAPQ_STRUCT_SIZE	0x10
+#define DARQ_STRUCT_SIZE	0x10
+#define DAPQ_BUFF_SIZE		(3 * 0x10)
+#define DARQ_BUFF_SIZE		(3 * 0x10)
+#define MODQ_BUFF_SIZE		0x400
+#define MIDQ_BUFF_SIZE		0x800
+#define DSPQ_BUFF_SIZE		0x5A0
+
+#define DAPQ_DATA_BUFF		0x6C00
+#define DARQ_DATA_BUFF		0x6C30
+#define MODQ_DATA_BUFF		0x6C60
+#define MIDQ_DATA_BUFF		0x7060
+#define DSPQ_DATA_BUFF		0x7860
+
+#define DAPQ_OFFSET		SRAM_CNTL_START
+#define DARQ_OFFSET		(SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET		(SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET		(SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET		(SRAM_CNTL_START + 0x20)
+
+#define WAVEHDR_MOP		0
+#define EXTOUT_MOP		1
+#define HWINIT_MOP		0xFE
+#define NO_MOP			0xFF
+
+#define MAX_MOP			1
+
+#define EXTIN_MIP		0
+#define WAVEHDR_MIP		1
+#define HWINIT_MIP		0xFE
+
+#define MAX_MIP			1
+
+struct SMA0_CommonData {
+	WORD wCurrPlayBytes;
+	WORD wCurrRecordBytes;
+	WORD wCurrPlayVolLeft;
+	WORD wCurrPlayVolRight;
+
+	WORD wCurrInVolLeft;
+	WORD wCurrInVolRight;
+	WORD wCurrMHdrVolLeft;
+	WORD wCurrMHdrVolRight;
+
+	DWORD dwCurrPlayPitch;
+	DWORD dwCurrPlayRate;
+
+	WORD wCurrMIDIIOPatch;
+
+	WORD wCurrPlayFormat;
+	WORD wCurrPlaySampleSize;
+	WORD wCurrPlayChannels;
+	WORD wCurrPlaySampleRate;
+
+	WORD wCurrRecordFormat;
+	WORD wCurrRecordSampleSize;
+	WORD wCurrRecordChannels;
+	WORD wCurrRecordSampleRate;
+
+	WORD wCurrDSPStatusFlags;
+	WORD wCurrHostStatusFlags;
+
+	WORD wCurrInputTagBits;
+	WORD wCurrLeftPeak;
+	WORD wCurrRightPeak;
+
+	BYTE bMicPotPosLeft;
+	BYTE bMicPotPosRight;
+
+	BYTE bMicPotMaxLeft;
+	BYTE bMicPotMaxRight;
+
+	BYTE bInPotPosLeft;
+	BYTE bInPotPosRight;
+	
+	BYTE bAuxPotPosLeft;
+	BYTE bAuxPotPosRight;
+	
+	BYTE bInPotMaxLeft;
+	BYTE bInPotMaxRight;
+	BYTE bAuxPotMaxLeft;
+	BYTE bAuxPotMaxRight;
+	BYTE bInPotMaxMethod;
+	BYTE bAuxPotMaxMethod;
+
+	WORD wCurrMastVolLeft;
+	WORD wCurrMastVolRight;
+
+	WORD wCalFreqAtoD;
+
+	WORD wCurrAuxVolLeft;
+	WORD wCurrAuxVolRight;
+
+	WORD wCurrPlay1VolLeft;
+	WORD wCurrPlay1VolRight;
+	WORD wCurrPlay2VolLeft;
+	WORD wCurrPlay2VolRight;
+	WORD wCurrPlay3VolLeft;
+	WORD wCurrPlay3VolRight;
+	WORD wCurrPlay4VolLeft;
+	WORD wCurrPlay4VolRight;
+	WORD wCurrPlay1PeakLeft;
+	WORD wCurrPlay1PeakRight;
+	WORD wCurrPlay2PeakLeft;
+	WORD wCurrPlay2PeakRight;
+	WORD wCurrPlay3PeakLeft;
+	WORD wCurrPlay3PeakRight;
+	WORD wCurrPlay4PeakLeft;
+	WORD wCurrPlay4PeakRight;
+	WORD wCurrPlayPeakLeft;
+	WORD wCurrPlayPeakRight;
+
+	WORD wCurrDATSR;
+	WORD wCurrDATRXCHNL;
+	WORD wCurrDATTXCHNL;
+	WORD wCurrDATRXRate;
+
+	DWORD dwDSPPlayCount;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+#  include "pndsperm.c"
+#  include "pndspini.c"
+#  define PERMCODE		pndsperm
+#  define INITCODE		pndspini
+#  define PERMCODESIZE		sizeof(pndsperm)
+#  define INITCODESIZE		sizeof(pndspini)
+#else
+#  define PERMCODEFILE		CONFIG_MSNDPIN_PERM_FILE
+#  define INITCODEFILE		CONFIG_MSNDPIN_INIT_FILE
+#  define PERMCODE		dspini
+#  define INITCODE		permini
+#  define PERMCODESIZE		sizeof_dspini
+#  define INITCODESIZE		sizeof_permini
+#endif
+#define LONGNAME		"MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.105/linux/drivers/sound/soundcard.c	Tue Jun  9 11:57:30 1998
+++ linux/drivers/sound/soundcard.c	Sat Jun 13 11:40:31 1998
@@ -153,13 +153,16 @@
 #else
 #define MODULEPROCSTRING "Driver compiled into kernel"
 #endif
-	
+
+	down(&uts_sem);	
+
 	len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
 		      "Load type: " MODULEPROCSTRING "\n"
 		      "Kernel: %s %s %s %s %s\n"
 		      "Config options: %x\n\nInstalled drivers: \n", 
 		      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
 		      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+	up(&uts_sem);
 	
 	for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
 		if (!sound_drivers[i].card_type)
diff -u --recursive --new-file v2.1.105/linux/drivers/sound/v_midi.c linux/drivers/sound/v_midi.c
--- v2.1.105/linux/drivers/sound/v_midi.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/v_midi.c	Sat Jun 13 10:23:52 1998
@@ -21,10 +21,11 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-#ifdef CONFIG_VMIDI
-
 #include "sound_config.h"
 #include "soundmodule.h"
+
+#ifdef CONFIG_VMIDI
+
 #include "v_midi.h"
 
 static vmidi_devc *v_devc[2] = { NULL, NULL};
diff -u --recursive --new-file v2.1.105/linux/drivers/zorro/Makefile linux/drivers/zorro/Makefile
--- v2.1.105/linux/drivers/zorro/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/zorro/Makefile	Mon Jun  8 11:03:49 1998
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux/drivers/zorro/ directory.
+#
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_OBJS   := zorro.o
+L_TARGET := zorro.a
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.105/linux/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- v2.1.105/linux/drivers/zorro/zorro.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/zorro/zorro.c	Mon Jun  8 11:03:50 1998
@@ -0,0 +1,1245 @@
+/*
+ *    linux/arch/m68k/amiga/zorro.c
+ *
+ *    Copyright (C) 1995 Geert Uytterhoeven
+ *
+ *    This file is subject to the terms and conditions of the GNU General Public
+ *    License.  See the file COPYING in the main directory of this archive
+ *    for more details.
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/setup.h>
+#include <asm/bitops.h>
+#include <asm/amigahw.h>
+#include <linux/zorro.h>
+
+
+#ifdef CONFIG_ZORRO
+
+    /*
+     *  Zorro Expansion Device Manufacturers and Products
+     */
+
+struct Manufacturer {
+    const char *Name;
+    u_short Manuf;
+    u_short NumProd;
+    const struct Product *Products;
+};
+
+struct Product {
+    const char *Name;
+    u_char Class;
+    u_char Prod;
+};
+
+struct GVP_Product {
+    const char *Name;
+    u_char Class;
+    u_char EPC;
+};
+
+
+    /*
+     *  Macro's to make life easier
+     */
+
+#define ARRAYSIZE(x)		(sizeof(x)/sizeof(*(x)))
+
+#define BEGIN_PROD(id) \
+    static struct Product Prod_##id[] = {
+#define PROD(name, class, id) \
+    { name, ZORRO_CLASS_##class, ZORRO_PROD(ZORRO_PROD_##id) },
+
+#define BEGIN_GVP_PROD \
+    static struct GVP_Product Ext_Prod_GVP[] = {
+#define GVP_PROD(name, class, id) \
+    { name, ZORRO_CLASS_##class, ZORRO_EPC(ZORRO_PROD_##id) },
+
+#define BEGIN_MANUF \
+    static struct Manufacturer Manufacturers[] = {
+#define MANUF(name, id) \
+    { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id },
+
+#define END \
+    };
+
+
+    /*
+     *  Recognized Zorro Expansion Devices
+     */
+
+BEGIN_PROD(PACIFIC_PERIPHERALS)
+    PROD("SE 2000 A500", HD, PACIFIC_PERIPHERALS_SE_2000_A500)
+    PROD(NULL, SCSI, PACIFIC_PERIPHERALS_SCSI)
+END
+
+BEGIN_PROD(MACROSYSTEMS_USA_2)
+    PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE)
+END
+
+BEGIN_PROD(KUPKE_1)
+    PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB)
+END
+
+BEGIN_PROD(MEMPHIS)
+    PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER)
+END
+
+BEGIN_PROD(3_STATE)
+    PROD("Megamix 2000", RAM, 3_STATE_MEGAMIX_2000)
+END
+
+BEGIN_PROD(COMMODORE_BRAUNSCHWEIG)
+    PROD("A2088 XT/A2286 AT", BRIDGE, CBM_A2088_A2286)
+    PROD("A2286 AT", BRIDGE, CBM_A2286)
+    PROD("A4091", SCSI, CBM_A4091_1)
+    PROD("A2386-SX", BRIDGE, CBM_A2386SX_1)
+END
+
+BEGIN_PROD(COMMODORE_WEST_CHESTER_1)
+    PROD("A2090/A2090A", SCSI, CBM_A2090A)
+    PROD("A590/A2091", SCSI, CBM_A590_A2091_1)
+    PROD("A590/A2091", SCSI, CBM_A590_A2091_2)
+    PROD("A2090B 2090 Autoboot", SCSI, CBM_A2090B)
+    PROD("A2060", ARCNET, CBM_A2060)
+    PROD("A590/A2052/A2058/A2091", RAM, CBM_A590_A2052_A2058_A2091)
+    PROD("A560", RAM, CBM_A560_RAM)
+    PROD("A2232 Prototype", MULTIIO, CBM_A2232_PROTOTYPE)
+    PROD("A2232", MULTIIO, CBM_A2232)
+    PROD("A2620 68020/RAM", TURBO_RAM, CBM_A2620)
+    PROD("A2630 68030/RAM", TURBO_RAM, CBM_A2630)
+    PROD("A4091", SCSI, CBM_A4091_2)
+    PROD("A2065", ETHERNET, CBM_A2065_1)
+    PROD("Romulator Card", UNKNOWN, CBM_ROMULATOR)
+    PROD("A3000 Test Fixture", MISC, CBM_A3000_TEST_FIXTURE)
+    PROD("A2386-SX", BRIDGE, CBM_A2386SX_2)
+    PROD("A2065", ETHERNET, CBM_A2065_2)
+END
+
+BEGIN_PROD(COMMODORE_WEST_CHESTER_2)
+    PROD("A2090/A2090A Combitec/MacroSystem", SCSI, CBM_A2090A_CM)
+END
+
+BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
+    PROD("EXP8000", RAM, PPS_EXP8000)
+END
+
+BEGIN_PROD(KOLFF_COMPUTER_SUPPLIES)
+    PROD("KCS Power PC Board", BRIDGE, KCS_POWER_PC_BOARD)
+END
+
+BEGIN_PROD(CARDCO_1)
+    PROD("Kronos 2000", SCSI, CARDCO_KRONOS_2000_1)
+    PROD("A1000", SCSI, CARDCO_A1000_1)
+    PROD("Escort", SCSI, CARDCO_ESCORT)
+    PROD("A2410 HiRes", GFX, CARDCO_A2410)
+END
+
+BEGIN_PROD(A_SQUARED)
+    PROD("Live! 2000", VIDEO, A_SQUARED_LIVE_2000)
+END
+
+BEGIN_PROD(COMSPEC_COMMUNICATIONS)
+    PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000)
+END
+
+BEGIN_PROD(ANAKIN_RESEARCH)
+    PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL)
+END
+
+BEGIN_PROD(MICROBOTICS)
+    PROD("StarBoard II", RAM, MICROBOTICS_STARBOARD_II)
+    PROD("StarDrive", SCSI, MICROBOTICS_STARDRIVE)
+    PROD("8-Up (Rev A)", RAM, MICROBOTICS_8_UP_A)
+    PROD("8-Up (Rev Z)", RAM, MICROBOTICS_8_UP_Z)
+    PROD("Delta", RAM, MICROBOTICS_DELTA_RAM)
+    PROD("8-Star", RAM, MICROBOTICS_8_STAR_RAM)
+    PROD("8-Star", MISC, MICROBOTICS_8_STAR)
+    PROD("VXL RAM*32", RAM, MICROBOTICS_VXL_RAM_32)
+    PROD("VXL-30", TURBO, MICROBOTICS_VXL_68030)
+    PROD("Delta", MISC, MICROBOTICS_DELTA)
+    PROD("MBX 1200/1200z", RAM, MICROBOTICS_MBX_1200_1200Z_RAM)
+    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_1)
+    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_2)
+    PROD("MBX 1200/1200z", MISC, MICROBOTICS_MBX_1200_1200Z)
+END
+
+BEGIN_PROD(ACCESS_ASSOCIATES_ALEGRA)
+END
+
+BEGIN_PROD(EXPANSION_TECHNOLOGIES)
+END
+
+BEGIN_PROD(ASDG)
+    PROD(NULL, RAM, ASDG_MEMORY_1)
+    PROD(NULL, RAM, ASDG_MEMORY_2)
+    PROD("EB-920 Lan Rover", ETHERNET, ASDG_EB920_LAN_ROVER)
+    PROD("GPIB/Dual IEEE-488/Twin-X", MULTIIO, ASDG_GPIB_DUALIEEE488_TWIN_X)
+END
+
+BEGIN_PROD(IMTRONICS_1)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2)
+END
+
+BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL)
+    PROD("A2410 HiRes", GFX, CBM_A2410)
+END
+
+BEGIN_PROD(AMERISTAR)
+    PROD("A2065", ETHERNET, AMERISTAR_A2065)
+    PROD("A560", ARCNET, AMERISTAR_A560)
+    PROD("A4066", ETHERNET, AMERISTAR_A4066)
+END
+
+BEGIN_PROD(SUPRA)
+    PROD("SupraDrive 4x4", SCSI, SUPRA_SUPRADRIVE_4x4)
+    PROD("1000", RAM, SUPRA_1000_RAM)
+    PROD("2000 DMA", SCSI, SUPRA_2000_DMA)
+    PROD("500", SCSI_RAM, SUPRA_500)
+    PROD("500", SCSI, SUPRA_500_SCSI)
+    PROD("500XP/2000", RAM, SUPRA_500XP_2000_RAM)
+    PROD("500RX/2000", RAM, SUPRA_500RX_2000_RAM)
+    PROD("2400zi", MODEM, SUPRA_2400ZI)
+    PROD("500XP/SupraDrive WordSync", SCSI, SUPRA_500XP_SUPRADRIVE_WORDSYNC)
+    PROD("SupraDrive WordSync II", SCSI, SUPRA_SUPRADRIVE_WORDSYNC_II)
+    PROD("2400zi+", MODEM, SUPRA_2400ZIPLUS)
+END
+
+BEGIN_PROD(COMPUTER_SYSTEMS_ASSOCIATES)
+    PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM)
+    PROD("12 Gauge", SCSI, CSA_12_GAUGE)
+END
+
+BEGIN_PROD(MARC_MICHAEL_GROTH)
+END
+
+BEGIN_PROD(M_TECH)
+    PROD("AT500", RAM, MTEC_AT500_1)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_1)
+    PROD("Impact Series I", SCSI_RAM, GVP_IMPACT_SERIES_I)
+END
+
+BEGIN_PROD(BYTEBOX)
+    PROD("A500", UNKNOWN, BYTEBOX_A500)
+END
+
+BEGIN_PROD(DKB_POWER_COMPUTING)
+    PROD("SecureKey", UNKNOWN, DKB_POWER_COMPUTING_SECUREKEY)
+    PROD("DKM 3128", RAM, DKB_POWER_COMPUTING_DKM_3128)
+    PROD("Rapid Fire", SCSI, DKB_POWER_COMPUTING_RAPID_FIRE)
+    PROD("DKM 1202", FPU_RAM, DKB_POWER_COMPUTING_DKM_1202)
+    PROD("Cobra/Viper II 68EC030", TURBO, DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030)
+    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_1)
+    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_2)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_2)
+    PROD("Impact Series I (4K)", SCSI, GVP_IMPACT_SERIES_I_4K)
+    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_2)
+    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_3)
+    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_1)
+    PROD("Impact 3001", RAM, GVP_IMPACT_3001_RAM)
+    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_1)
+/*  PROD(NULL, UNKNOWN, GVP_EPC_BASE) */
+    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_2)
+/*  PROD("A2000 030", TURBO, GVP_A2000_030) */
+/*  PROD("GForce 040", TURBO_SCSI, GFORCE_040_SCSI_2) */
+    PROD("GForce 040/060", TURBO_SCSI, GVP_GFORCE_040_060)
+    PROD("Impact Vision 24", GFX, GVP_IMPACT_VISION_24)
+    PROD("GForce 040", TURBO, GVP_GFORCE_040_2)
+END
+
+BEGIN_GVP_PROD					/* ZORRO_PROD_GVP_EPC_BASE */
+    GVP_PROD("GForce 040", TURBO, GVP_GFORCE_040_1)
+    GVP_PROD("GForce 040", TURBO_SCSI, GVP_GFORCE_040_SCSI_1)
+    GVP_PROD("A1291", SCSI, GVP_A1291)
+    GVP_PROD("Combo 030 R4", TURBO, GVP_COMBO_030_R4)
+    GVP_PROD("Combo 030 R4", TURBO_SCSI, GVP_COMBO_030_R4_SCSI)
+    GVP_PROD("Phone Pak", UNKNOWN, GVP_PHONEPAK)
+    GVP_PROD("IO-Extender", MULTIIO, GVP_IO_EXTENDER)
+    GVP_PROD("GForce 030", TURBO, GVP_GFORCE_030)
+    GVP_PROD("GForce 030", TURBO_SCSI, GVP_GFORCE_030_SCSI)
+    GVP_PROD("A530", TURBO, GVP_A530)
+    GVP_PROD("A530", TURBO_SCSI, GVP_A530_SCSI)
+    GVP_PROD("Combo 030 R3", TURBO, GVP_COMBO_030_R3)
+    GVP_PROD("Combo 030 R3", TURBO_SCSI, GVP_COMBO_030_R3_SCSI)
+    GVP_PROD("Series-II", SCSI, GVP_SERIES_II)
+END
+
+BEGIN_PROD(CALIFORNIA_ACCESS_SYNERGY)
+    PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU)
+END
+
+BEGIN_PROD(XETEC)
+    PROD("FastCard", SCSI, XETEC_FASTCARD)
+    PROD("FastCard", RAM, XETEC_FASTCARD_RAM)
+    PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS)
+END
+
+BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
+    PROD("Mercury", TURBO, PPS_MERCURY)
+    PROD("A3000 68040", TURBO, PPS_A3000_68040)
+    PROD("A2000 68040", TURBO, PPS_A2000_68040)
+    PROD("Zeus", TURBO_SCSI_RAM, PPS_ZEUS)
+    PROD("A500 68040", TURBO, PPS_A500_68040)
+END
+
+BEGIN_PROD(XEBEC)
+END
+
+BEGIN_PROD(SPIRIT_TECHNOLOGY)
+    PROD("Insider IN1000", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN1000)
+    PROD("Insider IN500", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN500)
+    PROD("SIN500", RAM, SPIRIT_TECHNOLOGY_SIN500)
+    PROD("HDA 506", HD, SPIRIT_TECHNOLOGY_HDA_506)
+    PROD("AX-S", MISC, SPIRIT_TECHNOLOGY_AX_S)
+    PROD("OctaByte", RAM, SPIRIT_TECHNOLOGY_OCTABYTE)
+    PROD("Inmate", SCSI_RAM, SPIRIT_TECHNOLOGY_INMATE)
+END
+
+BEGIN_PROD(SPIRIT_TECHNOLOGY_2)
+END
+
+BEGIN_PROD(BSC_ALFADATA_1)
+    PROD("ALF 3", SCSI, BSC_ALF_3_1)
+END
+
+BEGIN_PROD(BSC_ALFADATA_2)
+    PROD("ALF 2", SCSI, BSC_ALF_2_1)
+    PROD("ALF 2", SCSI, BSC_ALF_2_2)
+    PROD("ALF 3", SCSI, BSC_ALF_3_2)
+END
+
+BEGIN_PROD(CARDCO_2)
+    PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2)
+    PROD("A1000", SCSI, CARDCO_A1000_2)
+END
+
+BEGIN_PROD(JOCHHEIM)
+    PROD(NULL, RAM, JOCHHEIM_RAM)
+END
+
+BEGIN_PROD(CHECKPOINT_TECHNOLOGIES)
+    PROD("Serial Solution", SERIAL, CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION)
+END
+
+BEGIN_PROD(EDOTRONIK)
+    PROD("IEEE-488 Interface Board", UNKNOWN, EDOTRONIK_IEEE_488)
+    PROD("CBM-8032 Board", UNKNOWN, EDOTRONIK_8032)
+    PROD(NULL, SERIAL, EDOTRONIK_MULTISERIAL)
+    PROD("24Bit Realtime Video Digitizer", UNKNOWN, EDOTRONIK_VIDEODIGITIZER)
+    PROD("32Bit Parallel I/O Interface", UNKNOWN, EDOTRONIK_PARALLEL_IO)
+    PROD("PIC Prototyping Board", UNKNOWN, EDOTRONIK_PIC_PROTOYPING)
+    PROD("16 Channel ADC Interface", UNKNOWN, EDOTRONIK_ADC)
+    PROD("VME-Bus Controller", UNKNOWN, EDOTRONIK_VME)
+    PROD("DSP96000 Realtime Data Acquisition", DSP, EDOTRONIK_DSP96000)
+END
+
+BEGIN_PROD(NES_INC)
+    PROD(NULL, RAM, NES_INC_RAM)
+END
+
+BEGIN_PROD(ICD)
+    PROD("Advantage 2000", SCSI, ICD_ADVANTAGE_2000_SCSI)
+    PROD("Advantage", IDE, ICD_ADVANTAGE_2000_SCSI)
+    PROD("Advantage 2080", RAM, ICD_ADVANTAGE_2080_RAM)
+END
+
+BEGIN_PROD(KUPKE_2)
+    PROD("Omti", HD, KUPKE_OMTI)
+    PROD("Golem SCSI-II", SCSI, KUPKE_SCSI_II)
+    PROD("Golem Box", UNKNOWN, KUPKE_GOLEM_BOX)
+    PROD("030/882", TURBO, KUPKE_030_882)
+    PROD("Golem", SCSI, KUPKE_SCSI_AT)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_3)
+    PROD("A2000-RAM8/2", MISC, GVP_A2000_RAM8)
+    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_2)
+END
+
+BEGIN_PROD(INTERWORKS_NETWORK)
+END
+
+BEGIN_PROD(HARDITAL_SYNTHESIS)
+    PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882)
+END
+
+BEGIN_PROD(APPLIED_ENGINEERING)
+    PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000)
+    PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS)
+END
+
+BEGIN_PROD(BSC_ALFADATA_3)
+    PROD("Oktagon 2008", SCSI, BSC_OKTAGON_2008)
+    PROD("Tandem AT-2008/508", IDE, BSC_TANDEM_AT_2008_508)
+    PROD("Alpha RAM 1200", RAM, BSC_ALFA_RAM_1200)
+    PROD("Oktagon 2008", RAM, BSC_OKTAGON_2008_RAM)
+    PROD("MultiFace I", MULTIIO, BSC_MULTIFACE_I)
+    PROD("MultiFace II", MULTIIO, BSC_MULTIFACE_II)
+    PROD("MultiFace III", MULTIIO, BSC_MULTIFACE_III)
+    PROD("Framebuffer", MISC, BSC_FRAMEBUFFER)
+    PROD("Graffiti", GFXRAM, BSC_GRAFFITI_RAM)
+    PROD("Graffiti", GFX, BSC_GRAFFITI_REG)
+    PROD("ISDN MasterCard", ISDN, BSC_ISDN_MASTERCARD)
+    PROD("ISDN MasterCard II", ISDN, BSC_ISDN_MASTERCARD_II)
+END
+
+BEGIN_PROD(PHOENIX)
+    PROD("ST506", HD, PHOENIX_ST506)
+    PROD(NULL, SCSI, PHOENIX_SCSI)
+    PROD(NULL, RAM, PHOENIX_RAM)
+END
+
+BEGIN_PROD(ADVANCED_STORAGE_SYSTEMS)
+    PROD("Nexus", SCSI, ADVANCED_STORAGE_SYSTEMS_NEXUS)
+    PROD("Nexus", RAM, ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM)
+END
+
+BEGIN_PROD(IMPULSE)
+    PROD("FireCracker 24", GFX, IMPULSE_FIRECRACKER_24)
+END
+
+BEGIN_PROD(IVS)
+    PROD("GrandSlam PIC 2", RAM, IVS_GRANDSLAM_PIC_2)
+    PROD("GrandSlam PIC 1", RAM, IVS_GRANDSLAM_PIC_1)
+    PROD("OverDrive", HD, IVS_OVERDRIVE)
+    PROD("TrumpCard Classic", SCSI, IVS_TRUMPCARD_CLASSIC)
+    PROD("TrumpCard Pro/GrandSlam", SCSI, IVS_TRUMPCARD_PRO_GRANDSLAM)
+    PROD("Meta-4", RAM, IVS_META_4)
+    PROD("Wavetools", AUDIO, IVS_WAVETOOLS)
+    PROD("Vector", SCSI, IVS_VECTOR_1)
+    PROD("Vector", SCSI, IVS_VECTOR_2)
+END
+
+BEGIN_PROD(VECTOR_1)
+    PROD("Connection", MULTIIO, VECTOR_CONNECTION_1)
+END
+
+BEGIN_PROD(XPERT_PRODEV)
+    PROD("Visiona", GFXRAM, XPERT_PRODEV_VISIONA_RAM)
+    PROD("Visiona", GFX, XPERT_PRODEV_VISIONA_REG)
+    PROD("Merlin", GFXRAM, XPERT_PRODEV_MERLIN_RAM)
+    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_1)
+    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_2)
+END
+
+BEGIN_PROD(HYDRA_SYSTEMS)
+    PROD("Amiganet", ETHERNET, HYDRA_SYSTEMS_AMIGANET)
+END
+
+BEGIN_PROD(SUNRIZE_INDUSTRIES)
+    PROD("AD1012", AUDIO, SUNRIZE_INDUSTRIES_AD1012)
+    PROD("AD516", AUDIO, SUNRIZE_INDUSTRIES_AD516)
+    PROD("DD512", AUDIO, SUNRIZE_INDUSTRIES_DD512)
+END
+
+BEGIN_PROD(TRICERATOPS)
+    PROD(NULL, MULTIIO, TRICERATOPS_MULTI_IO)
+END
+
+BEGIN_PROD(APPLIED_MAGIC)
+    PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER)
+    PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER)
+END
+
+BEGIN_PROD(GFX_BASE)
+    PROD("GDA-1 VRAM", GFX, GFX_BASE_GDA_1_VRAM)
+    PROD("GDA-1", GFX, GFX_BASE_GDA_1)
+END
+
+BEGIN_PROD(ROCTEC)
+    PROD("RH 800C", HD, ROCTEC_RH_800C)
+    PROD("RH 800C", RAM, ROCTEC_RH_800C_RAM)
+END
+
+BEGIN_PROD(KATO)
+    PROD("Melody MPEG", AUDIO, KATO_MELODY)
+    PROD("Rainbow II", GFX, HELFRICH_RAINBOW_II)	/* ID clash!! */
+    PROD("Rainbow III", GFX, HELFRICH_RAINBOW_III)	/* ID clash!! */
+END
+
+BEGIN_PROD(ATLANTIS)
+END
+
+BEGIN_PROD(PROTAR)
+END
+
+BEGIN_PROD(ACS)
+END
+
+BEGIN_PROD(SOFTWARE_RESULTS_ENTERPRISES)
+    PROD("Golden Gate 2 Bus+", BRIDGE, SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS)
+END
+
+BEGIN_PROD(MASOBOSHI)
+    PROD("MasterCard SC201", RAM, MASOBOSHI_MASTER_CARD_SC201)
+    PROD("MasterCard MC702", SCSI_IDE, MASOBOSHI_MASTER_CARD_MC702)
+    PROD("MVD 819", UNKNOWN, MASOBOSHI_MVD_819)
+END
+
+BEGIN_PROD(MAINHATTAN_DATA)
+    PROD(NULL, IDE, MAINHATTAN_DATA_IDE)
+END
+
+BEGIN_PROD(VILLAGE_TRONIC)
+    PROD("Domino", GFXRAM, VILLAGE_TRONIC_DOMINO_RAM)
+    PROD("Domino", GFX, VILLAGE_TRONIC_DOMINO_REG)
+    PROD("Domino 16M Prototype", GFX, VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE)
+    PROD("Picasso II/II+", GFXRAM, VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM)
+    PROD("Picasso II/II+", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG)
+    PROD("Picasso II/II+ (Segmented Mode)", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE)
+    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1)
+    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2)
+    PROD("Picasso IV Z2", GFX, VILLAGE_TRONIC_PICASSO_IV_Z2_REG)
+    PROD("Picasso IV Z3", GFX, VILLAGE_TRONIC_PICASSO_IV_Z3)
+    PROD("Ariadne", ETHERNET_PARALLEL, VILLAGE_TRONIC_ARIADNE)
+END
+
+BEGIN_PROD(UTILITIES_UNLIMITED)
+    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE)
+    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE2)
+END
+
+BEGIN_PROD(AMITRIX)
+    PROD(NULL, MULTIIO, AMITRIX_MULTI_IO)
+    PROD("CD-RAM", RAM, AMITRIX_CD_RAM)
+END
+
+BEGIN_PROD(ARMAX)
+    PROD("OmniBus", GFX, ARMAX_OMNIBUS)
+END
+
+BEGIN_PROD(ZEUS)
+    PROD("Spider", VIDEO, ZEUS_SPIDER)
+END
+
+BEGIN_PROD(NEWTEK)
+    PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER)
+END
+
+BEGIN_PROD(M_TECH_GERMANY)
+    PROD("AT500", IDE, MTEC_AT500_2)
+    PROD("68030", TURBO, MTEC_68030)
+    PROD("68020i", TURBO, MTEC_68020I)
+    PROD("A1200 T68030 RTC", TURBO, MTEC_A1200_T68030_RTC)
+    PROD("Viper Mk V/E-Matrix 530", TURBO_RAM, MTEC_VIPER_MK_V_E_MATRIX_530)
+    PROD("8MB", RAM, MTEC_8_MB_RAM)
+    PROD("Viper Mk V/E-Matrix 530 SCSI/IDE", SCSI_IDE, MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_4)
+    PROD("EGS 28/24 Spectrum", GFX, GVP_EGS_28_24_SPECTRUM_REG)
+    PROD("EGS 28/24 Spectrum", GFXRAM, GVP_EGS_28_24_SPECTRUM_RAM)
+END
+
+BEGIN_PROD(APOLLO_1)
+    PROD("A1200", FPU_RAM, APOLLO_A1200)
+END
+
+BEGIN_PROD(HELFRICH_2)
+    PROD("Piccolo", GFXRAM, HELFRICH_PICCOLO_RAM)
+    PROD("Piccolo", GFX, HELFRICH_PICCOLO_REG)
+    PROD("PeggyPlus MPEG", VIDEO, HELFRICH_PEGGY_PLUS_MPEG)
+    PROD("VideoCruncher", VIDEO, HELFRICH_VIDEOCRUNCHER)
+    PROD("Piccolo SD64", GFXRAM, HELFRICH_SD64_RAM)
+    PROD("Piccolo SD64", GFX, HELFRICH_SD64_REG)
+END
+
+BEGIN_PROD(MACROSYSTEMS_USA)
+    PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx)
+END
+
+BEGIN_PROD(ELBOX_COMPUTER)
+    PROD("1200/4", RAM, ELBOX_COMPUTER_1200_4)
+END
+
+BEGIN_PROD(HARMS_PROFESSIONAL)
+    PROD("030 Plus", TURBO, HARMS_PROFESSIONAL_030_PLUS)
+    PROD("3500 Professional", TURBO_RAM, HARMS_PROFESSIONAL_3500)
+END
+
+BEGIN_PROD(MICRONIK)
+    PROD("RCA 120", RAM, MICRONIK_RCA_120)
+END
+
+BEGIN_PROD(MICRONIK2)
+    PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I)
+END
+
+BEGIN_PROD(MEGAMICRO)
+    PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500)
+    PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM)
+END
+
+BEGIN_PROD(IMTRONICS_2)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_3)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_4)
+END
+
+BEGIN_PROD(INDIVIDUAL_COMPUTERS)
+    PROD("Buddha", IDE, INDIVIDUAL_COMPUTERS_BUDDHA)
+    PROD("Catweasel", IDE_FLOPPY, INDIVIDUAL_COMPUTERS_CATWEASEL)
+END
+
+BEGIN_PROD(KUPKE_3)
+    PROD("Golem HD 3000", HD, KUPKE_GOLEM_HD_3000)
+END
+
+BEGIN_PROD(ITH)
+    PROD("ISDN-Master II", ISDN, ITH_ISDN_MASTER_II)
+END
+
+BEGIN_PROD(VMC)
+    PROD("ISDN Blaster Z2", ISDN, VMC_ISDN_BLASTER_Z2)
+    PROD("HyperCom 4", MULTIIO, VMC_HYPERCOM_4)
+END
+
+BEGIN_PROD(INFORMATION)
+    PROD("ISDN Engine I", ISDN, INFORMATION_ISDN_ENGINE_I)
+END
+
+BEGIN_PROD(VORTEX)
+    PROD("Golden Gate 80386SX", BRIDGE, VORTEX_GOLDEN_GATE_80386SX)
+    PROD("Golden Gate", RAM, VORTEX_GOLDEN_GATE_RAM)
+    PROD("Golden Gate 80486", BRIDGE, VORTEX_GOLDEN_GATE_80486)
+END
+
+BEGIN_PROD(EXPANSION_SYSTEMS)
+    PROD("DataFlyer 4000SX", SCSI, EXPANSION_SYSTEMS_DATAFLYER_4000SX)
+    PROD("DataFlyer 4000SX", RAM, EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM)
+END
+
+BEGIN_PROD(READYSOFT)
+    PROD("AMax II/IV", MACEMU, READYSOFT_AMAX_II_IV)
+END
+
+BEGIN_PROD(PHASE5)
+    PROD("Blizzard", RAM, PHASE5_BLIZZARD_RAM)
+    PROD("Blizzard", TURBO, PHASE5_BLIZZARD)
+    PROD("Blizzard 1220-IV", TURBO, PHASE5_BLIZZARD_1220_IV)
+    PROD("FastLane Z3", RAM, PHASE5_FASTLANE_Z3_RAM)
+    PROD("Blizzard 1230-II/Fastlane Z3/CyberSCSI/CyberStorm060", TURBO_SCSI, PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060)
+    PROD("Blizzard 1220/CyberStorm", TURBO_SCSI, PHASE5_BLIZZARD_1220_CYBERSTORM)
+    PROD("Blizzard 1230", TURBO, PHASE5_BLIZZARD_1230)
+    PROD("Blizzard 1230-IV/1260", TURBO, PHASE5_BLIZZARD_1230_IV_1260)
+    PROD("Blizzard 2060", TURBO, PHASE5_BLIZZARD_2060)
+    PROD("CyberStorm Mk II", FLASHROM, PHASE5_CYBERSTORM_MK_II)
+    PROD("CyberVision64", GFX, PHASE5_CYBERVISION64)
+    PROD("CyberVision64-3D Prototype", GFX, PHASE5_CYBERVISION64_3D_PROTOTYPE)
+    PROD("CyberVision64-3D", GFX, PHASE5_CYBERVISION64_3D)
+    PROD("CyberStorm Mk III", TURBO_SCSI, PHASE5_CYBERSTORM_MK_III)
+    PROD("Blizzard 603e+", TURBO_SCSI, PHASE5_BLIZZARD_603E_PLUS)
+END
+
+BEGIN_PROD(DPS)
+    PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER)
+END
+
+BEGIN_PROD(APOLLO_2)
+    PROD("A620 68020", TURBO, APOLLO_A620_68020_1)
+    PROD("A620 68020", TURBO, APOLLO_A620_68020_2)
+END
+
+BEGIN_PROD(APOLLO_3)
+    PROD("AT-Apollo", UNKNOWN, APOLLO_AT_APOLLO)
+    PROD("1230/1240/1260/2030/4040/4060", TURBO, APOLLO_1230_1240_1260_2030_4040_4060)
+END
+
+BEGIN_PROD(PETSOFF_LP)
+    PROD("Delfina", AUDIO, PETSOFF_LP_DELFINA)
+    PROD("Delfina Lite", AUDIO, PETSOFF_LP_DELFINA_LITE)
+END
+
+BEGIN_PROD(UWE_GERLACH)
+    PROD("RAM/ROM", MISC, UWE_GERLACH_RAM_ROM)
+END
+
+BEGIN_PROD(ACT)
+    PROD("Prelude", AUDIO, ACT_PRELUDE)
+END
+
+BEGIN_PROD(MACROSYSTEMS_GERMANY)
+    PROD("Maestro", AUDIO, MACROSYSTEMS_MAESTRO)
+    PROD("VLab", VIDEO, MACROSYSTEMS_VLAB)
+    PROD("Maestro Pro", AUDIO, MACROSYSTEMS_MAESTRO_PRO)
+    PROD("Retina", GFX, MACROSYSTEMS_RETINA)
+    PROD("MultiEvolution", SCSI, MACROSYSTEMS_MULTI_EVOLUTION)
+    PROD("Toccata", AUDIO, MACROSYSTEMS_TOCCATA)
+    PROD("Retina Z3", GFX, MACROSYSTEMS_RETINA_Z3)
+    PROD("VLab Motion", VIDEO, MACROSYSTEMS_VLAB_MOTION)
+    PROD("Altais", GFX, MACROSYSTEMS_ALTAIS)
+    PROD("Falcon '040", TURBO, MACROSYSTEMS_FALCON_040)
+END
+
+BEGIN_PROD(COMBITEC)
+END
+
+BEGIN_PROD(SKI_PERIPHERALS)
+    PROD("MAST Fireball", SCSI, SKI_PERIPHERALS_MAST_FIREBALL)
+    PROD("SCSI/Dual Serial", SCSI_SERIAL, SKI_PERIPHERALS_SCSI_DUAL_SERIAL)
+END
+
+BEGIN_PROD(REIS_WARE_2)
+    PROD("Scan King", SCANNER, REIS_WARE_SCAN_KING)
+END
+
+BEGIN_PROD(CAMERON)
+    PROD("Personal A4", SCANNER, CAMERON_PERSONAL_A4)
+END
+
+BEGIN_PROD(REIS_WARE)
+    PROD("Handyscanner", SCANNER, REIS_WARE_HANDYSCANNER)
+END
+
+BEGIN_PROD(PHOENIX_2)
+    PROD("ST506", HD, PHOENIX_ST506_2)
+    PROD(NULL, SCSI, PHOENIX_SCSI_2)
+    PROD(NULL, RAM, PHOENIX_RAM_2)
+END
+
+BEGIN_PROD(COMBITEC_2)
+    PROD(NULL, HD, COMBITEC_HD)
+    PROD("SRAM", RAM, COMBITEC_SRAM)
+END
+
+BEGIN_PROD(HACKER)	/* Unused */
+END
+
+
+BEGIN_MANUF
+    MANUF("Pacific Peripherals", PACIFIC_PERIPHERALS)
+    MANUF("MacroSystems USA", MACROSYSTEMS_USA_2)
+    MANUF("Kupke", KUPKE_1)
+    MANUF("Memphis", MEMPHIS)
+    MANUF("3-State", 3_STATE)
+    MANUF("Commodore Braunschweig", COMMODORE_BRAUNSCHWEIG)
+    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_1)
+    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_2)
+    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
+    MANUF("Kolff Computer Supplies", KOLFF_COMPUTER_SUPPLIES)
+    MANUF("Cardco Ltd.", CARDCO_1)
+    MANUF("A-Squared", A_SQUARED)
+    MANUF("Comspec Communications", COMSPEC_COMMUNICATIONS)
+    MANUF("Anakin Research", ANAKIN_RESEARCH)
+    MANUF("Microbotics", MICROBOTICS)
+    MANUF("Access Associates Alegra", ACCESS_ASSOCIATES_ALEGRA)
+    MANUF("Expansion Technologies (Pacific Cypress)", EXPANSION_TECHNOLOGIES)
+    MANUF("ASDG", ASDG)
+    MANUF("Ronin/Imtronics", IMTRONICS_1)
+    MANUF("Commodore/University of Lowell", CBM_UNIVERSITY_OF_LOWELL)
+    MANUF("Ameristar", AMERISTAR)
+    MANUF("Supra", SUPRA)
+    MANUF("Computer Systems Assosiates", COMPUTER_SYSTEMS_ASSOCIATES)
+    MANUF("Marc Michael Groth", MARC_MICHAEL_GROTH)
+    MANUF("M-Tech", M_TECH)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_1)
+    MANUF("ByteBox", BYTEBOX)
+    MANUF("DKB/Power Computing", DKB_POWER_COMPUTING)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_2)
+    MANUF("California Access (Synergy)", CALIFORNIA_ACCESS_SYNERGY)
+    MANUF("Xetec", XETEC)
+    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
+    MANUF("Xebec", XEBEC)
+    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY)
+    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY_2)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_1)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_2)
+    MANUF("Cardco Ltd.", CARDCO_2)
+    MANUF("Jochheim", JOCHHEIM)
+    MANUF("Checkpoint Technologies", CHECKPOINT_TECHNOLOGIES)
+    MANUF("Edotronik", EDOTRONIK)
+    MANUF("NES Inc.", NES_INC)
+    MANUF("ICD", ICD)
+    MANUF("Kupke", KUPKE_2)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_3)
+    MANUF("Interworks Network", INTERWORKS_NETWORK)
+    MANUF("Hardital Synthesis", HARDITAL_SYNTHESIS)
+    MANUF("Applied Engineering", APPLIED_ENGINEERING)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_3)
+    MANUF("Phoenix", PHOENIX)
+    MANUF("Advanced Storage Systems", ADVANCED_STORAGE_SYSTEMS)
+    MANUF("Impulse", IMPULSE)
+    MANUF("IVS", IVS)
+    MANUF("Vector", VECTOR_1)
+    MANUF("XPert ProDev", XPERT_PRODEV)
+    MANUF("Hydra Systems", HYDRA_SYSTEMS)
+    MANUF("Sunrize Industries", SUNRIZE_INDUSTRIES)
+    MANUF("Triceratops", TRICERATOPS)
+    MANUF("Applied Magic Inc.", APPLIED_MAGIC)
+    MANUF("GFX-Base", GFX_BASE)
+    MANUF("RocTec", ROCTEC)
+    MANUF("Kato", KATO)
+    MANUF("Atlantis", ATLANTIS)
+    MANUF("Protar", PROTAR)
+    MANUF("ACS", ACS)
+    MANUF("Software Results Enterprises", SOFTWARE_RESULTS_ENTERPRISES)
+    MANUF("Masoboshi", MASOBOSHI)
+    MANUF("Mainhattan-Data (A-Team)", MAINHATTAN_DATA)
+    MANUF("Village Tronic", VILLAGE_TRONIC)
+    MANUF("Utilities Unlimited", UTILITIES_UNLIMITED)
+    MANUF("Amitrix", AMITRIX)
+    MANUF("ArMax", ARMAX)
+    MANUF("ZEUS Electronic Development", ZEUS)
+    MANUF("NewTek", NEWTEK)
+    MANUF("M-Tech Germany", M_TECH_GERMANY)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_4)
+    MANUF("Apollo", APOLLO_1)
+    MANUF("Ingenieurbüro Helfrich", HELFRICH_2)
+    MANUF("MacroSystems USA", MACROSYSTEMS_USA)
+    MANUF("ElBox Computer", ELBOX_COMPUTER)
+    MANUF("Harms Professional", HARMS_PROFESSIONAL)
+    MANUF("Micronik", MICRONIK)
+    MANUF("Micronik", MICRONIK2)
+    MANUF("MegaMicro", MEGAMICRO)
+    MANUF("Ronin/Imtronics", IMTRONICS_2)
+    MANUF("Individual Computers", INDIVIDUAL_COMPUTERS)
+    MANUF("Kupke", KUPKE_3)
+    MANUF("ITH", ITH)
+    MANUF("VMC", VMC)
+    MANUF("Information", INFORMATION)
+    MANUF("Vortex", VORTEX)
+    MANUF("Expansion Systems", EXPANSION_SYSTEMS)
+    MANUF("ReadySoft", READYSOFT)
+    MANUF("Phase 5", PHASE5)
+    MANUF("DPS", DPS)
+    MANUF("Apollo", APOLLO_2)
+    MANUF("Apollo", APOLLO_3)
+    MANUF("Petsoff LP", PETSOFF_LP)
+    MANUF("Uwe Gerlach", UWE_GERLACH)
+    MANUF("ACT", ACT)
+    MANUF("MacroSystems Germany", MACROSYSTEMS_GERMANY)
+    MANUF("Combitec", COMBITEC)
+    MANUF("SKI Peripherals", SKI_PERIPHERALS)
+    MANUF("Reis-Ware", REIS_WARE_2)
+    MANUF("Cameron", CAMERON)
+    MANUF("Reis-Ware", REIS_WARE)
+    MANUF("Hacker Test Board", HACKER)	/* Unused */
+    MANUF("Phoenix", PHOENIX_2)
+    MANUF("Combitec", COMBITEC_2)
+END
+
+#define NUM_MANUF		(ARRAYSIZE(Manufacturers))
+#define NUM_GVP_PROD		(ARRAYSIZE(Ext_Prod_GVP))
+
+
+    /*
+     *  Zorro product classes
+     *
+     *  Make sure to keep these in sync with include/linux/zorro.h!
+     */
+
+static const char *classnames[] = {
+    NULL,				    /* ZORRO_CLASS_UNKNOWN */
+    "ArcNet Card",			    /* ZORRO_CLASS_ARCNET */
+    "Audio Board",			    /* ZORRO_CLASS_AUDIO */
+    "ISA Bus Bridge",			    /* ZORRO_CLASS_BRIDGE */
+    "DSP Board",			    /* ZORRO_CLASS_DSP */
+    "Ethernet Card",			    /* ZORRO_CLASS_ETHERNET */
+    "Ethernet Card and Parallel Ports",	    /* ZORRO_CLASS_ETHERNET_PARALLEL */
+    "Flash ROM",			    /* ZORRO_CLASS_FLASHROM */
+    "FPU and RAM Expansion",		    /* ZORRO_CLASS_FPU_RAM */
+    "Graphics Board",			    /* ZORRO_CLASS_GFX */
+    "Graphics Board (RAM)",		    /* ZORRO_CLASS_GFXRAM */
+    "HD Controller",			    /* ZORRO_CLASS_HD */
+    "HD Controller and RAM Expansion",	    /* ZORRO_CLASS_HD_RAM */
+    "IDE Interface",			    /* ZORRO_CLASS_IDE */
+    "IDE Interface and RAM Expansion",	    /* ZORRO_CLASS_IDE_RAM */
+    "IDE Interface and Floppy Controller",  /* ZORRO_CLASS_IDE_FLOPPY */
+    "ISDN Interface",			    /* ZORRO_CLASS_ISDN */
+    "Macintosh Emulator",		    /* ZORRO_CLASS_MACEMU */
+    "Miscellaneous Expansion Card",	    /* ZORRO_CLASS_MISC */
+    "Modem",				    /* ZORRO_CLASS_MODEM */
+    "Multi I/O",			    /* ZORRO_CLASS_MULTIIO */
+    "RAM Expansion",			    /* ZORRO_CLASS_RAM */
+    "Scanner Interface",		    /* ZORRO_CLASS_SCANNER */
+    "SCSI Host Adapter",		    /* ZORRO_CLASS_SCSI */
+    "SCSI Host Adapter and IDE Interface",  /* ZORRO_CLASS_SCSI_IDE */
+    "SCSI Host Adapter and RAM Expansion",  /* ZORRO_CLASS_SCSI_RAM */
+    "SCSI Host Adapter and Serial Card",    /* ZORRO_CLASS_SCSI_SERIAL */
+    "Multi Serial",			    /* ZORRO_CLASS_SERIAL */
+    "Drawing Tablet Interface",		    /* ZORRO_CLASS_TABLET */
+    "Accelerator",			    /* ZORRO_CLASS_TURBO */
+    "Accelerator and RAM Expansion",	    /* ZORRO_CLASS_TURBO_RAM */
+    "Accelerator and HD Controller",	    /* ZORRO_CLASS_TURBO_HD */
+    "Accelerator and IDE Interface",	    /* ZORRO_CLASS_TURBO_IDE */
+    "Accelerator and SCSI Host Adapter",    /* ZORRO_CLASS_TURBO_SCSI */
+    "Accelerator, SCSI Host Adapter and RAM Expansion",    /* ZORRO_CLASS_TURBO_SCSI */
+    "Video Board",			    /* ZORRO_CLASS_VIDEO */
+};
+
+static inline const char *get_class_name(enum Zorro_Classes class)
+{
+    if (class < ARRAYSIZE(classnames))
+	return(classnames[class]);
+    else
+	return("(**Illegal**)");
+}
+
+#endif /* CONFIG_ZORRO */
+
+
+    /*
+     *  Expansion Devices
+     */
+
+u_int zorro_num_autocon;
+struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
+static u32 BoardPartFlags[ZORRO_NUM_AUTO] = { 0, };
+
+   
+    /*
+     *  Find the key for the next unconfigured expansion device of a specific
+     *  type.
+     *
+     *  Part is a device specific number (0 <= part <= 31) to allow for the
+     *  independent configuration of independent parts of an expansion board.
+     *  Thanks to Jes Soerensen for this idea!
+     *
+     *  Index is used to specify the first board in the autocon list
+     *  to be tested. It was inserted in order to solve the problem
+     *  with the GVP boards that uses the same product code, but
+     *  it should help if there are other companies which use the same
+     *  method as GVP. Drivers for boards which are not using this
+     *  method do not need to think of this - just set index = 0.
+     *
+     *  Example:
+     *
+     *      while ((key = zorro_find(ZORRO_PROD_MY_BOARD, MY_PART, 0))) {
+     *      	cd = zorro_get_board(key);
+     *      	initialise_this_board;
+     *      	zorro_config_board(key, MY_PART);
+     *      }
+     */
+
+u_int zorro_find(zorro_id id, u_int part, u_int index)
+{
+    u_int manuf = ZORRO_MANUF(id);
+    u_int prod = ZORRO_PROD(id);
+    u_int epc = ZORRO_EPC(id);
+    u_int key;
+    const struct ConfigDev *cd;
+    u_long addr;
+
+    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
+	return(0);
+
+    if (part > 31) {
+	printk("zorro_find: bad part %d\n", part);
+	return(0);
+    }
+
+    for (key = index + 1; key <= zorro_num_autocon; key++) {
+	cd = &zorro_autocon[key-1];
+	addr = (u_long)cd->cd_BoardAddr;
+	if ((cd->cd_Rom.er_Manufacturer == manuf) &&
+	    (cd->cd_Rom.er_Product == prod) &&
+	    !(BoardPartFlags[key-1] & (1<<part)) &&
+	    (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
+	     prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE) ||
+	     (*(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK) == epc))
+	    break;
+    }
+    return(key <= zorro_num_autocon ? key : 0);
+}
+
+
+    /*
+     *  Get the board corresponding to a specific key
+     */
+
+const struct ConfigDev *zorro_get_board(u_int key)
+{
+    const struct ConfigDev *cd = NULL;
+
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_get_board: bad key %d\n", key);
+    else
+	cd = &zorro_autocon[key-1];
+
+    return(cd);
+}
+
+
+    /*
+     *  Mark a part of a board as configured
+     */
+
+void zorro_config_board(u_int key, u_int part)
+{
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_config_board: bad key %d\n", key);
+    else if (part > 31)
+	printk("zorro_config_board: bad part %d\n", part);
+    else if (BoardPartFlags[key-1] & (1<<part))
+	printk("zorro_config_board: key %d part %d is already configured\n",
+	       key, part);
+    else
+	BoardPartFlags[key-1] |= 1<<part;
+}
+
+
+    /*
+     *  Mark a part of a board as unconfigured
+     *
+     *  This function is mainly intended for the unloading of LKMs
+     */
+
+void zorro_unconfig_board(u_int key, u_int part)
+{
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_unconfig_board: bad key %d\n", key);
+    else if (part > 31)
+	printk("zorro_unconfig_board: bad part %d\n", part);
+    else if (!(BoardPartFlags[key-1] & (1<<part)))
+	printk("zorro_config_board: key %d part %d is not yet configured\n",
+	       key, part);
+    else
+	BoardPartFlags[key-1] &= ~(1<<part);
+}
+
+
+#ifdef CONFIG_ZORRO
+
+    /*
+     *  Identify an AutoConfig Expansion Device
+     *
+     *  If the board was configured by a Linux/m68k driver, an asterisk will
+     *  be printed before the board address (except for unknown and `Hacker
+     *  Test' boards).
+     */
+
+static int identify(u_int devnum, char *buf, int verbose)
+{
+    const struct ConfigDev *cd = &zorro_autocon[devnum];
+    u32 configured = BoardPartFlags[devnum];
+    u_int manuf = cd->cd_Rom.er_Manufacturer;
+    u_int prod = cd->cd_Rom.er_Product;
+    u_int class = ZORRO_CLASS_UNKNOWN;
+    u_int epc = 0;
+    const char *manufname = "Unknown";
+    const char *prodname = "Unknown";
+    const char *classname;
+    u_int i, j, k, len = 0;
+    u_long addr = (u_long)cd->cd_BoardAddr;
+    u_long size = cd->cd_BoardSize;
+    char mag;
+    int identified = 0, gvp = 0;
+
+    if (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
+	prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) {
+	for (i = 0; i < NUM_MANUF; i++)
+	    if (Manufacturers[i].Manuf == manuf) {
+		manufname = Manufacturers[i].Name;
+		for (j = 0; j < Manufacturers[i].NumProd; j++)
+		    if (Manufacturers[i].Products[j].Prod == prod) {
+			prodname = Manufacturers[i].Products[j].Name;
+			class = Manufacturers[i].Products[j].Class;
+			identified = 1;
+			break;
+		    }
+	    }
+	/* Put workarounds for ID clashes here */
+	if (manuf == ZORRO_MANUF(ZORRO_PROD_HELFRICH_RAINBOW_III) &&
+	    prod == ZORRO_PROD(ZORRO_PROD_HELFRICH_RAINBOW_III))
+	    manufname = "Ingenieurbüro Helfrich";
+    } else {
+	manufname = "Great Valley Products";
+	gvp = 1;
+	epc = *(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK;
+	for (k = 0; k < NUM_GVP_PROD; k++)
+	    if (epc == Ext_Prod_GVP[k].EPC) {
+		prodname = Ext_Prod_GVP[k].Name;
+		class = Ext_Prod_GVP[k].Class;
+		identified = 1;
+		break;
+	    }
+    }
+    classname = get_class_name(class);
+    if (size & 0xfffff) {
+	size >>= 10;
+	mag = 'K';
+    } else {
+	size >>= 20;
+	mag = 'M';
+    }
+    if (verbose) {
+	const char *zorro;
+	int is_mem = cd->cd_Rom.er_Type & ERTF_MEMLIST;
+	switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) {
+	    case ERT_ZORROII:
+		zorro = "Zorro II";
+		break;
+	    case ERT_ZORROIII:
+		zorro = "Zorro III";
+		break;
+	    default:
+		zorro = "Unknown Zorro";
+		break;
+	}
+	if (!prodname)
+	    prodname = "Unknown";
+	if (!classname)
+	    classname = "Unknown";
+	len = sprintf(buf, "  Device %d at 0x%08lx: ID=%04x:%02x", devnum,
+		      addr, manuf, prod);
+	if (gvp)
+	    len += sprintf(buf+len, ":%02x", epc);
+	len += sprintf(buf+len, ", %s, %ld%c", zorro, size, mag);
+	if (is_mem)
+	    len += sprintf(buf+len, ", System RAM");
+	else
+	    len += sprintf(buf+len, ", Configured=%08x", configured);
+	len += sprintf(buf+len, "\n"
+				"    Manufacturer: %s\n"
+				"    Product Name: %s\n"
+				"    Board Class : %s\n",
+				manufname, prodname, classname);
+    } else {
+	len = sprintf(buf, " %c%08lx: ", configured ? '*' : ' ', addr);
+	if (identified) {
+	    len += sprintf(buf+len, "%s", manufname);
+	    if (prodname)
+		len += sprintf(buf+len, " %s", prodname);
+	    if (classname)
+		len += sprintf(buf+len, " %s", classname);
+	} else if (manuf == ZORRO_MANUF_HACKER)
+	    len += sprintf(buf+len, "Hacker Test Board %02x", prod);
+	else if (gvp)
+	    len += sprintf(buf+len, "[%04x:%02x:%02x] made by %s", manuf, prod,
+			   epc, manufname);
+	else
+	    len += sprintf(buf+len, "[%04x:%02x] made by %s", manuf, prod,
+			   manufname);
+	len += sprintf(buf+len, " (%ld%c)\n", size, mag);
+	if (!identified && manuf != ZORRO_MANUF_HACKER)
+	    len += sprintf(buf+len, "    Please report this unknown device to "
+				    "zorro@linux-m68k.org\n");
+    }
+    return(len);
+}
+
+
+    /*
+     *  Identify all known AutoConfig Expansion Devices
+     */
+
+void zorro_identify(void)
+{
+    u_int i;
+    char tmp[256];
+
+    if (!AMIGAHW_PRESENT(ZORRO))
+	return;
+
+    printk("Probing AutoConfig expansion device(s):\n");
+    for (i = 0; i < zorro_num_autocon; i++) {
+	identify(i, tmp, 0);
+	printk(tmp);
+    }
+    if (!zorro_num_autocon)
+	printk("No AutoConfig expansion devices present.\n");
+}
+
+
+    /*
+     *  Get the list of all AutoConfig Expansion Devices
+     */
+
+int zorro_get_list(char *buffer)
+{
+    u_int i, len = 0, len2;
+    char tmp[256];
+
+    if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
+	len = sprintf(buffer, "AutoConfig expansion devices:\n");
+	for (i = 0; i < zorro_num_autocon; i++) {
+	    len2 = identify(i, tmp, 1);
+	    if (len+len2 >= 4075) {
+		len += sprintf(buffer+len, "4K limit reached!\n");
+		break;
+	    }
+	    strcpy(buffer+len, tmp);
+	    len += len2;
+	}
+    }
+    return(len);
+}
+
+#endif /* CONFIG_ZORRO */
+
+
+    /*
+     *  Bitmask indicating portions of available Zorro II RAM that are unused
+     *  by the system. Every bit represents a 64K chunk, for a maximum of 8MB
+     *  (128 chunks, physical 0x00200000-0x009fffff).
+     *
+     *  If you want to use (= allocate) portions of this RAM, you should clear
+     *  the corresponding bits.
+     *
+     *  Possible uses:
+     *      - z2ram device
+     *      - SCSI DMA bounce buffers
+     */
+
+u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 };
+
+
+static void mark_region(u_long addr, u_long size, int flag)
+{
+    u_long start, end, chunk;
+
+    if (flag) {
+	start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
+	end = (addr+size) & ~Z2RAM_CHUNKMASK;
+    } else {
+	start = addr & ~Z2RAM_CHUNKMASK;
+	end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
+    }
+    if (end <= Z2RAM_START || start >= Z2RAM_END)
+	return;
+    start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
+    end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
+    while (start < end) {
+	chunk = start>>Z2RAM_CHUNKSHIFT;
+	if (flag)
+	    set_bit( chunk, zorro_unused_z2ram );
+	else
+	    clear_bit( chunk, zorro_unused_z2ram );
+	start += Z2RAM_CHUNKSIZE;
+    }
+}
+
+
+    /*
+     *  Initialization
+     */
+
+void zorro_init(void)
+{
+    u_int i;
+    const struct ConfigDev *cd;
+
+    if (!AMIGAHW_PRESENT(ZORRO))
+	return;
+
+    /* Mark all available Zorro II memory */
+    for (i = 0; i < zorro_num_autocon; i++) {
+	cd = &zorro_autocon[i];
+	if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
+	    mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1);
+    }
+
+    /* Unmark all used Zorro II memory */
+    for (i = 0; i < m68k_num_memory; i++)
+	mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0);
+}
diff -u --recursive --new-file v2.1.105/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.105/linux/fs/binfmt_aout.c	Thu Apr 23 20:21:35 1998
+++ linux/fs/binfmt_aout.c	Sat Jun 13 12:10:31 1998
@@ -129,7 +129,7 @@
 	if (get_write_access(inode))
 		goto end_coredump;
 	if (init_private_file(&file, dentry, 3))
-		goto end_coredump;
+		goto end_coredump_write;
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
@@ -213,6 +213,7 @@
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
+end_coredump_write:
 	put_write_access(inode);
 end_coredump:
 	set_fs(fs);
diff -u --recursive --new-file v2.1.105/linux/fs/devpts/inode.c linux/fs/devpts/inode.c
--- v2.1.105/linux/fs/devpts/inode.c	Mon Apr  6 17:41:00 1998
+++ linux/fs/devpts/inode.c	Sat Jun 13 13:25:12 1998
@@ -28,15 +28,6 @@
 
 static struct super_block *mounts = NULL;
 
-static void devpts_put_inode(struct inode *inode)
-{
-}
-
-static void devpts_delete_inode(struct inode *inode)
-{
-	inode->i_size = 0;
-}
-
 static void devpts_put_super(struct super_block *sb)
 {
 	struct devpts_sb_info *sbi = SBI(sb);
@@ -48,6 +39,7 @@
 			if ( inode->i_count != 1 )
 				printk("devpts_put_super: badness: entry %d count %d\n",
 				       i, inode->i_count);
+			inode->i_nlink--;
 			iput(inode);
 		}
 	}
@@ -70,8 +62,8 @@
 static struct super_operations devpts_sops = {
 	devpts_read_inode,
 	devpts_write_inode,
-	devpts_put_inode,
-	devpts_delete_inode,
+	NULL,			/* put_inode */
+	NULL,			/* delete_inode */
 	NULL,			/* notify_change */
 	devpts_put_super,
 	NULL,			/* write_super */
@@ -281,8 +273,6 @@
 	if ( ino >= NR_PTYS )
 		return;		/* Bogus */
 	
-	inode->i_nlink = 1;
-
 	inode->i_mode = S_IFCHR;
 	inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */
 
@@ -322,6 +312,7 @@
 			inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
 			inode->i_mode = sbi->mode | S_IFCHR;
 			inode->i_rdev = device;
+			inode->i_nlink++;
 			sbi->inodes[number] = inode;
 		}
 	}
@@ -340,7 +331,7 @@
 
 		if ( inode ) {
 			sbi->inodes[number] = NULL;
-			inode->i_nlink = 0; /* Is this right? */
+			inode->i_nlink--;
 			iput(inode);
 		}
 	}
diff -u --recursive --new-file v2.1.105/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.105/linux/fs/filesystems.c	Thu May 14 19:47:43 1998
+++ linux/fs/filesystems.c	Sat Jun 13 13:33:24 1998
@@ -144,6 +144,10 @@
 	init_adfs_fs();
 #endif
 
+#ifdef CONFIG_ADFS_FS
+	init_adfs_fs();
+#endif
+
 #ifdef CONFIG_DEVPTS_FS
 	init_devpts_fs();
 #endif
diff -u --recursive --new-file v2.1.105/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.105/linux/fs/isofs/dir.c	Tue Mar 10 10:03:34 1998
+++ linux/fs/isofs/dir.c	Sat Jun 13 13:39:15 1998
@@ -91,6 +91,32 @@
 	return i;
 }
 
+/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
+int get_acorn_filename(struct iso_directory_record * de,
+			    char * retname, struct inode * inode)
+{
+	int std;
+	unsigned char * chr;
+	int retnamlen = isofs_name_translate(de->name,
+				de->name_len[0], retname);
+	if (retnamlen == 0) return 0;
+	std = sizeof(struct iso_directory_record) + de->name_len[0];
+	if (std & 1) std++;
+	if ((*((unsigned char *) de) - std) != 32) return retnamlen;
+	chr = ((unsigned char *) de) + std;
+	if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
+	if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
+	if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
+		&& ((chr[12] & 0xf0) == 0xf0))
+	{
+		retname[retnamlen] = ',';
+		sprintf(retname+retnamlen+1, "%3.3x",
+			((chr[12] & 0xf) << 8) | chr[11]);
+		retnamlen += 4;
+	}
+	return retnamlen;
+}
+
 /*
  * This should _really_ be cleaned up some day..
  */
@@ -230,15 +256,17 @@
 				p = tmpname;
 			} else
 #endif
-			{
-				if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
-					len = isofs_name_translate(de->name, de->name_len[0],
-								   tmpname);
-					p = tmpname;
-				} else {
-					p = de->name;
-					len = de->name_len[0];
-				}
+			if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
+				len = get_acorn_filename(de, tmpname, inode);
+				p = tmpname;
+			} else
+			if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+				len = isofs_name_translate(de->name,
+					de->name_len[0], tmpname);
+				p = tmpname;
+			} else {
+				p = de->name;
+				len = de->name_len[0];
 			}
 		}
 		if (len > 0) {
diff -u --recursive --new-file v2.1.105/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.105/linux/fs/isofs/inode.c	Thu May 14 19:47:43 1998
+++ linux/fs/isofs/inode.c	Sat Jun 13 13:39:16 1998
@@ -90,7 +90,7 @@
 {
 	char *this_char,*value;
 
-	popt->map = 'n';
+	popt->map = 'a';
 	popt->rock = 'y';
 	popt->joliet = 'y';
 	popt->cruft = 'n';
@@ -141,10 +141,11 @@
 		} else
 #endif
 		if (!strcmp(this_char,"map") && value) {
-			if (value[0] && !value[1] && strchr("on",*value))
+			if (value[0] && !value[1] && strchr("ano",*value))
 				popt->map = *value;
 			else if (!strcmp(value,"off")) popt->map = 'o';
 			else if (!strcmp(value,"normal")) popt->map = 'n';
+			else if (!strcmp(value,"acorn")) popt->map = 'a';
 			else return 0;
 		}
 		else if (!strcmp(this_char,"check") && value) {
diff -u --recursive --new-file v2.1.105/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.1.105/linux/fs/isofs/namei.c	Wed Dec  3 04:24:29 1997
+++ linux/fs/isofs/namei.c	Sat Jun 13 13:39:16 1998
@@ -178,6 +178,9 @@
 			dlen = get_joliet_filename(de, dir, page);
 			dpnt = page;
 #endif
+		} else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') {
+			dlen = get_acorn_filename(de, page, dir);
+			dpnt = page;
 		} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
 			for (i = 0; i < dlen; i++) {
 				c = dpnt[i];
diff -u --recursive --new-file v2.1.105/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.1.105/linux/fs/minix/bitmap.c	Fri Dec 19 15:55:45 1997
+++ linux/fs/minix/bitmap.c	Sat Jun 13 13:25:12 1998
@@ -36,16 +36,17 @@
 
 	if (numblocks==0 || !(bh=map[numblocks-1]))
 		return(0);
-	i = (numbits-(numblocks-1)*BLOCK_SIZE*8)/8;
+	i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
 	for (j=0; j<i; j++) {
 		sum += nibblemap[bh->b_data[j] & 0xf]
 			+ nibblemap[(bh->b_data[j]>>4) & 0xf];
 	}
 
-	i = numbits%8;
+	i = numbits%16;
 	if (i!=0) {
-		i = bh->b_data[j] | ~((1<<i) - 1);
+		i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
 		sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
+		sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
 	}
 	return(sum);
 }
@@ -71,11 +72,11 @@
 	zone = block - sb->u.minix_sb.s_firstdatazone + 1;
 	bit = zone & 8191;
 	zone >>= 13;
-	bh = sb->u.minix_sb.s_zmap[zone];
-	if (!bh) {
+	if (zone >= sb->u.minix_sb.s_zmap_blocks) {
 		printk("minix_free_block: nonexistent bitmap buffer\n");
 		return;
 	}
+	bh = sb->u.minix_sb.s_zmap[zone];
 	if (!minix_clear_bit(bit,bh->b_data))
 		printk("free_block (%s:%d): bit already cleared\n",
 		       kdevname(sb->s_dev), block);
@@ -94,11 +95,13 @@
 	}
 repeat:
 	j = 8192;
-	for (i=0 ; i<64 ; i++)
-		if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
-			if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
-				break;
-	if (i>=64 || !bh || j>=8192)
+	bh = NULL;
+	for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
+		bh = sb->u.minix_sb.s_zmap[i];
+		if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+			break;
+	}
+	if (!bh || j >= 8192)
 		return 0;
 	if (minix_set_bit(j,bh->b_data)) {
 		printk("new_block: bit already set");
@@ -134,7 +137,7 @@
 	int ino, block;
 
 	ino = inode->i_ino;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s: %d is out of range\n",
 		       kdevname(inode->i_dev), ino);
 		return 0;
@@ -162,7 +165,7 @@
 	int ino, block;
 
 	ino = inode->i_ino;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s: %d is out of range\n",
 		       kdevname(inode->i_dev), ino);
 		return 0;
@@ -218,15 +221,16 @@
 		printk("free_inode: inode on nonexistent device\n");
 		return;
 	}
-	if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("free_inode: inode 0 or nonexistent inode\n");
 		return;
 	}
 	ino = inode->i_ino;
-	if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
+	if ((ino >> 13) >= inode->i_sb->u.minix_sb.s_imap_blocks) {
 		printk("free_inode: nonexistent imap in superblock\n");
 		return;
 	}
+	bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
 	minix_clear_inode(inode);
 	clear_inode(inode);
 	if (!minix_clear_bit(ino & 8191, bh->b_data))
@@ -247,10 +251,12 @@
 	inode->i_sb = sb;
 	inode->i_flags = inode->i_sb->s_flags;
 	j = 8192;
-	for (i=0 ; i<8 ; i++)
-		if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
-			if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
-				break;
+	bh = NULL;
+	for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) {
+		bh = inode->i_sb->u.minix_sb.s_imap[i];
+		if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+			break;
+	}
 	if (!bh || j >= 8192) {
 		iput(inode);
 		return NULL;
@@ -262,7 +268,7 @@
 	}
 	mark_buffer_dirty(bh, 1);
 	j += i*8192;
-	if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
 		iput(inode);
 		return NULL;
 	}
diff -u --recursive --new-file v2.1.105/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.1.105/linux/fs/minix/inode.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/minix/inode.c	Sat Jun 13 13:25:12 1998
@@ -63,9 +63,9 @@
 		sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
 		mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
 	}
-	for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
+	for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++)
 		brelse(sb->u.minix_sb.s_imap[i]);
-	for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
+	for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++)
 		brelse(sb->u.minix_sb.s_zmap[i]);
 	brelse (sb->u.minix_sb.s_sbh);
 	kfree(sb->u.minix_sb.s_imap);
@@ -173,7 +173,8 @@
 	const char * errmsg;
 	struct inode *root_inode;
 	
-	/* N.B. These should be compile-time tests */
+	/* N.B. These should be compile-time tests.
+	   Unfortunately that is impossible. */
 	if (32 != sizeof (struct minix_inode))
 		panic("bad V1 i-node size");
 	if (64 != sizeof(struct minix2_inode))
@@ -203,33 +204,37 @@
 		s->u.minix_sb.s_version = MINIX_V1;
 		s->u.minix_sb.s_dirsize = 16;
 		s->u.minix_sb.s_namelen = 14;
+		s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
 	} else if (s->s_magic == MINIX_SUPER_MAGIC2) {
 		s->u.minix_sb.s_version = MINIX_V1;
 		s->u.minix_sb.s_dirsize = 32;
 		s->u.minix_sb.s_namelen = 30;
+		s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
 	} else if (s->s_magic == MINIX2_SUPER_MAGIC) {
 		s->u.minix_sb.s_version = MINIX_V2;
+		s->u.minix_sb.s_nzones = ms->s_zones;
 		s->u.minix_sb.s_dirsize = 16;
 		s->u.minix_sb.s_namelen = 14;
+		s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
 	} else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
 		s->u.minix_sb.s_version = MINIX_V2;
+		s->u.minix_sb.s_nzones = ms->s_zones;
 		s->u.minix_sb.s_dirsize = 32;
 		s->u.minix_sb.s_namelen = 30;
+		s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
 	} else
 		goto out_no_fs;
 
-	if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS)
-		goto out_too_big;
 	/*
 	 * Allocate the buffer map to keep the superblock small.
 	 */
-	i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh);
+	i = (s->u.minix_sb.s_imap_blocks + s->u.minix_sb.s_zmap_blocks) * sizeof(bh);
 	map = kmalloc(i, GFP_KERNEL);
 	if (!map)
 		goto out_no_map;
 	memset(map, 0, i);
 	s->u.minix_sb.s_imap = &map[0];
-	s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS];
+	s->u.minix_sb.s_zmap = &map[s->u.minix_sb.s_imap_blocks];
 
 	block=2;
 	for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) {
@@ -242,8 +247,6 @@
 			goto out_no_bitmap;
 		block++;
 	}
-	if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks)
-		goto out_no_bitmap;
 
 	minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
 	minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
@@ -263,6 +266,8 @@
 	if (!s->s_root)
 		goto out_iput;
 
+	s->s_root->d_op = &minix_dentry_operations;
+
 	if (!(s->s_flags & MS_RDONLY)) {
 		ms->s_state &= ~MINIX_VALID_FS;
 		mark_buffer_dirty(bh, 1);
@@ -292,9 +297,9 @@
 out_no_bitmap:
 	printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
     out_freemap:
-	for(i=0;i<MINIX_I_MAP_SLOTS;i++)
+	for (i = 0; i < s->u.minix_sb.s_imap_blocks; i++)
 		brelse(s->u.minix_sb.s_imap[i]);
-	for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
+	for (i = 0; i < s->u.minix_sb.s_zmap_blocks; i++)
 		brelse(s->u.minix_sb.s_zmap[i]);
 	kfree(s->u.minix_sb.s_imap);
 	goto out_release;
@@ -304,11 +309,6 @@
 		printk ("MINIX-fs: can't allocate map\n");
 	goto out_release;
 
-out_too_big:
-	if (!silent)
-		printk ("MINIX-fs: filesystem too big\n");
-	goto out_release;
-
 out_no_fs:
 	if (!silent)
 		printk("VFS: Can't find a minix or minix V2 filesystem on dev "
@@ -729,7 +729,7 @@
 	ino = inode->i_ino;
 	inode->i_op = NULL;
 	inode->i_mode = 0;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
@@ -783,7 +783,7 @@
 	ino = inode->i_ino;
 	inode->i_op = NULL;
 	inode->i_mode = 0;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
@@ -848,7 +848,7 @@
 	int ino, block;
 
 	ino = inode->i_ino;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
@@ -886,7 +886,7 @@
 	int ino, block;
 
 	ino = inode->i_ino;
-	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
diff -u --recursive --new-file v2.1.105/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.1.105/linux/fs/minix/namei.c	Thu May  7 22:51:53 1998
+++ linux/fs/minix/namei.c	Sat Jun 13 13:25:12 1998
@@ -23,34 +23,12 @@
 static inline int namecompare(int len, int maxlen,
 	const char * name, const char * buffer)
 {
-	if (len > maxlen)
-		return 0;
 	if (len < maxlen && buffer[len])
 		return 0;
 	return !memcmp(name, buffer, len);
 }
 
 /*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use minix_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
- */
-static int minix_match(int len, const char * name,
-	struct buffer_head * bh, unsigned long * offset,
-	struct minix_sb_info * info)
-{
-	struct minix_dir_entry * de;
-
-	de = (struct minix_dir_entry *) (bh->b_data + *offset);
-	*offset += info->s_dirsize;
-	if (!de->inode || len > info->s_namelen)
-		return 0;
-	return namecompare(len,info->s_namelen,name,de->name);
-}
-
-/*
  *	minix_find_entry()
  *
  * finds an entry in the specified directory with the wanted name. It
@@ -64,6 +42,7 @@
 	unsigned long block, offset;
 	struct buffer_head * bh;
 	struct minix_sb_info * info;
+	struct minix_dir_entry *de;
 
 	*res_dir = NULL;
 	if (!dir || !dir->i_sb)
@@ -86,9 +65,12 @@
 				continue;
 			}
 		}
-		*res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
-		if (minix_match(namelen,name,bh,&offset,info))
+		de = (struct minix_dir_entry *) (bh->b_data + offset);
+		offset += info->s_dirsize;
+		if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
+			*res_dir = de;
 			return bh;
+		}
 		if (offset < bh->b_size)
 			continue;
 		brelse(bh);
@@ -97,16 +79,52 @@
 		block++;
 	}
 	brelse(bh);
-	*res_dir = NULL;
 	return NULL;
 }
 
+#ifndef NO_TRUNCATE
+
+static int minix_hash(struct dentry *dentry, struct qstr *qstr)
+{
+	unsigned long hash;
+	int i;
+	const char *name;
+
+	i = dentry->d_inode->i_sb->u.minix_sb.s_namelen;
+	if (i >= qstr->len)
+		return 0;
+	/* Truncate the name in place, avoids having to define a compare
+	   function. */
+	qstr->len = i;
+	name = qstr->name;
+	hash = init_name_hash();
+	while (i--)
+		hash = partial_name_hash(*name++, hash);
+	qstr->hash = end_name_hash(hash);
+	return 0;
+}
+
+#endif
+
+struct dentry_operations minix_dentry_operations = {
+	0,		/* revalidate */
+#ifndef NO_TRUNCATE
+	minix_hash,
+#else
+	0,
+#endif
+	0		/* compare */
+};
+
 int minix_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode = NULL;
 	struct minix_dir_entry * de;
 	struct buffer_head * bh;
 
+#ifndef NO_TRUNCATE
+	dentry->d_op = &minix_dentry_operations;
+#endif
 	bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
 	if (bh) {
 		int ino = de->inode;
@@ -296,7 +314,7 @@
 		brelse(bh);
 		return -EEXIST;
 	}
-	if (dir->i_nlink >= MINIX_LINK_MAX)
+	if (dir->i_nlink >= info->s_link_max)
 		return -EMLINK;
 	inode = minix_new_inode(dir);
 	if (!inode)
@@ -434,7 +452,7 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (inode->i_count > 1) {
+	if (dentry->d_count > 1) {
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
@@ -573,7 +591,7 @@
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
-	if (inode->i_nlink >= MINIX_LINK_MAX)
+	if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
 		return -EMLINK;
 
 	bh = minix_find_entry(dir, dentry->d_name.name,
@@ -689,7 +707,7 @@
 		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
+		if (!new_inode && new_dir->i_nlink >= info->s_link_max)
 			goto end_rename;
 	}
 	if (!new_bh) {
diff -u --recursive --new-file v2.1.105/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.1.105/linux/fs/nfsd/nfsproc.c	Fri Jan 30 11:28:08 1998
+++ linux/fs/nfsd/nfsproc.c	Sat Jun 13 09:58:14 1998
@@ -180,10 +180,8 @@
 
 /*
  * CREATE processing is complicated. The keyword here is `overloaded.'
- * There's a small race condition here between the check for existence
- * and the actual create() call, but one could even consider this a
- * feature because this only happens if someone else creates the file
- * at the same time.
+ * The parent directory is kept locked between the check for existence
+ * and the actual create() call in compliance with VFS protocols.
  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
  */
 static int
@@ -193,15 +191,14 @@
 	svc_fh		*dirfhp = &argp->fh;
 	svc_fh		*newfhp = &resp->fh;
 	struct iattr	*attr = &argp->attrs;
-	struct inode	*inode = NULL;
-	int		nfserr, type, mode;
-	int		rdonly = 0, exists;
+	struct inode	*inode;
+	int		nfserr, type, mode, rdonly = 0;
 	dev_t		rdev = NODEV;
 
 	dprintk("nfsd: CREATE   %d/%ld %s\n",
 		SVCFH_DEV(dirfhp), SVCFH_INO(dirfhp), argp->name);
 
-	/* Get the directory inode */
+	/* First verify the parent filehandle */
 	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
 	if (nfserr)
 		goto done; /* must fh_put dirfhp even on error */
@@ -214,18 +211,32 @@
 	} else if (nfserr)
 		goto done;
 
-	/* First, check if the file already exists.  */
-	exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
-
-	if (newfhp->fh_dverified)
-		inode = newfhp->fh_dentry->d_inode;
+	/*
+	 * Do a lookup to verify the new filehandle.
+	 */
+	nfserr = nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
+	if (nfserr) {
+		if (nfserr != nfserr_noent)
+			goto done;
+		/*
+		 * If the new filehandle wasn't verified, we can't tell
+		 * whether the file exists or not. Time to bail ...
+		 */
+		nfserr = nfserr_acces;
+		if (!newfhp->fh_dverified) {
+			printk(KERN_WARNING 
+				"nfsd_proc_create: filehandle not verified\n");
+			goto done;
+		}
+	}
 
-	/* Get rid of this soon... */
-	if (exists && !inode) {
-		printk("nfsd_proc_create: Wheee... exists but d_inode==NULL\n");
-		nfserr = nfserr_rofs;
+	/*
+	 * Lock the parent directory and check for existence.
+	 */
+	nfserr = fh_lock_parent(dirfhp, newfhp->fh_dentry);
+	if (nfserr)
 		goto done;
-	}		
+	inode = newfhp->fh_dentry->d_inode;
 
 	/* Unfudge the mode bits */
 	if (attr->ia_valid & ATTR_MODE) { 
@@ -233,7 +244,7 @@
 		mode = attr->ia_mode & ~S_IFMT;
 		if (!type)	/* HP weirdness */
 			type = S_IFREG;
-	} else if (exists) {
+	} else if (inode) {
 		type = inode->i_mode & S_IFMT;
 		mode = inode->i_mode & ~S_IFMT;
 	} else {
@@ -243,8 +254,8 @@
 
 	/* This is for "echo > /dev/null" a la SunOS. Argh. */
 	nfserr = nfserr_rofs;
-	if (rdonly && (!exists || type == S_IFREG))
-		goto done;
+	if (rdonly && (!inode || type == S_IFREG))
+		goto out_unlock;
 
 	attr->ia_valid |= ATTR_MODE;
 	attr->ia_mode = type | mode;
@@ -252,7 +263,6 @@
 	/* Special treatment for non-regular files according to the
 	 * gospel of sun micro
 	 */
-	nfserr = 0;
 	if (type != S_IFREG) {
 		int	is_borc = 0;
 		u32	size = attr->ia_size;
@@ -267,21 +277,21 @@
 		} else if (size != rdev) {
 			/* dev got truncated because of 16bit Linux dev_t */
 			nfserr = nfserr_io;	/* or nfserr_inval? */
-			goto done;
+			goto out_unlock;
 		} else {
 			/* Okay, char or block special */
 			is_borc = 1;
 		}
 
 		/* Make sure the type and device matches */
-		if (exists && (type != (inode->i_mode & S_IFMT)
-		 || (is_borc && inode->i_rdev != rdev))) {
-			nfserr = nfserr_exist;
-			goto done;
-		}
+		nfserr = nfserr_exist;
+		if (inode && (type != (inode->i_mode & S_IFMT) || 
+		    (is_borc && inode->i_rdev != rdev)))
+			goto out_unlock;
 	}
 	
-	if (!exists) {
+	nfserr = 0;
+	if (!inode) {
 		/* File doesn't exist. Create it and set attrs */
 		nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
 					attr, type, rdev, newfhp);
@@ -297,6 +307,10 @@
 			nfserr = nfsd_setattr(rqstp, newfhp, attr);
 	}
 
+out_unlock:
+	/* We don't really need to unlock, as fh_put does it. */
+	fh_unlock(dirfhp);
+
 done:
 	fh_put(dirfhp);
 	RETURN(nfserr);
@@ -359,9 +373,9 @@
 	int		nfserr;
 
 	dprintk("nfsd: SYMLINK  %p %s -> %s\n",
-		SVCFH_DENTRY(&argp->ffh),
-		argp->fname, argp->tname);
+		SVCFH_DENTRY(&argp->ffh), argp->fname, argp->tname);
 
+	memset(&newfh, 0, sizeof(struct svc_fh));
 	/*
 	 * Create the link, look up new file and set attrs.
 	 */
@@ -386,12 +400,13 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: MKDIR    %p %s\n",
-		SVCFH_DENTRY(&argp->fh),
-		argp->name);
+	dprintk("nfsd: MKDIR    %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+
+	if (resp->fh.fh_dverified) {
+		printk(KERN_WARNING
+			"nfsd_proc_mkdir: response already verified??\n");
+	}
 
-	/* N.B. what about the dentry count?? */
-	resp->fh.fh_dverified = 0; /* paranoia */
 	nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
 				    &argp->attrs, S_IFDIR, 0, &resp->fh);
 	fh_put(&argp->fh);
diff -u --recursive --new-file v2.1.105/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.105/linux/fs/nfsd/vfs.c	Fri May  8 23:14:53 1998
+++ linux/fs/nfsd/vfs.c	Sat Jun 13 09:58:14 1998
@@ -31,14 +31,13 @@
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/nfsfh.h>
 #include <linux/quotaops.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
 #endif
 
-extern void fh_update(struct svc_fh*);
-
 #define NFSDDBG_FACILITY		NFSDDBG_FILEOP
 
 /* Open mode for nfsd_open */
@@ -77,6 +76,41 @@
 static struct raparms *		raparm_cache = 0;
 
 /*
+ * Lock a parent directory following the VFS locking protocol.
+ */
+int
+fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild)
+{
+	int	nfserr = 0;
+
+	fh_lock(parent_fh);
+	/*
+	 * Make sure the parent->child relationship still holds,
+	 * and that the child is still hashed.
+	 */
+	if (dchild->d_parent != parent_fh->fh_dentry) 
+		goto out_not_parent;
+	if (list_empty(&dchild->d_hash))
+		goto out_not_hashed; 
+out:
+	return nfserr;
+
+out_not_parent:
+	printk(KERN_WARNING
+		"fh_lock_parent: %s/%s parent changed\n",
+		dchild->d_parent->d_name.name, dchild->d_name.name);
+	goto out_unlock;
+out_not_hashed:
+	printk(KERN_WARNING
+		"fh_lock_parent: %s/%s unhashed\n",
+		dchild->d_parent->d_name.name, dchild->d_name.name);
+out_unlock:
+	nfserr = nfserr_noent;
+	fh_unlock(parent_fh);
+	goto out;
+}
+
+/*
  * Deny access to certain file systems
  */
 static inline int
@@ -546,8 +580,11 @@
 }
 
 /*
- * Create a file (regular, directory, device, fifo).
- * UNIX sockets not yet implemented.
+ * Create a file (regular, directory, device, fifo); UNIX sockets 
+ * not yet implemented.
+ * If the response fh has been verified, the parent directory should
+ * already be locked. Note that the parent directory is left locked.
+ *
  * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
  */
 int
@@ -557,13 +594,12 @@
 {
 	struct dentry	*dentry, *dchild;
 	struct inode	*dirp;
+	nfsd_dirop_t	opfunc = NULL;
 	int		err;
 
 	err = nfserr_perm;
 	if (!flen)
 		goto out;
-	if (!(iap->ia_valid & ATTR_MODE))
-		iap->ia_mode = 0;
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
 	if (err)
 		goto out;
@@ -571,64 +607,74 @@
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
 
-	/* Get all the sanity checks out of the way before we lock the parent. */
 	err = nfserr_notdir;
 	if(!dirp->i_op || !dirp->i_op->lookup)
 		goto out;
-	err = nfserr_perm;
-	if (type == S_IFREG) {
-		if(!dirp->i_op->create)
-			goto out;
-	} else if(type == S_IFDIR) {
-		if(!dirp->i_op->mkdir)
-			goto out;
-	} else if((type == S_IFCHR) || (type == S_IFBLK) || (type == S_IFIFO)) {
-		if(!dirp->i_op->mknod)
-			goto out;
-	} else {
-		goto out;
-	}
-
 	/*
-	 * The response filehandle may have been setup already ...
+	 * Check whether the response filehandle has been verified yet.
+	 * If it has, the parent directory should already be locked.
 	 */
 	if (!resfhp->fh_dverified) {
 		dchild = lookup_dentry(fname, dget(dentry), 0);
 		err = PTR_ERR(dchild);
-		if(IS_ERR(dchild))
+		if (IS_ERR(dchild))
 			goto out_nfserr;
 		fh_compose(resfhp, fhp->fh_export, dchild);
-	} else
+		/* Lock the parent and check for errors ... */
+		err = fh_lock_parent(fhp, dchild);
+		if (err)
+			goto out;
+	} else {
 		dchild = resfhp->fh_dentry;
+		if (!fhp->fh_locked)
+			printk(KERN_ERR
+				"nfsd_create: parent %s/%s not locked!\n",
+				dentry->d_parent->d_name.name,
+				dentry->d_name.name);
+	}
 	/*
 	 * Make sure the child dentry is still negative ...
 	 */
+	err = nfserr_exist;
 	if (dchild->d_inode) {
-		printk("nfsd_create: dentry %s/%s not negative!\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name);
+		printk(KERN_WARNING
+			"nfsd_create: dentry %s/%s not negative!\n",
+			dentry->d_name.name, dchild->d_name.name);
+		goto out; 
 	}
 
-	/* Looks good, lock the directory. */
-	fh_lock(fhp);
-	DQUOT_INIT(dirp);
+	/*
+	 * Get the dir op function pointer.
+	 */
+	err = nfserr_perm;
 	switch (type) {
 	case S_IFREG:
-		err = dirp->i_op->create(dirp, dchild, iap->ia_mode);
+		opfunc = (nfsd_dirop_t) dirp->i_op->create;
 		break;
 	case S_IFDIR:
-		err = dirp->i_op->mkdir(dirp, dchild, iap->ia_mode);
+		opfunc = (nfsd_dirop_t) dirp->i_op->mkdir;
 		break;
 	case S_IFCHR:
 	case S_IFBLK:
 	case S_IFIFO:
-		err = dirp->i_op->mknod(dirp, dchild, iap->ia_mode, rdev);
+		opfunc = dirp->i_op->mknod;
 		break;
 	}
-	DQUOT_DROP(dirp);
-	fh_unlock(fhp);
+	if (!opfunc)
+		goto out;
 
+	if (!(iap->ia_valid & ATTR_MODE))
+		iap->ia_mode = 0;
+
+	/*
+	 * Call the dir op function to create the object.
+	 */
+	DQUOT_INIT(dirp);
+	err = opfunc(dirp, dchild, iap->ia_mode, rdev);
+	DQUOT_DROP(dirp);
 	if (err < 0)
 		goto out_nfserr;
+
 	if (EX_ISSYNC(fhp->fh_export))
 		write_inode_now(dirp);
 
@@ -778,21 +824,29 @@
 	if (IS_ERR(dnew))
 		goto out_nfserr;
 
-	err = -EEXIST;
+	/*
+	 * Lock the parent before checking for existence
+	 */
+	err = fh_lock_parent(fhp, dnew);
+	if (err)
+		goto out_compose;
+
+	err = nfserr_exist;
 	if (!dnew->d_inode) {
-		fh_lock(fhp);
 		DQUOT_INIT(dirp);
 		err = dirp->i_op->symlink(dirp, dnew, path);
 		DQUOT_DROP(dirp);
-		fh_unlock(fhp);
 		if (!err) {
 			if (EX_ISSYNC(fhp->fh_export))
 				write_inode_now(dirp);
-		}
+		} else
+			err = nfserrno(-err);
 	}
+	fh_unlock(fhp);
+
+	/* Compose the fh so the dentry will be freed ... */
+out_compose:
 	fh_compose(resfhp, fhp->fh_export, dnew);
-	if (err)
-		goto out_nfserr;
 out:
 	return err;
 
@@ -820,6 +874,10 @@
 	if (err)
 		goto out;
 
+	err = nfserr_perm;
+	if (!len)
+		goto out;
+
 	ddir = ffhp->fh_dentry;
 	dirp = ddir->d_inode;
 
@@ -827,44 +885,48 @@
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
+	/*
+	 * Lock the parent before checking for existence
+	 */
+	err = fh_lock_parent(ffhp, dnew);
+	if (err)
+		goto out_dput;
 
-	err = -EEXIST;
+	err = nfserr_exist;
 	if (dnew->d_inode)
-		goto dput_and_out;
-
-	err = -EPERM;
-	if (!len)
-		goto dput_and_out;
+		goto out_unlock;
 
 	dold = tfhp->fh_dentry;
 	dest = dold->d_inode;
 
-	err = -EACCES;
+	err = nfserr_acces;
 	if (nfsd_iscovered(ddir, ffhp->fh_export))
-		goto dput_and_out;
+		goto out_unlock;
+	/* FIXME: nxdev for NFSv3 */
 	if (dirp->i_dev != dest->i_dev)
-		goto dput_and_out;	/* FIXME: nxdev for NFSv3 */
+		goto out_unlock;
 
-	err = -EPERM;
+	err = nfserr_perm;
 	if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
-		goto dput_and_out;
+		goto out_unlock;
 	if (!dirp->i_op || !dirp->i_op->link)
-		goto dput_and_out;
+		goto out_unlock;
 
-	fh_lock(ffhp);
 	DQUOT_INIT(dirp);
 	err = dirp->i_op->link(dold, dirp, dnew);
 	DQUOT_DROP(dirp);
-	fh_unlock(ffhp);
+	if (!err) {
+		if (EX_ISSYNC(ffhp->fh_export)) {
+			write_inode_now(dirp);
+			write_inode_now(dest);
+		}
+	} else
+		err = nfserrno(-err);
 
-	if (!err && EX_ISSYNC(ffhp->fh_export)) {
-		write_inode_now(dirp);
-		write_inode_now(dest);
-	}
-dput_and_out:
+out_unlock:
+	fh_unlock(ffhp);
+out_dput:
 	dput(dnew);
-	if (err)
-		goto out_nfserr;
 out:
 	return err;
 
@@ -1005,7 +1067,10 @@
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
 
-	fh_lock(fhp);
+	err = fh_lock_parent(fhp, rdentry);
+	if (err)
+		goto out;
+
 	DQUOT_INIT(dirp);
 	if (type == S_IFDIR) {
 		err = -ENOTDIR;
diff -u --recursive --new-file v2.1.105/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.105/linux/fs/proc/array.c	Tue Jun  9 11:57:30 1998
+++ linux/fs/proc/array.c	Sat Jun 13 12:59:15 1998
@@ -544,6 +544,23 @@
 	}
 #elif defined(__powerpc__)
 	return (p->tss.wchan);
+#elif defined (CONFIG_ARM)
+	{
+		unsigned long fp, lr;
+		unsigned long stack_page;
+		int count = 0;
+
+		stack_page = 4096 + (unsigned long)p;
+		fp = get_css_fp (&p->tss);
+		do {
+			if (fp < stack_page || fp > 4092+stack_page)
+				return 0;
+			lr = pc_pointer (((unsigned long *)fp)[-1]);
+			if (lr < first_sched || lr > last_sched)
+				return lr;
+			fp = *(unsigned long *) (fp - 12);
+		} while (count ++ < 16);
+	}
 #endif
 	return 0;
 }
@@ -560,6 +577,9 @@
 # define KSTK_EIP(tsk) \
     (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
 # define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(CONFIG_ARM)
+# define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+# define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
 #elif defined(__mc68000__)
 #define	KSTK_EIP(tsk)	\
     ({			\
@@ -704,21 +724,6 @@
 			data - stack, stack,
 			exec - lib, lib);
 	}
-	return buffer;
-}
-
-char * render_sigset_t(sigset_t *set, char *buffer)
-{
-	int i = _NSIG, x;
-	do {
-		i -= 4, x = 0;
-		if (sigismember(set, i+1)) x |= 1;
-		if (sigismember(set, i+2)) x |= 2;
-		if (sigismember(set, i+3)) x |= 4;
-		if (sigismember(set, i+4)) x |= 8;
-		*buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
-	} while (i >= 4);
-	*buffer = 0;
 	return buffer;
 }
 
diff -u --recursive --new-file v2.1.105/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.105/linux/fs/romfs/inode.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/romfs/inode.c	Wed Jun 10 11:17:29 1998
@@ -282,7 +282,7 @@
 	/* Not really failsafe, but we are read-only... */
 	for(;;) {
 		if (!offset || offset >= maxoff) {
-			offset = 0xffffffff;
+			offset = maxoff;
 			filp->f_pos = offset;
 			return stored;
 		}
diff -u --recursive --new-file v2.1.105/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.1.105/linux/include/asm-alpha/bitops.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/bitops.h	Sat Jun 13 12:56:46 1998
@@ -183,6 +183,24 @@
 }
 
 /*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
+/*
  * Find next zero bit in a bitmap reasonably efficiently..
  */
 extern inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
diff -u --recursive --new-file v2.1.105/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.1.105/linux/include/asm-alpha/pgtable.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/pgtable.h	Sat Jun 13 12:48:10 1998
@@ -11,6 +11,7 @@
 #include <linux/config.h>
 
 #include <asm/system.h>
+#include <asm/processor.h>	/* For TASK_SIZE */
 #include <asm/mmu_context.h>
 
 /* Caches aren't brain-dead on the alpha. */
@@ -181,6 +182,7 @@
 #define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PMD	(1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PGD	((1UL << (PAGE_SHIFT-3))-1)
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE	(1UL << (PAGE_SHIFT-3))
@@ -401,126 +403,174 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-extern inline void pte_free_kernel(pte_t * pte)
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
+#else
+#include <asm/smp.h>
+#define quicklists cpu_data[smp_processor_id()]
+#endif
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
+{
+	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+	
+	if (ret) {
+		init = pgd_offset(&init_mm, 0);
+		memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	}
+	return ret;
+}
+
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-	free_page((unsigned long) pte);
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
 }
 
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_set(pmd, page);
-				return page + address;
-			}
-			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
 }
 
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	free_page((unsigned long) pmd);
+	free_page((unsigned long)pgd);
 }
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
+
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-		if (pgd_none(*pgd)) {
-			if (page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
 	}
-	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PAGETABLE);
-		return NULL;
+	return (pmd_t *)ret;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+	*(unsigned long *)pmd = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pmd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+	free_page((unsigned long)pmd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
 	}
-	return (pmd_t *) pgd_page(*pgd) + address;
+	return (pte_t *)ret;
 }
 
-extern inline void pte_free(pte_t * pte)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
-	free_page((unsigned long) pte);
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
 }
 
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pmd(pgd_t *pgd);
+
+#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free(pte)		free_pte_fast(pte)
+#define pmd_free_kernel(pmd)	free_pmd_fast(pmd)
+#define pmd_free(pmd)		free_pmd_fast(pmd)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
+#define pgd_alloc()		get_pgd_fast()
+
 extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_set(pmd, page);
-				return page + address;
-			}
-			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
+		pte_t *page = get_pte_fast();
+		
+		if (!page)
+			return get_pte_slow(pmd, address);
+		pmd_set(pmd, page);
+		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		__bad_pte(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
 }
 
-extern inline void pmd_free(pmd_t * pmd)
-{
-	free_page((unsigned long) pmd);
-}
-
 extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
 {
 	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
 	if (pgd_none(*pgd)) {
-		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-		if (pgd_none(*pgd)) {
-			if (page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
+		pmd_t *page = get_pmd_fast();
+		
+		if (!page)
+			return get_pmd_slow(pgd, address);
+		pgd_set(pgd, page);
+		return page + address;
 	}
 	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PAGETABLE);
+		__bad_pmd(pgd);
 		return NULL;
 	}
 	return (pmd_t *) pgd_page(*pgd) + address;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{
-	free_page((unsigned long) pgd);
-}
+#define pte_alloc_kernel	pte_alloc
+#define pmd_alloc_kernel	pmd_alloc
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-	return (pgd_t *) get_free_page(GFP_KERNEL);
+	struct task_struct * p;
+	pgd_t *pgd;
+        
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[(address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)] = entry;
 }
 
 extern pgd_t swapper_pg_dir[1024];
diff -u --recursive --new-file v2.1.105/linux/include/asm-alpha/signal.h linux/include/asm-alpha/signal.h
--- v2.1.105/linux/include/asm-alpha/signal.h	Thu Feb 12 20:56:12 1998
+++ linux/include/asm-alpha/signal.h	Tue Jun  9 00:55:10 1998
@@ -76,7 +76,7 @@
 /*
  * SA_FLAGS values:
  *
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ * SA_ONSTACK indicates that a registered stack_t will be used.
  * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
  * SA_RESTART flag to get restarting signals (which were the default long ago)
  * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
@@ -100,6 +100,16 @@
 #define SA_NOMASK	SA_NODEFER
 #define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
 
+/* 
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	4096
+#define SIGSTKSZ	16384
+
+
 #ifdef __KERNEL__
 /*
  * These values of sa_flags are used only by the kernel as part of the
@@ -163,6 +173,15 @@
 	int ss_flags;
 	size_t ss_size;
 } stack_t;
+
+/* sigstack(2) is deprecated, and will be withdrawn in a future version
+   of the X/Open CAE Specification.  Use sigaltstack instead.  It is only
+   implemented here for OSF/1 compatability.  */
+
+struct sigstack {
+	void *ss_sp;
+	int ss_onstack;
+};
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
diff -u --recursive --new-file v2.1.105/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.1.105/linux/include/asm-alpha/smp.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/smp.h	Sat Jun 13 12:48:11 1998
@@ -10,6 +10,9 @@
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
 	unsigned int next;
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
 };
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
diff -u --recursive --new-file v2.1.105/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.1.105/linux/include/asm-alpha/unistd.h	Sun Jun  7 11:16:36 1998
+++ linux/include/asm-alpha/unistd.h	Tue Jun  9 13:34:01 1998
@@ -113,7 +113,7 @@
 #define __NR_osf_old_sigblock	109	/* not implemented */
 #define __NR_osf_old_sigsetmask	110	/* not implemented */
 #define __NR_sigsuspend		111
-#define __NR_osf_sigstack	112	/* not implemented */
+#define __NR_osf_sigstack	112
 #define __NR_recvmsg		113
 #define __NR_sendmsg		114
 #define __NR_osf_old_vtrace	115	/* not implemented */
@@ -205,7 +205,7 @@
 
 #define __NR_getpgid		233
 #define __NR_getsid		234
-#define __NR_osf_sigaltstack	235	/* not implemented */
+#define __NR_sigaltstack	235
 #define __NR_osf_waitid		236	/* not implemented */
 #define __NR_osf_priocntlset	237	/* not implemented */
 #define __NR_osf_sigsendset	238	/* not implemented */
@@ -305,7 +305,8 @@
 #define __NR_wait4			365
 #define __NR_adjtimex			366
 #define __NR_getcwd			367
-
+#define __NR_capget			368
+#define __NR_capset			369
 
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/a.out.h linux/include/asm-arm/arch-a5k/a.out.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/a.out.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP		(0x01a00000)
-#define LIBRARY_START_TEXT	(0x00c00000)
-#endif
-
-#endif
-
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/dma.h linux/include/asm-arm/arch-a5k/dma.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/dma.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/dma.h	Wed Dec 31 16:00:00 1969
@@ -1,101 +0,0 @@
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS		0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-	case 2:  disable_irq(64); break;
-	default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    switch(dmanr) {
-	case 2:  break;
-	default: printk (dma_str, "clear_dma_ff", dmanr); break;
-    }
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
-
-#endif /* _ASM_ARCH_DMA_H */
-
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/hardware.h linux/include/asm-arm/arch-a5k/hardware.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/hardware.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/hardware.h	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/hardware.h
- *
- * Copyright (C) 1996 Russell King.
- *
- * This file contains the hardware definitions of the A5000 series machines.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-#define HAS_IOC
-#define HAS_PCIO
-#define HAS_MEMC
-#define HAS_MEMC1A
-#define HAS_VIDC
-
-/*
- * Optional hardware
- */
-#define HAS_EXPMASK
-
-#ifndef __ASSEMBLER__
-
-/*
- * for use with inb/outb
- */
-#define VIDC_BASE		0x80100000
-#define IOCEC4IO_BASE		0x8009c000
-#define IOCECIO_BASE		0x80090000
-#define IOC_BASE		0x80080000
-#define MEMCECIO_BASE		0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE		((volatile unsigned char *)0x03360000)
-#define IOEB_BASE		((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE		0x03010000
-
-/*
- * Mapping areas
- */
-#define IO_END			0x03ffffff
-#define IO_BASE			0x03000000
-#define IO_SIZE			(IO_END - IO_BASE)
-#define IO_START		0x03000000
-
-/*
- * Screen mapping information
- */
-#define SCREEN2_END		0x02078000
-#define SCREEN2_BASE		0x02000000
-#define SCREEN1_END		SCREEN2_BASE
-#define SCREEN1_BASE		0x01f88000
-#define SCREEN_START		0x02000000
-
-/*
- * RAM definitions
- */
-#define MAPTOPHYS(a)		(((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)		((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
-#define GET_MEMORY_END(p)	(PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE		(PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE		(PAGE_OFFSET + 0x80000)
-
-#else
-
-#define IOEB_BASE		0x03350050
-#define IOC_BASE		0x03200000
-#define PCIO_FLOPPYDMABASE	0x0302a000
-#define PCIO_BASE		0x03010000
-#define IO_BASE			0x03000000
-
-#endif
-#endif
-
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/ide.h linux/include/asm-arm/arch-a5k/ide.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/ide.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/ide.h	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/ide.h
- *
- * Copyright (c) 1997 Russell King
- */
-
-static __inline__ int
-ide_default_irq(ide_ioreg_t base)
-{
-	if (base == 0x1f0)
-		return 11;
-	return 0;
-}
-
-static __inline__ ide_ioreg_t
-ide_default_io_base(int index)
-{
-	if (index == 0)
-		return 0x1f0;
-	return 0;
-}
-
-static __inline__ int
-ide_default_stepping(int index)
-{
-	return 0;
-}
-
-static __inline__ void
-ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int stepping, int *irq)
-{
-	ide_ioreg_t port = base;
-	ide_ioreg_t ctrl = base + 0x206;
-	int i;
-
-	i = 8;
-	while (i--) {
-		*p++ = port;
-		port += 1 << stepping;
-	}
-	*p++ = ctrl;
-	if (irq != NULL)
-		irq = 0;
-}
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/io.h linux/include/asm-arm/arch-a5k/io.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/io.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/io.h	Wed Dec 31 16:00:00 1969
@@ -1,215 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- *  06-Dec-1997	RMK	Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x)	((unsigned long)(x))
-#define bus_to_virt(x)	((void *)(x))
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef	ARCH_IO_DELAY
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.  Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x)	(!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"strb	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"str	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"str	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long temp, value;						\
-	__asm__ __volatile__(							\
-	"tst	%2, #0x80000000\n\t"						\
-	"mov	%0, %4\n\t"							\
-	"addeq	%0, %0, %3\n\t"							\
-	"ldr" ##instr## "	%1, [%0, %2, lsl #2]"				\
-	: "=&r" (temp), "=r" (value)						\
-	: "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)		\
-	: "cc");								\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	if (__PORT_PCIO(port))							\
-		return (unsigned int)(PCIO_BASE + (port << 2));			\
-	else									\
-		return (unsigned int)(IO_BASE + (port << 2));			\
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)							\
-({										\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"strb	%0, [%1, %2]"						\
-		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"strb	%0, [%1, %2]"						\
-		: : "r" (value), "r" (IO_BASE), "r" ((port) << 2));		\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldrb	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldrb	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	unsigned long v = value;						\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"str	%0, [%1, %2]"						\
-		: : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));	\
-	else									\
-		__asm__ __volatile__(						\
-		"str	%0, [%1, %2]"						\
-		: : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));		\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result & 0xffff;							\
-})
-
-#define __outlc(v,p) __outwc((v),(p))
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	if (__PORT_PCIO((port)))						\
-		addr = PCIO_BASE + ((port) << 2);				\
-	else									\
-		addr = IO_BASE + ((port) << 2);					\
-	addr;									\
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)								\
-	(*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)								\
-	(*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)								\
-	(*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)								\
-	(*(volatile unsigned long *)(p))
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/irq.h linux/include/asm-arm/arch-a5k/irq.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/irq.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-/*
- * include/asm-arm/arch-a5k/irq.h
- *
- * Copyright (C) 1996 Russell King
- *
- * Changelog:
- *   24-09-1996	RMK	Created
- *   10-10-1996	RMK	Brought up to date with arch-sa110eval
- *   22-10-1996	RMK	Changed interrupt numbers & uses new inb/outb macros
- *   11-01-1998	RMK	Added mask_and_ack_irq
- */
-
-#define BUILD_IRQ(s,n,m) \
-	void IRQ##n##_interrupt(void); \
-	void fast_IRQ##n##_interrupt(void); \
-	void bad_IRQ##n##_interrupt(void); \
-	void probe_IRQ##n##_interrupt(void);
-
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt		timer_IRQ_interrupt
-
-#define IRQ_INTERRUPT(n)	IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)	fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)	bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)	probe_IRQ##n##_interrupt
-                                
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-	static const int addrmasks[] = {
-		X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
-		X((IOC_IRQMASKB - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		X((IOC_FIQMASK - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0)
-	};
-	unsigned int temp1, temp2;
-
-	__asm__ __volatile__(
-"	ldr	%1, [%5, %3, lsl #2]\n"
-"	teq	%1, #0\n"
-"	beq	2f\n"
-"	ldrb	%0, [%2, %1, lsr #16]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2, %1, lsr #16]\n"
-"	tst	%1, #0x8000\n"			/* do we need an IRQ clear? */
-"	strneb	%1, [%2, %4]\n"
-"2:"
-	: "=&r" (temp1), "=&r" (temp2)
-	: "r" (ioaddr(IOC_BASE)), "r" (irq),
-	  "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-	extern void ecard_disableirq (unsigned int);
-	extern void ecard_disablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_disableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_disablefiq (irq & 7);
-	}
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
-	extern void ecard_enableirq (unsigned int);
-	extern void ecard_enablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_enableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_enablefiq (irq & 7);
-	}
-}
-
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-	return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
-}
-
-static __inline__ void irq_init_irq(void)
-{
-	outb(0, IOC_IRQMASKA);
-	outb(0, IOC_IRQMASKB);
-	outb(0, IOC_FIQMASK);
-}
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/irqs.h linux/include/asm-arm/arch-a5k/irqs.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/irqs.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/irqs.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/irqs.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define IRQ_PRINTER		0
-#define IRQ_BATLOW		1
-#define IRQ_FLOPPYINDEX		2
-#define IRQ_VSYNCPULSE		3
-#define IRQ_POWERON		4
-#define IRQ_TIMER0		5
-#define IRQ_TIMER1		6
-#define IRQ_IMMEDIATE		7
-#define IRQ_EXPCARDFIQ		8
-#define IRQ_SOUNDCHANGE		9
-#define IRQ_SERIALPORT		10
-#define IRQ_HARDDISK		11
-#define IRQ_FLOPPYDISK		12
-#define IRQ_EXPANSIONCARD	13
-#define IRQ_KEYBOARDTX		14
-#define IRQ_KEYBOARDRX		15
-
-#define FIQ_FLOPPYDATA		0
-#define FIQ_ECONET		2
-#define FIQ_SERIALPORT		4
-#define FIQ_EXPANSIONCARD	6
-#define FIQ_FORCE		7
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/mmu.h linux/include/asm-arm/arch-a5k/mmu.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/mmu.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt(ppage) ppage
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/oldlatches.h linux/include/asm-arm/arch-a5k/oldlatches.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/oldlatches.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (a5k) machine"
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/processor.h linux/include/asm-arm/arch-a5k/processor.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/processor.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/processor.h	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/processor.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  10-09-1996	RMK	Created
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 26MB
- */
-#define TASK_SIZE	(0x01a00000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE(off)	(TASK_SIZE / 3)
-#define TASK_UNMAPPED_ALIGN(addr, off)	PAGE_ALIGN(addr)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/serial.h linux/include/asm-arm/arch-a5k/serial.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/serial.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-	{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/shmparam.h linux/include/asm-arm/arch-a5k/shmparam.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/shmparam.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/system.h linux/include/asm-arm/arch-a5k/system.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/system.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/system.h	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/system.h
- *
- * Copyright (c) 1996 Russell King
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-extern __inline__ void arch_hard_reset (void)
-{
-	extern void ecard_reset (int card);
-
-	/*
-	 * Reset all expansion cards.
-	 */
-	ecard_reset (-1);
-
-	/*
-	 * copy branch instruction to reset location and call it
-	 */
-	*(unsigned long *)0 = *(unsigned long *)0x03800000;
-	((void(*)(void))0)();
-
-	/*
-	 * If that didn't work, loop endlessly
-	 */
-	while (1);
-}
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/time.h linux/include/asm-arm/arch-a5k/time.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/time.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/time.h	Wed Dec 31 16:00:00 1969
@@ -1,96 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/time.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  24-Sep-1996	RMK	Created
- *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
- *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
- */
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-	unsigned int count1, count2, status1, status2;
-	unsigned long offset = 0;
-
-	status1 = IOC_IRQREQA;
-	barrier ();
-	outb (0, IOC_T0LATCH);
-	barrier ();
-	count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-	barrier ();
-	status2 = inb(IOC_IRQREQA);
-	barrier ();
-	outb (0, IOC_T0LATCH);
-	barrier ();
-	count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-
-	if (count2 < count1) {
-		/*
-		 * This means that we haven't just had an interrupt
-		 * while reading into status2.
-		 */
-		if (status2 & (1 << 5))
-			offset = tick;
-		count1 = count2;
-	} else if (count2 > count1) {
-		/*
-		 * We have just had another interrupt while reading
-		 * status2.
-		 */
-		offset += tick;
-		count1 = count2;
-	}
-
-	count1 = LATCH - count1;
-	/*
-	 * count1 = number of clock ticks since last interrupt
-	 */
-	offset += count1 * tick / LATCH;
-	return offset;
-}
-
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
-
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-	extern int iic_control (unsigned char, int, char *, int);
-	unsigned int year, mon, day, hour, min, sec;
-	char buf[8];
-
-	outb(LATCH & 255, IOC_T0LTCHL);
-	outb(LATCH >> 8, IOC_T0LTCHH);
-	outb(0, IOC_T0GO);
-
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
-
-	return mktime(year, mon, day, hour, min, sec);
-}
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/timex.h linux/include/asm-arm/arch-a5k/timex.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/timex.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/timex.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/timex.h
- *
- * A5000 architecture timex specifications
- *
- * Copyright (C) 1997, 1998 Russell King
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE		2000000
-
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-a5k/uncompress.h linux/include/asm-arm/arch-a5k/uncompress.h
--- v2.1.105/linux/include/asm-arm/arch-a5k/uncompress.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-a5k/uncompress.h	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/uncompress.h
- *
- * Copyright (C) 1996 Russell King
- */
-#define VIDMEM ((char *)0x02000000)
- 
-#include "../arch/arm/drivers/char/font.h"
-
-int video_num_columns, video_num_lines, video_size_row;
-int white, bytes_per_char_h;
-extern unsigned long con_charconvtable[256];
-
-struct param_struct {
-	unsigned long page_size;
-	unsigned long nr_pages;
-	unsigned long ramdisk_size;
-	unsigned long mountrootrdonly;
-	unsigned long rootdev;
-	unsigned long video_num_cols;
-	unsigned long video_num_rows;
-	unsigned long video_x;
-	unsigned long video_y;
-	unsigned long memc_control_reg;
-	unsigned char sounddefault;
-	unsigned char adfsdrives;
-	unsigned char bytes_per_char_h;
-	unsigned char bytes_per_char_v;
-	unsigned long unused[256/4-11];
-};
-
-static struct param_struct *params = (struct param_struct *)0x0207c000;
- 
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-	extern void ll_write_char(char *, unsigned long);
-	int x,y;
-	unsigned char c;
-	char *ptr;
-
-	x = params->video_x;
-	y = params->video_y;
-
-	while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
-		if ( c == '\n' ) {
-			x = 0;
-			if ( ++y >= video_num_lines ) {
-				y--;
-			}
-		} else {
-			ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-			ll_write_char(ptr, c|(white<<8));
-			if ( ++x >= video_num_columns ) {
-				x = 0;
-				if ( ++y >= video_num_lines ) {
-					y--;
-				}
-			}
-		}
-	}
-
-	params->video_x = x;
-	params->video_y = y;
-}
-
-static void error(char *x);
-
-/*
- * Setup for decompression
- */
-static void arch_decomp_setup(void)
-{
-	int i;
-	
-	video_num_lines = params->video_num_rows;
-	video_num_columns = params->video_num_cols;
-	bytes_per_char_h = params->bytes_per_char_h;
-	video_size_row = video_num_columns * bytes_per_char_h;
-	if (bytes_per_char_h == 4)
-		for (i = 0; i < 256; i++)
-			con_charconvtable[i] =
-				(i & 128 ? 1 << 0  : 0) |
-				(i & 64  ? 1 << 4  : 0) |
-				(i & 32  ? 1 << 8  : 0) |
-				(i & 16  ? 1 << 12 : 0) |
-				(i & 8   ? 1 << 16 : 0) |
-				(i & 4   ? 1 << 20 : 0) |
-				(i & 2   ? 1 << 24 : 0) |
-				(i & 1   ? 1 << 28 : 0);
-	else
-		for (i = 0; i < 16; i++)
-			con_charconvtable[i] =
-				(i & 8   ? 1 << 0  : 0) |
-				(i & 4   ? 1 << 8  : 0) |
-				(i & 2   ? 1 << 16 : 0) |
-				(i & 1   ? 1 << 24 : 0);
-
-	white = bytes_per_char_h == 8 ? 0xfc : 7;
-
-	if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
-}
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-ebsa110/mmap.h linux/include/asm-arm/arch-ebsa110/mmap.h
--- v2.1.105/linux/include/asm-arm/arch-ebsa110/mmap.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-ebsa110/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR	0x40000000
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.1.105/linux/include/asm-arm/arch-ebsa285/io.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/io.h	Sat Jun 13 13:11:12 1998
@@ -140,4 +140,26 @@
 #define inl_t(p)								\
 	(*(volatile unsigned long *)(p))
 
+/*
+ * This is not sufficient... (and it's a hack anyway)
+ */
+static inline void writeb(unsigned char b, unsigned int addr)
+{
+	*(volatile unsigned char *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned char readb(unsigned int addr)
+{
+	return *(volatile unsigned char *)(0xe0000000 + (addr));
+}
+
+static inline void writew(unsigned short b, unsigned int addr)
+{
+	*(volatile unsigned short *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned short readw(unsigned int addr)
+{
+	return *(volatile unsigned short *)(0xe0000000 + (addr));
+}
 #endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h
--- v2.1.105/linux/include/asm-arm/arch-ebsa285/processor.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-ebsa285/processor.h	Sat Jun 13 13:11:12 1998
@@ -23,7 +23,11 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
+#if 0
 #define TASK_UNMAPPED_BASE(off)	(TASK_SIZE / 3)
+#else
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#endif
 #define TASK_UNMAPPED_ALIGN(addr, off)	PAGE_ALIGN(addr)
 
 #define INIT_MMAP \
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-nexuspci/mmap.h linux/include/asm-arm/arch-nexuspci/mmap.h
--- v2.1.105/linux/include/asm-arm/arch-nexuspci/mmap.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-nexuspci/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR	0x40000000
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-nexuspci/serial.h linux/include/asm-arm/arch-nexuspci/serial.h
--- v2.1.105/linux/include/asm-arm/arch-nexuspci/serial.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-nexuspci/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/serial.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-	{ 0, BASE_BAUD, 0x3F8,  1, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8,  2, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
-
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/arch-rpc/mmap.h linux/include/asm-arm/arch-rpc/mmap.h
--- v2.1.105/linux/include/asm-arm/arch-rpc/mmap.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-rpc/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-#define SAFE_ADDR 0x00000000	/* ROM */
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-	static int updated = 0;
-	unsigned long address;
-	pgd_t *pgd;
-
-	if (updated)
-		return 0;
-	updated = update;
-
-	address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-	pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
-	pgd_val(pgd[0]) = address;
-	pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
-	if (update) {
-		unsigned long pgtable = PAGE_ALIGN(kmem), *p;
-		int i;
-
-		memzero ((void *)pgtable, 4096);
-		
-		pgd_val(pgd[-2]) = virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		pgd_val(pgd[-1]) = virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		p = (unsigned long *)pgtable;
-
-		i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
-		address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
-		while (i < PTRS_PER_PTE * 2) {
-			p[i++] = address;
-			address += PAGE_SIZE;
-		}
-
-		flush_page_to_ram(pgtable);
-
-		kmem = pgtable + PAGE_SIZE;
-	}
-	return kmem;
-}
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/bitops.h linux/include/asm-arm/bitops.h
--- v2.1.105/linux/include/asm-arm/bitops.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/bitops.h	Sat Jun 13 12:56:46 1998
@@ -53,6 +53,24 @@
         return k;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 #ifdef __KERNEL__
 
 #define ext2_set_bit			test_and_set_bit
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/fiq.h linux/include/asm-arm/fiq.h
--- v2.1.105/linux/include/asm-arm/fiq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/fiq.h	Sat Jun 13 13:11:12 1998
@@ -0,0 +1,16 @@
+/* Support for FIQ on ARM architectures.
+ * Written by Philip Blundell <philb@gnu.org>, 1998
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+struct fiq_handler {
+	 const char *name;
+	 int (*callback)(void);
+};
+
+extern int claim_fiq(struct fiq_handler *f);
+extern void release_fiq(struct fiq_handler *f);
+
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/floppy.h linux/include/asm-arm/floppy.h
--- v2.1.105/linux/include/asm-arm/floppy.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/floppy.h	Sat Jun 13 13:11:12 1998
@@ -9,7 +9,14 @@
 #include <asm/arch/floppy.h>
 #endif
 
-#define fd_outb(val,port)	outb((val),(port))
+#define fd_outb(val,port)			\
+	do {					\
+		if ((port) == FD_DOR)		\
+			fd_setdor((val));	\
+		else				\
+			outb((val),(port));	\
+	} while(0)
+
 #define fd_inb(port)		inb((port))
 #define fd_request_irq()	request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
 					SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
@@ -27,6 +34,9 @@
 #define fd_set_dma_count(len)	set_dma_count(FLOPPY_DMA, (len))
 #define fd_cacheflush(addr,sz)
 
+/* need to clean up dma.h */
+#define DMA_FLOPPYDISK		DMA_FLOPPY
+
 /* Floppy_selects is the list of DOR's to select drive fd
  *
  * On initialisation, the floppy list is scanned, and the drives allocated
@@ -40,13 +50,14 @@
 	{ 0x10, 0x21, 0x23, 0x33 }
 };
 
-#define fd_setdor(dor)										\
-do {												\
-	int new_dor = (dor);									\
-	if (new_dor & 0xf0)									\
-		fd_outb((new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3], FD_DOR);		\
-	else											\
-		fd_outb((new_dor & 0x0c), FD_DOR);						\
+#define fd_setdor(dor)								\
+do {										\
+	int new_dor = (dor);							\
+	if (new_dor & 0xf0)							\
+		new_dor = (new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3];	\
+	else									\
+		new_dor &= 0x0c;						\
+	outb(new_dor, FD_DOR);							\
 } while (0)
 
 /*
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.1.105/linux/include/asm-arm/hardirq.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/hardirq.h	Sat Jun 13 13:11:12 1998
@@ -5,6 +5,12 @@
 
 extern unsigned int local_irq_count[NR_CPUS];
 
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.1.105/linux/include/asm-arm/io.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/io.h	Sat Jun 13 13:11:12 1998
@@ -170,44 +170,5 @@
 #undef ARCH_IO_DELAY
 #undef ARCH_IO_CONSTANT
 
-/*
- * Leftovers...
- */
-#if 0
-#define __outwc(value,port)						\
-({									\
-	if (port < 256)							\
-		__asm__ __volatile__(					\
-		"strh	%0, [%1, %2]"					\
-		: : "r" (value), "r" (PCIO_BASE), "J" (port << 2));	\
-	else if (__PORT_PCIO(port))					\
-		__asm__ __volatile__(					\
-		"strh	%0, [%1, %2]"					\
-		: : "r" (value), "r" (PCIO_BASE), "r" (port << 2));	\
-	else								\
-		__asm__ __volatile__(					\
-		"strh	%0, [%1, %2]"					\
-		: : "r" (value), "r" (IO_BASE), "r" (port << 2));	\
-})
-
-#define __inwc(port)							\
-({									\
-	unsigned short result;						\
-	if (port < 256)							\
-		__asm__ __volatile__(					\
-		"ldrh	%0, [%1, %2]"					\
-		: "=r" (result) : "r" (PCIO_BASE), "J" (port << 2));	\
-	else								\
-	if (__PORT_PCIO(port))						\
-		__asm__ __volatile__(					\
-		"ldrh	%0, [%1, %2]"					\
-		: "=r" (result) : "r" (PCIO_BASE), "r" (port << 2));	\
-	else								\
-		__asm__ __volatile__(					\
-		"ldrh	%0, [%1, %2]"					\
-		: "=r" (result) : "r" (IO_BASE), "r" (port << 2));	\
-	result;								\
-})
-#endif
 #endif
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/ioctl.h linux/include/asm-arm/ioctl.h
--- v2.1.105/linux/include/asm-arm/ioctl.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/ioctl.h	Sat Jun 13 13:11:12 1998
@@ -1,5 +1,4 @@
-/* $Id: ioctl.h,v 1.1 1998/01/28 09:56:22 ecd Exp $
- *
+/*
  * linux/ioctl.h for Linux by H.H. Bergman.
  */
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/irq-no.h linux/include/asm-arm/irq-no.h
--- v2.1.105/linux/include/asm-arm/irq-no.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/irq-no.h	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-/*
- * linux/include/asm-arm/irq-no.h
- *
- * Machine independent interrupt numbers
- */
-
-#include <asm/arch/irqs.h>
-
-#ifndef NR_IRQS
-#define NR_IRQS		128
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-arm/namei.h linux/include/asm-arm/namei.h
--- v2.1.105/linux/include/asm-arm/namei.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/namei.h	Sat Jun 13 13:11:12 1998
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1998/01/28 09:56:37 ecd Exp $
+/*
  * linux/include/asm-i386/namei.h
  *
  * Included from linux/fs/namei.c
diff -u --recursive --new-file v2.1.105/linux/include/asm-generic/bitops.h linux/include/asm-generic/bitops.h
--- v2.1.105/linux/include/asm-generic/bitops.h	Mon Aug 15 00:54:22 1994
+++ linux/include/asm-generic/bitops.h	Sat Jun 13 12:56:46 1998
@@ -50,4 +50,22 @@
 	mask = 1 << (nr & 0x1f);
 	return ((mask & *addr) != 0);
 }
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #endif /* _ASM_GENERIC_BITOPS_H */
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.1.105/linux/include/asm-i386/bitops.h	Mon Dec  1 11:16:57 1997
+++ linux/include/asm-i386/bitops.h	Sat Jun 13 12:56:46 1998
@@ -187,6 +187,33 @@
 	return word;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int ffs(int x)
+{
+	int r;
+
+	__asm__("bsfl %1,%0\n\t"
+		"jnz 1f\n\t"
+		"movl $-1,%0\n"
+		"1:" : "=r" (r) : "g" (x));
+	return r+1;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 #ifdef __KERNEL__
 
 #define ext2_set_bit                 test_and_set_bit
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/math_emu.h linux/include/asm-i386/math_emu.h
--- v2.1.105/linux/include/asm-i386/math_emu.h	Tue Dec  9 17:57:09 1997
+++ linux/include/asm-i386/math_emu.h	Tue Jun  9 00:55:10 1998
@@ -3,8 +3,8 @@
 
 #include <asm/sigcontext.h>
 
-void restore_i387_soft(void *s387, struct _fpstate *buf);
-struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf);
+int restore_i387_soft(void *s387, struct _fpstate *buf);
+int save_i387_soft(void *s387, struct _fpstate * buf);
 
 /* This structure matches the layout of the data saved to the stack
    following a device-not-present interrupt, part of it saved
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.1.105/linux/include/asm-i386/pgtable.h	Tue Mar 17 22:18:15 1998
+++ linux/include/asm-i386/pgtable.h	Sat Jun 13 13:48:21 1998
@@ -12,8 +12,10 @@
  * This file contains the functions and defines necessary to modify and use
  * the i386 page table tree.
  */
-
 #ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <linux/tasks.h>
+
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
@@ -38,7 +40,7 @@
 #define __flush_tlb() \
 do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0)
 
-#if defined(CONFIG_M386) || defined(CONFIG_AMD_K5_INVBUG)
+#ifdef CONFIG_M386
 #define __flush_tlb_one(addr) flush_tlb()
 #else
 #define __flush_tlb_one(addr) \
@@ -182,6 +184,7 @@
 #define PTRS_PER_PTE	1024
 #define PTRS_PER_PMD	1
 #define PTRS_PER_PGD	1024
+#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
 /*
  * pgd entries used up by user/kernel:
@@ -385,85 +388,137 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-extern inline void pte_free_kernel(pte_t * pte)
+
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
+{
+	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+
+	if (ret) {
+		init = pgd_offset(&init_mm, 0);
+		memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	}
+	return ret;
+}
+
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-	free_page((unsigned long) pte);
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
 }
 
-extern const char bad_pmd_string[];
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
 
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
-				return page + address;
-			}
-			pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk(bad_pmd_string, pmd_val(*pmd));
-		pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
-		return NULL;
+	free_page((unsigned long)pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
 	}
-	return (pte_t *) pmd_page(*pmd) + address;
+	return (pte_t *)ret;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
-	pmd_val(*pmd) = 0;
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
 }
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+extern __inline__ void free_pte_slow(pte_t *pte)
 {
-	return (pmd_t *) pgd;
+	free_page((unsigned long)pte);
+}
+
+/* We don't use pmd cache, so these are dummy routines */
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
 }
 
-extern inline void pte_free(pte_t * pte)
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
 {
-	free_page((unsigned long) pte);
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+#define pte_free_kernel(pte)    free_pte_fast(pte)
+#define pte_free(pte)           free_pte_fast(pte)
+#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pgd_alloc()             get_pgd_fast()
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_pte_fast();
+		
+		if (!page)
+			return get_pte_kernel_slow(pmd, address);
+		pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
+		return page + address;
+	}
+	if (pmd_bad(*pmd)) {
+		__bad_pte_kernel(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
 }
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
 
-repeat:
 	if (pmd_none(*pmd))
 		goto getnew;
 	if (pmd_bad(*pmd))
 		goto fix;
 	return (pte_t *) (pmd_page(*pmd) + address);
-	
 getnew:
 {
-	unsigned long page = __get_free_page(GFP_KERNEL);
-	if (!pmd_none(*pmd))
-		goto freenew;
+	unsigned long page = (unsigned long) get_pte_fast();
+	
 	if (!page)
-		goto oom;
-	memset((void *) page, 0, PAGE_SIZE);
+		return get_pte_slow(pmd, address);
 	pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
 	return (pte_t *) (page + address);
-freenew:
-	free_page(page);
-	goto repeat;
 }
-
 fix:
-	printk(bad_pmd_string, pmd_val(*pmd));
-oom:
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+	__bad_pte(pmd);
 	return NULL;
 }
 
@@ -473,7 +528,6 @@
  */
 extern inline void pmd_free(pmd_t * pmd)
 {
-	pmd_val(*pmd) = 0;
 }
 
 extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
@@ -481,14 +535,34 @@
 	return (pmd_t *) pgd;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{
-	free_page((unsigned long) pgd);
-}
+#define pmd_free_kernel		pmd_free
+#define pmd_alloc_kernel	pmd_alloc
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-	return (pgd_t *) get_free_page(GFP_KERNEL);
+	struct task_struct * p;
+	pgd_t *pgd;
+#ifdef __SMP__
+	int i;
+#endif	
+        
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+#ifndef __SMP__
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
+#else
+	/* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+	   modify pgd caches of other CPUs as well. -jj */
+	for (i = 0; i < NR_CPUS; i++)
+		for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+			pgd[address >> PGDIR_SHIFT] = entry;
+#endif
 }
 
 extern pgd_t swapper_pg_dir[1024];
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.105/linux/include/asm-i386/processor.h	Wed May 20 19:10:41 1998
+++ linux/include/asm-i386/processor.h	Sat Jun 13 12:48:11 1998
@@ -34,6 +34,9 @@
 	int	fdiv_bug;
 	int	f00f_bug;
 	unsigned long loops_per_sec;
+	unsigned long *pgd_quick;
+	unsigned long *pte_quick;
+	unsigned long pgtable_cache_sz;
 };
 
 #define X86_VENDOR_INTEL 0
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h
--- v2.1.105/linux/include/asm-i386/signal.h	Thu Feb 12 20:56:12 1998
+++ linux/include/asm-i386/signal.h	Tue Jun  9 00:55:10 1998
@@ -72,7 +72,7 @@
 /*
  * SA_FLAGS values:
  *
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ * SA_ONSTACK indicates that a registered stack_t will be used.
  * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
  * SA_RESTART flag to get restarting signals (which were the default long ago)
  * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
@@ -96,6 +96,15 @@
 #define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
 
 #define SA_RESTORER	0x04000000
+
+/* 
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h
--- v2.1.105/linux/include/asm-i386/termios.h	Wed Apr  8 19:36:29 1998
+++ linux/include/asm-i386/termios.h	Mon Jun  8 10:02:35 1998
@@ -47,6 +47,7 @@
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
 #define N_6PACK		7
+#define N_MASC		8	/* Reserved fo Mobitex module <kaz@cafe.net> */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.1.105/linux/include/asm-i386/unistd.h	Thu May  7 22:51:54 1998
+++ linux/include/asm-i386/unistd.h	Tue Jun  9 00:55:10 1998
@@ -191,6 +191,7 @@
 #define __NR_getcwd		183
 #define __NR_capget		184
 #define __NR_capset		185
+#define __NR_sigaltstack	186
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/amifd.h linux/include/asm-m68k/amifd.h
--- v2.1.105/linux/include/asm-m68k/amifd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-m68k/amifd.h	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-#ifndef _ASM_M68K_AMIFD_H
-#define _ASM_M68K_AMIFD_H
-
-/* Definitions for the Amiga floppy driver */
-
-#include <linux/fd.h>
-
-#define FD_MAX_UNITS    4	/* Max. Number of drives */
-#define FLOPPY_MAX_SECTORS	22	/* Max. Number of sectors per track */
-
-#ifndef ASSEMBLER
-
-struct fd_data_type {
-    char *name;			/* description of data type */
-    int sects;			/* sectors per track */
-#ifdef __STDC__
-    int (*read_fkt)(int);
-    void (*write_fkt)(int);
-#else
-    int (*read_fkt)();		/* read whole track */
-    void (*write_fkt)();		/* write whole track */
-#endif
-};
-
-/*
-** Floppy type descriptions
-*/
-
-struct fd_drive_type {
-    unsigned long code;		/* code returned from drive */
-    char *name;			/* description of drive */
-    unsigned int tracks;	/* number of tracks */
-    unsigned int heads;		/* number of heads */
-    unsigned int read_size;	/* raw read size for one track */
-    unsigned int write_size;	/* raw write size for one track */
-    unsigned int sect_mult;	/* sectors and gap multiplier (HD = 2) */
-    unsigned int precomp1;	/* start track for precomp 1 */
-    unsigned int precomp2;	/* start track for precomp 2 */
-    unsigned int step_delay;	/* time (in ms) for delay after step */
-    unsigned int settle_time;	/* time to settle after dir change */
-    unsigned int side_time;	/* time needed to change sides */
-};
-
-struct amiga_floppy_struct {
-    struct fd_drive_type *type;	/* type of floppy for this unit */
-    struct fd_data_type *dtype;	/* type of floppy for this unit */
-    int track;			/* current track (-1 == unknown) */
-    unsigned char *trackbuf;    /* current track (kmaloc()'d */
-
-    int blocks;			/* total # blocks on disk */
-
-    int changed;		/* true when not known */
-    int disk;			/* disk in drive (-1 == unknown) */
-    int motor;			/* true when motor is at speed */
-    int busy;			/* true when drive is active */
-    int dirty;			/* true when trackbuf is not on disk */
-    int status;			/* current error code for unit */
-};
-#endif
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/amifdreg.h linux/include/asm-m68k/amifdreg.h
--- v2.1.105/linux/include/asm-m68k/amifdreg.h	Wed Dec 27 12:46:43 1995
+++ linux/include/asm-m68k/amifdreg.h	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-#ifndef _LINUX_AMIFDREG_H
-#define _LINUX_AMIFDREG_H
-
-/*
-** CIAAPRA bits (read only)
-*/
-
-#define DSKRDY      (0x1<<5)        /* disk ready when low */
-#define DSKTRACK0   (0x1<<4)        /* head at track zero when low */
-#define DSKPROT     (0x1<<3)        /* disk protected when low */
-#define DSKCHANGE   (0x1<<2)        /* low when disk removed */
-
-/*
-** CIAAPRB bits (read/write)
-*/
-
-#define DSKMOTOR    (0x1<<7)        /* motor on when low */
-#define DSKSEL3     (0x1<<6)        /* select drive 3 when low */
-#define DSKSEL2     (0x1<<5)        /* select drive 2 when low */
-#define DSKSEL1     (0x1<<4)        /* select drive 1 when low */
-#define DSKSEL0     (0x1<<3)        /* select drive 0 when low */
-#define DSKSIDE     (0x1<<2)        /* side selection: 0 = upper, 1 = lower */
-#define DSKDIREC    (0x1<<1)        /* step direction: 0=in, 1=out (to trk 0) */
-#define DSKSTEP     (0x1)           /* pulse low to step head 1 track */
-
-/*
-** DSKBYTR bits (read only)
-*/
-
-#define DSKBYT      (1<<15)         /* register contains valid byte when set */
-#define DMAON       (1<<14)         /* disk DMA enabled */
-#define DISKWRITE   (1<<13)         /* disk write bit in DSKLEN enabled */
-#define WORDEQUAL   (1<<12)         /* DSKSYNC register match when true */
-/* bits 7-0 are data */
-
-/*
-** ADKCON/ADKCONR bits
-*/
-
-#ifndef SETCLR
-#define ADK_SETCLR      (1<<15)     /* control bit */
-#endif
-#define ADK_PRECOMP1    (1<<14)     /* precompensation selection */
-#define ADK_PRECOMP0    (1<<13)     /* 00=none, 01=140ns, 10=280ns, 11=500ns */
-#define ADK_MFMPREC     (1<<12)     /* 0=GCR precomp., 1=MFM precomp. */
-#define ADK_WORDSYNC    (1<<10)     /* enable DSKSYNC auto DMA */
-#define ADK_MSBSYNC     (1<<9)      /* when 1, enable sync on MSbit (for GCR) */
-#define ADK_FAST        (1<<8)      /* bit cell: 0=2us (GCR), 1=1us (MFM) */
- 
-/*
-** DSKLEN bits
-*/
-
-#define DSKLEN_DMAEN    (1<<15)
-#define DSKLEN_WRITE    (1<<14)
-
-/*
-** INTENA/INTREQ bits
-*/
-
-#define DSKINDEX    (0x1<<4)        /* DSKINDEX bit */
-
-/*
-** Misc
-*/
- 
-#define MFM_SYNC    0x4489          /* standard MFM sync value */
-
-/* Values for FD_COMMAND */
-#define FD_RECALIBRATE		0x07	/* move to track 0 */
-#define FD_SEEK			0x0F	/* seek track */
-#define FD_READ			0xE6	/* read with MT, MFM, SKip deleted */
-#define FD_WRITE		0xC5	/* write with MT, MFM */
-#define FD_SENSEI		0x08	/* Sense Interrupt Status */
-#define FD_SPECIFY		0x03	/* specify HUT etc */
-#define FD_FORMAT		0x4D	/* format one track */
-#define FD_VERSION		0x10	/* get version code */
-#define FD_CONFIGURE		0x13	/* configure FIFO operation */
-#define FD_PERPENDICULAR	0x12	/* perpendicular r/w mode */
-
-#endif /* _LINUX_AMIFDREG_H */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h
--- v2.1.105/linux/include/asm-m68k/amigahw.h	Tue Feb 17 13:12:48 1998
+++ linux/include/asm-m68k/amigahw.h	Sat Jun 13 13:14:33 1998
@@ -332,4 +332,4 @@
 #define TOD2000_HOUR1_PM	(1<<2)
 #define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
 
-#endif /* __ASMm68k_AMIGAHW_H */
+#endif /* _M68K_AMIGAHW_H */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/amigardb.h linux/include/asm-m68k/amigardb.h
--- v2.1.105/linux/include/asm-m68k/amigardb.h	Wed Dec 27 12:46:44 1995
+++ linux/include/asm-m68k/amigardb.h	Wed Dec 31 16:00:00 1969
@@ -1,126 +0,0 @@
-#ifndef _LINUX_AMIGARDB_H
-#define _LINUX_AMIGARDB_H 1
-
-#define ULONG	u_long
-#define LONG	long
-#define UBYTE	u_char
-
-/* definitions for the Amiga RigidDiskBlock layout, which always starts in 
-   cylinder 0 of a medium. Taken from page 254f of the RKM: Devices */
-
-struct RigidDiskBlock {
-    ULONG   rdb_ID;		/* 4 character identifier */
-    ULONG   rdb_SummedLongs;	/* size of this checksummed structure */
-    LONG    rdb_ChkSum;		/* block checksum (longword sum to zero) */
-    ULONG   rdb_HostID;		/* SCSI Target ID of host */
-    ULONG   rdb_BlockBytes;	/* size of disk blocks */
-    ULONG   rdb_Flags;		/* see below for defines */
-    /* block list heads */
-    ULONG   rdb_BadBlockList;	/* optional bad block list */
-    ULONG   rdb_PartitionList;	/* optional first partition block */
-    ULONG   rdb_FileSysHeaderList; /* optional file system header block */
-    ULONG   rdb_DriveInit;	/* optional drive-specific init code */
-				/* DriveInit(lun,rdb,ior): "C" stk & d0/a0/a1 */
-    ULONG   rdb_Reserved1[6];	/* set to $ffffffff */
-    /* physical drive characteristics */
-    ULONG   rdb_Cylinders;	/* number of drive cylinders */
-    ULONG   rdb_Sectors;	/* sectors per track */
-    ULONG   rdb_Heads;		/* number of drive heads */
-    ULONG   rdb_Interleave;	/* interleave */
-    ULONG   rdb_Park;		/* landing zone cylinder */
-    ULONG   rdb_Reserved2[3];
-    ULONG   rdb_WritePreComp;	/* starting cylinder: write precompensation */
-    ULONG   rdb_ReducedWrite;	/* starting cylinder: reduced write current */
-    ULONG   rdb_StepRate;	/* drive step rate */
-    ULONG   rdb_Reserved3[5];
-    /* logical drive characteristics */
-    ULONG   rdb_RDBBlocksLo;	/* low block of range reserved for hardblocks */
-    ULONG   rdb_RDBBlocksHi;	/* high block of range for these hardblocks */
-    ULONG   rdb_LoCylinder;	/* low cylinder of partitionable disk area */
-    ULONG   rdb_HiCylinder;	/* high cylinder of partitionable data area */
-    ULONG   rdb_CylBlocks;	/* number of blocks available per cylinder */
-    ULONG   rdb_AutoParkSeconds; /* zero for no auto park */
-    ULONG   rdb_HighRDSKBlock;	/* highest block used by RDSK */
-				/* (not including replacement bad blocks) */
-    ULONG   rdb_Reserved4;
-    /* drive identification */
-    char    rdb_DiskVendor[8];
-    char    rdb_DiskProduct[16];
-    char    rdb_DiskRevision[4];
-    char    rdb_ControllerVendor[8];
-    char    rdb_ControllerProduct[16];
-    char    rdb_ControllerRevision[4];
-    ULONG   rdb_Reserved5[10];
-};
-
-#define	IDNAME_RIGIDDISK	0x5244534B	/* 'RDSK' */
-
-#define	RDB_LOCATION_LIMIT	16
-
-#define	RDBFB_LAST	0	/* no disks exist to be configured after */
-#define	RDBFF_LAST	0x01L	/*   this one on this controller */
-#define	RDBFB_LASTLUN	1	/* no LUNs exist to be configured greater */
-#define	RDBFF_LASTLUN	0x02L	/*   than this one at this SCSI Target ID */
-#define	RDBFB_LASTTID	2	/* no Target IDs exist to be configured */
-#define	RDBFF_LASTTID	0x04L	/*   greater than this one on this SCSI bus */
-#define	RDBFB_NORESELECT 3	/* don't bother trying to perform reselection */
-#define	RDBFF_NORESELECT 0x08L	/*   when talking to this drive */
-#define	RDBFB_DISKID	4	/* rdb_Disk... identification valid */
-#define	RDBFF_DISKID	0x10L
-#define	RDBFB_CTRLRID	5	/* rdb_Controller... identification valid */
-#define	RDBFF_CTRLRID	0x20L
-				/* added 7/20/89 by commodore: */
-#define RDBFB_SYNCH	6	/* drive supports scsi synchronous mode */
-#define RDBFF_SYNCH	0x40L	/* CAN BE DANGEROUS TO USE IF IT DOESN'T! */
-
-struct PartitionBlock {
-    ULONG   pb_ID;		/* 4 character identifier */
-    ULONG   pb_SummedLongs;	/* size of this checksummed structure */
-    LONG    pb_ChkSum;		/* block checksum (longword sum to zero) */
-    ULONG   pb_HostID;		/* SCSI Target ID of host */
-    ULONG   pb_Next;		/* block number of the next PartitionBlock */
-    ULONG   pb_Flags;		/* see below for defines */
-    ULONG   pb_Reserved1[2];
-    ULONG   pb_DevFlags;	/* preferred flags for OpenDevice */
-    UBYTE   pb_DriveName[32];	/* preferred DOS device name: BSTR form */
-				/* (not used if this name is in use) */
-    ULONG   pb_Reserved2[15];	/* filler to 32 longwords */
-    ULONG   pb_Environment[17];	/* environment vector for this partition */
-    ULONG   pb_EReserved[15];	/* reserved for future environment vector */
-};
-
-#define	IDNAME_PARTITION	0x50415254	/* 'PART' */
-
-#define	PBFB_BOOTABLE	0	/* this partition is intended to be bootable */
-#define	PBFF_BOOTABLE	1L	/*   (expected directories and files exist) */
-#define	PBFB_NOMOUNT	1	/* do not mount this partition (e.g. manually */
-#define	PBFF_NOMOUNT	2L	/*   mounted, but space reserved here) */
-
-/* this is from <dos/filehandler.h> */
-
-#define DE_TABLESIZE	0	/* minimum value is 11 (includes NumBuffers) */
-#define DE_SIZEBLOCK	1	/* in longwords: standard value is 128 */
-#define DE_SECORG	2	/* not used; must be 0 */
-#define DE_NUMHEADS	3	/* # of heads (surfaces). drive specific */
-#define DE_SECSPERBLK	4	/* not used; must be 1 */
-#define DE_BLKSPERTRACK 5	/* blocks per track. drive specific */
-#define DE_RESERVEDBLKS 6	/* unavailable blocks at start.	 usually 2 */
-#define DE_PREFAC	7	/* not used; must be 0 */
-#define DE_INTERLEAVE	8	/* usually 0 */
-#define DE_LOWCYL	9	/* starting cylinder. typically 0 */
-#define DE_UPPERCYL	10	/* max cylinder.  drive specific */
-#define DE_NUMBUFFERS	11	/* starting # of buffers.  typically 5 */
-#define DE_MEMBUFTYPE	12	/* type of mem to allocate for buffers. */
-#define DE_BUFMEMTYPE	12	/* same as above, better name
-				 * 1 is public, 3 is chip, 5 is fast */
-#define DE_MAXTRANSFER	13	/* Max number bytes to transfer at a time */
-#define DE_MASK		14	/* Address Mask to block out certain memory */
-#define DE_BOOTPRI	15	/* Boot priority for autoboot */
-#define DE_DOSTYPE	16	/* ASCII (HEX) string showing filesystem type;
-				 * 0X444F5300 is old filesystem,
-				 * 0X444F5301 is fast file system */
-#define DE_BAUD		17	/* Baud rate for serial handler */
-#define DE_CONTROL	18	/* Control word for handler/filesystem */
-#define DE_BOOTBLOCKS	19	/* Number of blocks containing boot code */
-
-#endif /* _LINUX_AMIGARDB_H */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h
--- v2.1.105/linux/include/asm-m68k/atari_SCCserial.h	Tue Feb 17 13:12:48 1998
+++ linux/include/asm-m68k/atari_SCCserial.h	Sat Jun 13 13:14:33 1998
@@ -29,8 +29,9 @@
 						 * clock sources */
 
 #define SCC_BAUD_BASE_MVME_PCLK	781250	/* 12.5 MHz */
-#define SCC_BAUD_BASE_BVM	460800	/* 7.3728 MHz */
 #define SCC_BAUD_BASE_MVME	625000	/* 10.000 MHz */
+#define SCC_BAUD_BASE_BVME_PCLK	781250	/* 12.5 MHz */   /* XXX ??? */
+#define SCC_BAUD_BASE_BVME	460800	/* 7.3728 MHz */
 
 /* The SCC configuration structure */
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/atari_mouse.h linux/include/asm-m68k/atari_mouse.h
--- v2.1.105/linux/include/asm-m68k/atari_mouse.h	Mon Mar  4 12:47:32 1996
+++ linux/include/asm-m68k/atari_mouse.h	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-#ifndef _LINUX_ATARI_MOUSE_H
-#define _LINUX_ATARI_MOUSE_H
-
-/*
- * linux/include/linux/atari_mouse.h
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-	char		buttons;
-	short		dx;
-	short		dy;
-	int		ready;
-	int		active;
-	struct wait_queue *wait;
-	struct fasync_struct *fasyncptr;
-};
-
-#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v2.1.105/linux/include/asm-m68k/bitops.h	Tue Feb 17 13:12:48 1998
+++ linux/include/asm-m68k/bitops.h	Sat Jun 13 12:56:46 1998
@@ -210,6 +210,23 @@
 	return res ^ 31;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 /* Bitmap functions for the minix filesystem */
 
 extern __inline__ int
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/blinken.h linux/include/asm-m68k/blinken.h
--- v2.1.105/linux/include/asm-m68k/blinken.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/blinken.h	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,27 @@
+/*
+** asm/blinken.h -- m68k blinkenlights support (currently hp300 only)
+**
+** (c) 1998 Phil Blundell <philb@gnu.org>
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef _M68K_BLINKEN_H
+#define _M68K_BLINKEN_H
+
+#include <asm/setup.h>
+
+#define HP300_LEDS		0xf001ffff
+
+static __inline__ void blinken_leds(int x)
+{
+  if (MACH_IS_HP300)
+  {
+    *((volatile unsigned char *)HP300_LEDS) = (x);
+  }
+}
+
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v2.1.105/linux/include/asm-m68k/bootinfo.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/bootinfo.h	Sat Jun 13 13:14:33 1998
@@ -109,7 +109,7 @@
 #define ATARI_MACH_AB40		3	/* Afterburner040 on Falcon */
 
     /*
-     *  Macintosh-specific tags
+     *  Macintosh-specific tags (all u_long)
      */
 
 #define BI_MAC_MODEL		0x8000	/* Mac Gestalt ID (model type) */
@@ -123,9 +123,37 @@
 #define BI_MAC_GMTBIAS		0x8008	/* Mac GMT timezone offset */
 #define BI_MAC_MEMSIZE		0x8009	/* Mac RAM size (sanity check) */
 #define BI_MAC_CPUID		0x800a	/* Mac CPU type (sanity check) */
+#define BI_MAC_ROMBASE		0x800b	/* Mac system ROM base address */ 
+
+    /*
+     *  Macintosh hardware profile data - unused, see macintosh.h for 
+     *  resonable type values 
+     */
+
+#define BI_MAC_VIA1BASE		0x8010	/* Mac VIA1 base address (always present) */
+#define BI_MAC_VIA2BASE		0x8011	/* Mac VIA2 base address (type varies) */
+#define BI_MAC_VIA2TYPE		0x8012	/* Mac VIA2 type (VIA, RBV, OSS) */
+#define BI_MAC_ADBTYPE		0x8013	/* Mac ADB interface type */
+#define BI_MAC_ASCBASE		0x8014	/* Mac Apple Sound Chip base address */
+#define BI_MAC_SCSI5380		0x8015	/* Mac NCR 5380 SCSI (base address, multi) */
+#define BI_MAC_SCSIDMA		0x8016	/* Mac SCSI DMA (base address) */
+#define BI_MAC_SCSI5396		0x8017	/* Mac NCR 53C96 SCSI (base address, multi) */
+#define BI_MAC_IDETYPE		0x8018	/* Mac IDE interface type */
+#define BI_MAC_IDEBASE		0x8019	/* Mac IDE interface base address */
+#define BI_MAC_NUBUS		0x801a	/* Mac Nubus type (none, regular, pseudo) */
+#define BI_MAC_SLOTMASK		0x801b	/* Mac Nubus slots present */
+#define BI_MAC_SCCTYPE		0x801c	/* Mac SCC serial type (normal, IOP) */
+#define BI_MAC_ETHTYPE		0x801d	/* Mac builtin ethernet type (Sonic, MACE */
+#define BI_MAC_ETHBASE		0x801e	/* Mac builtin ethernet base address */
+#define BI_MAC_PMU		0x801f	/* Mac power managment / poweroff hardware */
+#define BI_MAC_IOP_SWIM		0x8020	/* Mac SWIM floppy IOP */
+#define BI_MAC_IOP_ADB		0x8021	/* Mac ADB IOP */
 
     /*
      * Mac: compatibility with old booter data format (temporarily)
+     * Fields unused with the new bootinfo can be deleted now; instead of
+     * adding new fields the struct might be splitted into a hardware address
+     * part and a hardware type part
      */
 
 #ifndef __ASSEMBLY__
@@ -198,6 +226,7 @@
 #define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
 #define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
 #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
+#define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
 
 
 #ifdef BOOTINFO_COMPAT_1_0
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/bvme6000hw.h linux/include/asm-m68k/bvme6000hw.h
--- v2.1.105/linux/include/asm-m68k/bvme6000hw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/bvme6000hw.h	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,129 @@
+#ifndef _M68K_BVME6000HW_H_
+#define _M68K_BVME6000HW_H_
+
+#include <asm/irq.h>
+
+/*
+ * PIT structure
+ */
+
+#define BVME_PIT_BASE	0xffa00000
+
+typedef struct {
+	unsigned char
+	pad_a[3], pgcr,
+	pad_b[3], psrr,
+	pad_c[3], paddr,
+	pad_d[3], pbddr,
+	pad_e[3], pcddr,
+	pad_f[3], pivr,
+	pad_g[3], pacr,
+	pad_h[3], pbcr,
+	pad_i[3], padr,
+	pad_j[3], pbdr,
+	pad_k[3], paar,
+	pad_l[3], pbar,
+	pad_m[3], pcdr,
+	pad_n[3], psr,
+	pad_o[3], res1,
+	pad_p[3], res2,
+	pad_q[3], tcr,
+	pad_r[3], tivr,
+	pad_s[3], res3,
+	pad_t[3], cprh,
+	pad_u[3], cprm,
+	pad_v[3], cprl,
+	pad_w[3], res4,
+	pad_x[3], crh,
+	pad_y[3], crm,
+	pad_z[3], crl,
+	pad_A[3], tsr,
+	pad_B[3], res5;
+} PitRegs_t, *PitRegsPtr;
+
+#define bvmepit   ((*(volatile PitRegsPtr)(BVME_PIT_BASE)))
+
+#define BVME_RTC_BASE	0xff900000
+
+typedef struct {
+	unsigned char
+	pad_a[3], msr,
+	pad_b[3], t0cr_rtmr,
+	pad_c[3], t1cr_omr,
+	pad_d[3], pfr_icr0,
+	pad_e[3], irr_icr1,
+	pad_f[3], bcd_tenms,
+	pad_g[3], bcd_sec,
+	pad_h[3], bcd_min,
+	pad_i[3], bcd_hr,
+	pad_j[3], bcd_dom,
+	pad_k[3], bcd_mth,
+	pad_l[3], bcd_year,
+	pad_m[3], bcd_ujcc,
+	pad_n[3], bcd_hjcc,
+	pad_o[3], bcd_dow,
+	pad_p[3], t0lsb,
+	pad_q[3], t0msb,
+	pad_r[3], t1lsb,
+	pad_s[3], t1msb,
+	pad_t[3], cmp_sec,
+	pad_u[3], cmp_min,
+	pad_v[3], cmp_hr,
+	pad_w[3], cmp_dom,
+	pad_x[3], cmp_mth,
+	pad_y[3], cmp_dow,
+	pad_z[3], sav_sec,
+	pad_A[3], sav_min,
+	pad_B[3], sav_hr,
+	pad_C[3], sav_dom,
+	pad_D[3], sav_mth,
+	pad_E[3], ram,
+	pad_F[3], test;
+} RtcRegs_t, *RtcPtr_t;
+
+
+#define BVME_I596_BASE	0xff100000
+
+#define BVME_ETHIRQ_REG	0xff20000b
+
+#define BVME_LOCAL_IRQ_STAT  0xff20000f
+
+#define BVME_ETHERR          0x02
+#define BVME_ABORT_STATUS    0x08
+
+#define BVME_NCR53C710_BASE	0xff000000
+
+#define BVME_SCC_A_ADDR	0xffb0000b
+#define BVME_SCC_B_ADDR	0xffb00003
+
+#define BVME_CONFIG_REG	0xff500003
+
+#define config_reg_ptr	(unsigned char *)BVME_CONFIG_REG
+
+#define BVME_CONFIG_SW1	0x08
+#define BVME_CONFIG_SW2	0x04
+#define BVME_CONFIG_SW3	0x02
+#define BVME_CONFIG_SW4	0x01
+
+
+#define BVME_IRQ_TYPE_PRIO	0
+
+#define BVME_IRQ_PRN		0x54
+#define BVME_IRQ_I596		0x1a
+#define BVME_IRQ_SCSI		0x1b
+#define BVME_IRQ_TIMER		0x59
+#define BVME_IRQ_RTC		0x1e
+#define BVME_IRQ_ABORT		0x1f
+
+/* SCC interrupts */
+#define BVME_IRQ_SCC_BASE		0x40
+#define BVME_IRQ_SCCB_TX		0x40
+#define BVME_IRQ_SCCB_STAT		0x42
+#define BVME_IRQ_SCCB_RX		0x44
+#define BVME_IRQ_SCCB_SPCOND		0x46
+#define BVME_IRQ_SCCA_TX		0x48
+#define BVME_IRQ_SCCA_STAT		0x4a
+#define BVME_IRQ_SCCA_RX		0x4c
+#define BVME_IRQ_SCCA_SPCOND		0x4e
+
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h
--- v2.1.105/linux/include/asm-m68k/checksum.h	Sat May  2 14:19:54 1998
+++ linux/include/asm-m68k/checksum.h	Sat Jun 13 13:14:33 1998
@@ -39,6 +39,10 @@
 csum_partial_copy_from_user ( const char *src, char *dst,
 			      int len, int sum, int *csum_err);
 
+/* FIXME: this needs to be written to really do no check -- Cort */
+#define csum_partial_copy_nocheck(src, dst, len, sum)	\
+	csum_partial_copy((src), (dst), (len), (sum))
+
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
  *	which always checksum on 4 octet boundaries.
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.1.105/linux/include/asm-m68k/entry.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/entry.h	Sat Jun 13 13:14:33 1998
@@ -54,7 +54,7 @@
 LTSS_FPCTXT	= 24
 
 /* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI_ONLY) && !defined(CONFIG_HADES)
 	/* block out HSYNC on the atari */
 #define ALLOWINT 0xfbff
 #define	MAX_NOINT_IPL	3
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.1.105/linux/include/asm-m68k/hardirq.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/hardirq.h	Sat Jun 13 13:14:33 1998
@@ -5,6 +5,8 @@
 
 extern unsigned int local_irq_count[NR_CPUS];
 
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
 #define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu) == 0)
 #define hardirq_endlock(cpu)	(--local_irq_count[cpu])
 
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/hwtest.h linux/include/asm-m68k/hwtest.h
--- v2.1.105/linux/include/asm-m68k/hwtest.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/hwtest.h	Sat Jun 13 13:14:33 1998
@@ -0,0 +1,15 @@
+/* Routines to test for presence/absence of hardware registers:
+ * see arch/m68k/mm/hwtest.c.
+ *  -- PMM <pmaydell@chiark.greenend.org.uk> 05/1998
+ *
+ * Removed initfunc from decls.  We might want them in modules, and 
+ * the code is tiny anyway.  16/5/98 pb
+ */
+
+#ifndef __ASM_HWTEST_H
+#define __ASM_HWTEST_H 
+
+extern int hwreg_present(volatile void *regp);
+extern int hwreg_write(volatile void *regp, unsigned short val);
+
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.1.105/linux/include/asm-m68k/ide.h	Thu May  7 22:51:54 1998
+++ linux/include/asm-m68k/ide.h	Sat Jun 13 13:14:33 1998
@@ -41,6 +41,10 @@
 #include <asm/atari_stdma.h>
 #endif
 
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
+
 typedef unsigned char * ide_ioreg_t;
 
 #ifndef MAX_HWIFS
@@ -71,6 +75,10 @@
 	} b;
 	} select_t;
 
+#ifdef CONFIG_MAC	/* MSch: Hack; wrapper for ide_intr */
+void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+#endif
+
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
@@ -78,6 +86,14 @@
 	if (MACH_IS_AMIGA)
 		return request_irq(irq, handler, 0, device, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+	if (MACH_IS_MAC)
+#if 0	/* MSch Hack: maybe later we'll call ide_intr without a wrapper */
+	return nubus_request_irq(12, dev_id, handler);
+#else
+	return nubus_request_irq(12, dev_id, mac_ide_intr);
+#endif
+#endif /* CONFIG_MAC */
 	return 0;
 }
 
@@ -87,6 +103,10 @@
 	if (MACH_IS_AMIGA)
 		free_irq(irq, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+	if (MACH_IS_MAC)
+		nubus_free_irq(12);
+#endif /* CONFIG_MAC */
 }
 
 /*
@@ -117,81 +137,83 @@
 #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
-#define insw(port, buf, nr) \
-    if ((nr) % 16) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/a1@+; \
-		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #4,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 movew %/a0@,%/a1@+; \
-		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "a0", "a1", "d6")
-
-#define outsw(port, buf, nr) \
-    if ((nr) % 16) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/a0@; \
-		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #4,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 movew %/a1@+,%/a0@; \
-		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "a0", "a1", "d6")
+#define insw(port, buf, nr) ({				\
+	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_buf = (buf);			\
+	int _nr = (nr);					\
+	unsigned long _tmp;				\
+							\
+	if (_nr & 15) {					\
+		_tmp = (_nr & 15) - 1;			\
+		asm volatile (				\
+			"1: movew %2@,%3@+; dbra %4,1b"	\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+	_tmp = (_nr >> 4) - 1;				\
+	asm volatile (					\
+		"1: "					\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"movew %2@,%3@+; "			\
+		"dbra %4,1b"				\
+		: "=a" (_buf), "=d" (_tmp)		\
+		: "a" (_port), "0" (_buf),		\
+		  "1" (_tmp));				\
+})
+
+#define outsw(port, buf, nr) ({				\
+	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_buf = (buf);			\
+	int _nr = (nr);					\
+	unsigned long _tmp;				\
+							\
+	if (_nr & 15) {					\
+		_tmp = (_nr & 15) - 1;			\
+		asm volatile (				\
+			"1: movew %3@,%2@+; dbra %4,1b"	\
+			: "=a" (_buf), "=d" (_tmp)	\
+			: "a" (_port), "0" (_buf),	\
+			  "1" (_tmp));			\
+	}						\
+	_tmp = (_nr >> 4) - 1;				\
+	asm volatile (					\
+		"1: "					\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"movew %3@+,%2@; "			\
+		"dbra %4,1b"	   			\
+		: "=a" (_buf), "=d" (_tmp)		\
+		: "a" (_port), "0" (_buf),		\
+		  "1" (_tmp));				\
+})
 
 #ifdef CONFIG_ATARI
 #define insl_swapw(data_reg, buffer, wcount) \
@@ -310,11 +332,11 @@
 #define D_INT(cnt)      (T_INT   | (cnt))
 #define D_TEXT(cnt)     (T_TEXT  | (cnt))
 
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
 static u_short driveid_types[] = {
 	D_SHORT(10),	/* config - vendor2 */
 	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
+	D_SHORT(3),	/* buf_type, buf_size - ecc_bytes */
 	D_TEXT(48),	/* fw_rev - model */
 	D_CHAR(2),	/* max_multsect - vendor3 */
 	D_SHORT(1),	/* dword_io */
@@ -333,12 +355,12 @@
 
 static __inline__ void ide_fix_driveid(struct hd_driveid *id)
 {
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
    u_char *p = (u_char *)id;
    int i, j, cnt;
    u_char t;
 
-   if (!MACH_IS_AMIGA)
+   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
    	return;
    for (i = 0; i < num_driveid_types; i++) {
       cnt = driveid_types[i] & T_MASK_COUNT;
@@ -423,7 +445,7 @@
  * an interrupt, and in that case it does nothing. Hope that is reasonable and
  * works. (Roman)
  */
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA)
+#ifdef CONFIG_ATARI_ONLY
 #define	ide__sti()					\
     do {						\
 	if (!in_interrupt()) __sti();			\
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h
--- v2.1.105/linux/include/asm-m68k/io.h	Mon Feb 23 18:12:11 1998
+++ linux/include/asm-m68k/io.h	Sat Jun 13 13:14:33 1998
@@ -28,9 +28,9 @@
 #define readl(addr) \
     ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
 
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
 
 #define memset_io(a,b,c)	memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/machw.h linux/include/asm-m68k/machw.h
--- v2.1.105/linux/include/asm-m68k/machw.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/machw.h	Sat Jun 13 13:14:33 1998
@@ -100,9 +100,16 @@
 # define via_1         ((*(volatile struct VIA *)VIA1_BAS))
 # define via_2         ((*(volatile struct VIA *)VIA2_BAS))
 # define via1_regp    ((volatile unsigned char *)VIA1_BAS)
-
-# define via2_regp    ((volatile unsigned char *)VIA2_BAS)
-# define via2_ci_regp ((volatile unsigned char *)VIA2_BAS_IIci)
-# define rbv_regp     ((volatile unsigned char *)VIA2_BAS_IIci)
  
+/*
+ * OSS/RBV base address 
+ */
+
+#define OSS_BAS		0x50f1a000
+#define PSC_BAS		0x50f31000
+
+/* move to oss.h?? */
+#define nIFR	0x203
+#define oIFR	0x202
+
 #endif /* linux/machw.h */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h
--- v2.1.105/linux/include/asm-m68k/macintosh.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-m68k/macintosh.h	Sat Jun 13 13:14:33 1998
@@ -76,6 +76,7 @@
 #define MAC_SCC_II		1
 #define MAC_SCC_QUADRA		2
 #define MAC_SCC_QUADRA2		3
+#define MAC_SCC_IOP		4
 
 #define MAC_ETHER_NONE		0	
 #define MAC_ETHER_SONIC		1
@@ -94,6 +95,7 @@
 #define MAC_MODEL_IICI		11
 #define MAC_MODEL_IIFX		13	/* And well numbered it is too */
 #define MAC_MODEL_IISI		18
+#define MAC_MODEL_LC		19
 #define MAC_MODEL_Q900		20
 #define MAC_MODEL_PB170		21
 #define MAC_MODEL_Q700		22
@@ -131,9 +133,11 @@
 #define MAC_MODEL_PB190 	85
 #define MAC_MODEL_TV		88
 #define MAC_MODEL_P475		89	/* aka: LC475, P476 */
+#define MAC_MODEL_P475F		90	/* aka: P475 w/ FPU (no LC040) */
 #define MAC_MODEL_P575		92	/* aka: LC575/580, P577/578/508 */
 #define MAC_MODEL_Q605		94
 #define MAC_MODEL_Q630		98	/* aka: LC630, P630/631/636/640 */
+#define MAC_MODEL_P588		99	/* aka: ?? */
 #define MAC_MODEL_PB280		102
 #define MAC_MODEL_PB280C	103
 #define MAC_MODEL_PB150		115
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h
--- v2.1.105/linux/include/asm-m68k/macints.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-m68k/macints.h	Sat Jun 13 13:14:33 1998
@@ -26,9 +26,9 @@
 
 #define VIA1_SOURCE_BASE	8
 #define VIA2_SOURCE_BASE	16
-#define RBF_SOURCE_BASE		24
+#define RBV_SOURCE_BASE		24
 #define MAC_SCC_SOURCE_BASE	32
-#define NUBUS_SOURCE_BASE	40
+#define NUBUS_SOURCE_BASE	56
 #define NUBUS_MAX_SOURCES	8
 
 /* FIXME: sources not contigous ... */
@@ -42,14 +42,6 @@
  */
 #define	IRQ_IDX(irq)	(irq)
 
-#if 0
-/* convert vector number to int source number */
-#define IRQ_VECTOR_TO_SOURCE(v)	(v)
-
-/* convert irq_handler index to vector number */
-#define IRQ_SOURCE_TO_VECTOR(i)	(i)
-#endif
-
 /* interrupt service types */
 #define IRQ_TYPE_SLOW     0
 #define IRQ_TYPE_FAST     1
@@ -96,6 +88,7 @@
 #define IRQ_VIA2_6	  (22)
 #define IRQ_VIA2_7        (23)
 
+#if 0
 /* RBV interrupts */
 #define IRQ_RBV_0	  (24)
 #define IRQ_RBV_1	  (25)
@@ -105,10 +98,19 @@
 #define IRQ_RBV_5	  (29)
 #define IRQ_RBV_6	  (30)
 #define IRQ_RBV_7	  (31)
+#endif
 
+/* Level 3 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC3_0	  (24)
+#define IRQ_MAC_MACE	  IRQ_PSC3_0
+#define IRQ_PSC3_1	  (25)
+#define IRQ_PSC3_2	  (26)
+#define IRQ_PSC3_3	  (27)
+
+/* Level 4 (SCC) interrupts */
 #define IRQ_SCC 	     (32)
-#define IRQ_SCCB	     (32)
-#define IRQ_SCCA	     (33)
+#define IRQ_SCCB	     (33)
+#define IRQ_SCCA	     (34)
 #if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */
 /* SCC interrupts */
 #define IRQ_SCCB_TX	     (32)
@@ -121,7 +123,27 @@
 #define IRQ_SCCA_SPCOND	     (39)
 #endif
 
-#define IRQ_NUBUS_1	     (40)
+/* Level 4 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC4_0	  (32)
+#define IRQ_PSC4_1	  (33)
+#define IRQ_PSC4_2	  (34)
+#define IRQ_PSC4_3	  (35)
+#define IRQ_MAC_MACE_DMA  IRQ_PSC4_3
+
+/* Level 5 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC5_0	  (40)
+#define IRQ_PSC5_1	  (41)
+#define IRQ_PSC5_2	  (42)
+#define IRQ_PSC5_3	  (43)
+
+/* Level 6 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC6_0	  (48)
+#define IRQ_PSC6_1	  (49)
+#define IRQ_PSC6_2	  (50)
+#define IRQ_PSC6_3	  (51)
+
+/* Nubus interrupts (cascaded to VIA2) */
+#define IRQ_NUBUS_1	  (56)
 
 #define INT_CLK   24576	    /* CLK while int_clk =2.456MHz and divide = 100 */
 #define INT_TICKS 246	    /* to make sched_time = 99.902... HZ */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/mvme16xhw.h linux/include/asm-m68k/mvme16xhw.h
--- v2.1.105/linux/include/asm-m68k/mvme16xhw.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/mvme16xhw.h	Sat Jun 13 13:14:33 1998
@@ -34,37 +34,59 @@
 		spare3,
 		spare4,
 		data;
-} lpr_ctrl;
+} MVMElp, *MVMElpPtr;
 
-#define LPR_REGS	((volatile lpr_ctrl *)0xfff42030)
+#define MVME_LPR_BASE	0xfff42030
 
-#define I596_BASE	0xfff46000
+#define mvmelp   ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
 
-#define SCC_A_ADDR	0xfff45005
-#define SCC_B_ADDR	0xfff45001
-
-#define IRQ_MVME162_TYPE_PRIO	0
-
-#define IRQ_MVME167_PRN		0x54
-#define IRQ_MVME16x_I596	0x57
-#define IRQ_MVME16x_SCSI	0x55
-#define IRQ_MVME16x_FLY		0x7f
-#define IRQ_MVME167_SER_ERR	0x5c
-#define IRQ_MVME167_SER_MODEM	0x5d
-#define IRQ_MVME167_SER_TX	0x5e
-#define IRQ_MVME167_SER_RX	0x5f
-#define IRQ_MVME16x_TIMER	0x59
+typedef struct {
+	unsigned char
+		ctrl,
+		bcd_sec,
+		bcd_min,
+		bcd_hr,
+		bcd_dow,
+		bcd_dom,
+		bcd_mth,
+		bcd_year;
+} MK48T08_t, *MK48T08ptr_t;
+
+#define RTC_WRITE	0x80
+#define RTC_READ	0x40
+#define RTC_STOP	0x20
+
+#define MVME_RTC_BASE	0xfffc1ff8
+
+#define MVME_I596_BASE	0xfff46000
+
+#define MVME_SCC_A_ADDR	0xfff45005
+#define MVME_SCC_B_ADDR	0xfff45001
+
+#define MVME162_IRQ_TYPE_PRIO	0
+                
+#define MVME167_IRQ_PRN		0x54
+#define MVME16x_IRQ_I596	0x57
+#define MVME16x_IRQ_SCSI	0x55
+#define MVME16x_IRQ_FLY		0x7f
+#define MVME167_IRQ_SER_ERR	0x5c
+#define MVME167_IRQ_SER_MODEM	0x5d
+#define MVME167_IRQ_SER_TX	0x5e
+#define MVME167_IRQ_SER_RX	0x5f
+#define MVME16x_IRQ_TIMER	0x59
+#define MVME167_IRQ_ABORT	0x6e
+#define MVME162_IRQ_ABORT	0x5e
 
 /* SCC interrupts, for MVME162 */
-#define IRQ_MVME162_SCC_BASE		0x40
-#define IRQ_MVME162_SCCB_TX		0x40
-#define IRQ_MVME162_SCCB_STAT		0x42
-#define IRQ_MVME162_SCCB_RX		0x44
-#define IRQ_MVME162_SCCB_SPCOND		0x46
-#define IRQ_MVME162_SCCA_TX		0x48
-#define IRQ_MVME162_SCCA_STAT		0x4a
-#define IRQ_MVME162_SCCA_RX		0x4c
-#define IRQ_MVME162_SCCA_SPCOND		0x4e
+#define MVME162_IRQ_SCC_BASE		0x40
+#define MVME162_IRQ_SCCB_TX		0x40
+#define MVME162_IRQ_SCCB_STAT		0x42
+#define MVME162_IRQ_SCCB_RX		0x44
+#define MVME162_IRQ_SCCB_SPCOND		0x46
+#define MVME162_IRQ_SCCA_TX		0x48
+#define MVME162_IRQ_SCCA_STAT		0x4a
+#define MVME162_IRQ_SCCA_RX		0x4c
+#define MVME162_IRQ_SCCA_SPCOND		0x4e
 
 /* MVME162 version register */
 
@@ -85,34 +107,4 @@
 #define MVME16x_CONFIG_GOT_SCCA		0x0400
 #define MVME16x_CONFIG_GOT_SCCB		0x0800
 
-/* Specials for the ethernet driver */
-
-#define CA()		(((struct i596_reg *)dev->base_addr)->ca = 1)
-
-#define MPU_PORT(c,x)	\
-  ((struct i596_reg *)(dev->base_addr))->porthi = ((c) | (u32)(x)) & 0xffff; \
-  ((struct i596_reg *)(dev->base_addr))->portlo = ((c) | (u32)(x)) >> 16
-
-#define SCP_SYSBUS	0x00000054
-
-#define WSWAPrfd(x)	((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)	((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x)	((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)	((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)	((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)	((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x)	((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- */
-#define PORT_RESET	0x00	/* reset 82596 */
-#define PORT_SELFTEST	0x01	/* selftest */
-#define PORT_ALTSCP	0x02	/* alternate SCB address */
-#define PORT_ALTDUMP	0x03	/* Alternate DUMP address */
-
-#define ISCP_BUSY	0x00010000
-
-#endif /* _M68K_MVME16xHW_H_ */
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.1.105/linux/include/asm-m68k/pgtable.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-m68k/pgtable.h	Sat Jun 13 13:14:33 1998
@@ -328,6 +328,16 @@
  * and initialized in head.S */
 extern int m68k_pgtable_cachemode;
 
+/* This is the cache mode for normal pages, for supervisor access on
+ * processors >= '040. It is used in pte_mkcache(), and the variable is
+ * defined and initialized in head.S */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+extern int m68k_supervisor_cachemode;
+#else
+#define m68k_supervisor_cachemode _PAGE_CACHE040
+#endif
+
 #if defined(CPU_M68040_OR_M68060_ONLY)
 #define mm_cachebits _PAGE_CACHE040
 #elif defined(CPU_M68020_OR_M68030_ONLY)
@@ -495,7 +505,7 @@
 	pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
 	return pte;
 }
-extern inline pte_t pte_mkcache(pte_t pte)	{ pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | _PAGE_CACHE040; return pte; }
+extern inline pte_t pte_mkcache(pte_t pte)	{ pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
 
 /* to set the page-dir */
 extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.1.105/linux/include/asm-m68k/processor.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-m68k/processor.h	Sat Jun 13 13:14:33 1998
@@ -19,7 +19,7 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE(off)	0xC0000000UL
+#define TASK_UNMAPPED_BASE	0xC0000000UL
 #define TASK_UNMAPPED_ALIGN(addr, off)	PAGE_ALIGN(addr)
 
 /*
@@ -72,6 +72,9 @@
 {
 }
 
+#define copy_segments(nr, tsk, mm)	do { } while (0)
+#define release_segments(mm)		do { } while (0)
+
 /*
  * Free current thread data structures etc..
  */
@@ -84,19 +87,16 @@
  */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	extern int sys_pause(void);
-	extern void schedule(void);
+	extern void scheduling_functions_start_here(void);
+	extern void scheduling_functions_end_here(void);
 	struct switch_stack *sw = (struct switch_stack *)t->ksp;
 	/* Check whether the thread is blocked in resume() */
-	if (sw->retpc >= (unsigned long)schedule &&
-	    sw->retpc < (unsigned long)sys_pause)
+	if (sw->retpc > (unsigned long)scheduling_functions_start_here &&
+	    sw->retpc < (unsigned long)scheduling_functions_end_here)
 		return ((unsigned long *)sw->a6)[1];
 	else
 		return sw->retpc;
 }
-
-#define copy_segments(nr, tsk, mm)	do { } while (0)
-#define release_segments(mm)		do { } while (0)
 
 /* Allocation and freeing of basic task resources. */
 #define alloc_task_struct() \
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.1.105/linux/include/asm-m68k/serial.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/serial.h	Sat Jun 13 13:14:33 1998
@@ -34,6 +34,8 @@
 #define SER_WHIPPET	108	/* Amiga Hisoft Whippet PCMCIA (16c550B) */
 #define SER_SCC_MVME	109	/* MVME162/MVME172 ports */
 #define SER_SCC_MAC	110	/* Macintosh SCC channel */
+#define SER_HPDCA	111	/* HP DCA serial */
+#define SER_SCC_BVME	112	/* BVME6000 ports */
 
 struct serial_struct {
 	int	type;
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- v2.1.105/linux/include/asm-m68k/setup.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-m68k/setup.h	Sat Jun 13 13:14:33 1998
@@ -38,6 +38,7 @@
 #define MACH_MVME147  6
 #define MACH_MVME16x  7
 #define MACH_BVME6000 8
+#define MACH_HP300    9
 
 #ifdef __KERNEL__
 
@@ -48,10 +49,10 @@
 #if !defined(CONFIG_AMIGA)
 #  define MACH_IS_AMIGA (0)
 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
-#  define MACH_AMIGA_ONLY
+#  define CONFIG_AMIGA_ONLY
 #  define MACH_IS_AMIGA (1)
 #  define MACH_TYPE (MACH_AMIGA)
 #endif
@@ -59,17 +60,18 @@
 #if !defined(CONFIG_ATARI)
 #  define MACH_IS_ATARI (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
-#  define MACH_ATARI_ONLY
+#  define CONFIG_ATARI_ONLY
 #  define MACH_IS_ATARI (1)
 #  define MACH_TYPE (MACH_ATARI)
 #endif
 
 #if !defined(CONFIG_MAC)
 #  define MACH_IS_MAC (0)
-#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
+	|| defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
 #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
 #else
 #  define CONFIG_MAC_ONLY
@@ -86,7 +88,7 @@
 #if !defined (CONFIG_APOLLO)
 #  define MACH_IS_APOLLO (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
 #else
 #  define CONFIG_APOLLO_ONLY
@@ -97,7 +99,7 @@
 #if !defined (CONFIG_MVME16x)
 #  define MACH_IS_MVME16x (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
 #else
 #  define CONFIG_MVME16x_ONLY
@@ -108,7 +110,7 @@
 #if !defined (CONFIG_BVME6000)
 #  define MACH_IS_BVME6000 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
 #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
 #else
 #  define CONFIG_BVME6000_ONLY
@@ -116,6 +118,16 @@
 #  define MACH_TYPE (MACH_BVME6000)
 #endif
 
+#if !defined (CONFIG_HP300)
+#  define MACH_IS_HP300 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+#  define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+#else
+#  define CONFIG_HP300_ONLY
+#  define MACH_IS_HP300 (1)
+#  define MACH_TYPE (MACH_HP300)
+#endif
 
 #ifndef MACH_TYPE
 #  define MACH_TYPE (m68k_machtype)
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h
--- v2.1.105/linux/include/asm-m68k/signal.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-m68k/signal.h	Sat Jun 13 13:14:33 1998
@@ -142,11 +142,18 @@
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
 struct sigaction {
-	__sighandler_t sa_handler;
+	union {
+	  __sighandler_t _sa_handler;
+	  void (*_sa_sigaction)(int, struct siginfo *, void *);
+	} _u;
 	sigset_t sa_mask;
 	unsigned long sa_flags;
 	void (*sa_restorer)(void);
 };
+
+#define sa_handler	_u._sa_handler
+#define sa_sigaction	_u._sa_sigaction
+
 #endif /* __KERNEL__ */
 
 typedef struct sigaltstack {
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/stat.h linux/include/asm-m68k/stat.h
--- v2.1.105/linux/include/asm-m68k/stat.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-m68k/stat.h	Sat Jun 13 13:14:33 1998
@@ -38,6 +38,7 @@
 	unsigned long  __unused5;
 };
 
+#if 0
 typedef struct {
 	unsigned int	major;
 	unsigned int	minor;
@@ -62,6 +63,7 @@
 	unsigned long	st_blksize;
 	unsigned long	__unused4;
 };
+#endif
 
 #define __XSTAT_VER_1		1
 #define __XSTAT_VER_2		2
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.1.105/linux/include/asm-m68k/system.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/system.h	Sat Jun 13 13:14:33 1998
@@ -60,7 +60,7 @@
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
 
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES) && !defined(CONFIG_VME) && !defined(CONFIG_APOLLO)
 /* block out HSYNC on the atari */
 #define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
 #else /* portable version */
diff -u --recursive --new-file v2.1.105/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.1.105/linux/include/asm-m68k/unistd.h	Wed Apr  8 19:36:29 1998
+++ linux/include/asm-m68k/unistd.h	Sat Jun 13 13:14:33 1998
@@ -187,6 +187,9 @@
 #define __NR_pread		180
 #define __NR_pwrite		181
 #define __NR_lchown		182
+#define __NR_getcwd		183
+#define __NR_capget		184
+#define __NR_capset		185
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -u --recursive --new-file v2.1.105/linux/include/asm-mips/bitops.h linux/include/asm-mips/bitops.h
--- v2.1.105/linux/include/asm-mips/bitops.h	Tue Dec 16 12:45:55 1997
+++ linux/include/asm-mips/bitops.h	Sat Jun 13 12:56:46 1998
@@ -372,6 +372,23 @@
 	return __res;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #ifdef __MIPSEB__
 /* For now I steal the Sparc C versions, no need for speed, just need to
  * get it working.
diff -u --recursive --new-file v2.1.105/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.1.105/linux/include/asm-ppc/bitops.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-ppc/bitops.h	Sat Jun 13 12:56:46 1998
@@ -97,6 +97,34 @@
 }
 
 /*
+ * ffs: find first bit set. This is defined the same way as
+ * 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 */
+}
+#endif
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+/*
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
  */
diff -u --recursive --new-file v2.1.105/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.1.105/linux/include/asm-sparc/bitops.h	Thu Apr 23 20:21:38 1998
+++ linux/include/asm-sparc/bitops.h	Sat Jun 13 12:56:46 1998
@@ -182,6 +182,24 @@
 	return result;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
diff -u --recursive --new-file v2.1.105/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.105/linux/include/asm-sparc64/bitops.h	Mon Jan 12 15:15:54 1998
+++ linux/include/asm-sparc64/bitops.h	Sat Jun 13 12:56:47 1998
@@ -186,6 +186,53 @@
 	return result;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#ifdef ULTRA_HAS_POPULATION_COUNT
+
+extern __inline__ unsigned int hweight32(unsigned int w)
+{
+	unsigned int res;
+
+	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
+	return res;
+}
+
+extern __inline__ unsigned int hweight16(unsigned int w)
+{
+	unsigned int res;
+
+	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
+	return res;
+}
+
+extern __inline__ unsigned int hweight8(unsigned int w)
+{
+	unsigned int res;
+
+	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
+	return res;
+}
+
+#else
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif
+
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
diff -u --recursive --new-file v2.1.105/linux/include/linux/adfs_fs.h linux/include/linux/adfs_fs.h
--- v2.1.105/linux/include/linux/adfs_fs.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/adfs_fs.h	Sat Jun 13 13:32:04 1998
@@ -111,30 +111,22 @@
 };
 
 #ifdef __KERNEL__
-
-
 /*
  * Calculate the boot block checksum on an ADFS drive.  Note that this will
  * appear to be correct if the sector contains all zeros, so also check that
  * the disk size is non-zero!!!
  */
- 
 extern inline int adfs_checkbblk(unsigned char *ptr)
 {
-	int i = 511;
-
-	int result = 0;
+	unsigned int result = 0;
+	unsigned char *p = ptr + 511;
 
 	do {
-		result = (result & 0xff) + (result >> 8);
-		result = result + ptr[i];
-		i--;
-	}
-	while (i != 0);
-	
-	result &= 0xff;
-	return result != ptr[511];
-	return 0;
+	        result = (result & 0xff) + (result >> 8);
+        	result = result + *--p;
+	} while (p != ptr);
+
+	return (result & 0xff) != ptr[511];
 }
 
 /* dir.c */
diff -u --recursive --new-file v2.1.105/linux/include/linux/bitops.h linux/include/linux/bitops.h
--- v2.1.105/linux/include/linux/bitops.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/bitops.h	Sat Jun 13 12:56:47 1998
@@ -0,0 +1,72 @@
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int generic_ffs(int x)
+{
+	int r = 1;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff)) {
+		x >>= 16;
+		r += 16;
+	}
+	if (!(x & 0xff)) {
+		x >>= 8;
+		r += 8;
+	}
+	if (!(x & 0xf)) {
+		x >>= 4;
+		r += 4;
+	}
+	if (!(x & 3)) {
+		x >>= 2;
+		r += 2;
+	}
+	if (!(x & 1)) {
+		x >>= 1;
+		r += 1;
+	}
+	return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+extern __inline__ unsigned int generic_hweight32(unsigned int w)
+{
+        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+extern __inline__ unsigned int generic_hweight16(unsigned int w)
+{
+        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+        res = (res & 0x3333) + ((res >> 2) & 0x3333);
+        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+extern __inline__ unsigned int generic_hweight8(unsigned int w)
+{
+        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+        res = (res & 0x33) + ((res >> 2) & 0x33);
+        return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+#include <asm/bitops.h>
+
+
+#endif
diff -u --recursive --new-file v2.1.105/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.1.105/linux/include/linux/blk.h	Fri May  8 23:14:56 1998
+++ linux/include/linux/blk.h	Sat Jun 13 13:48:44 1998
@@ -339,6 +339,15 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
diff -u --recursive --new-file v2.1.105/linux/include/linux/dio.h linux/include/linux/dio.h
--- v2.1.105/linux/include/linux/dio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dio.h	Sat Jun 13 13:14:32 1998
@@ -0,0 +1,204 @@
+/* header file for DIO boards for the HP300 architecture.
+ * Maybe this should handle DIO-II later?
+ * The general structure of this is vaguely based on how
+ * the Amiga port handles Zorro boards.
+ * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ *
+ * The board IDs are from the NetBSD kernel, which for once provided
+ * helpful comments...
+ *
+ * This goes with arch/m68k/hp300/dio.c
+ */
+
+#ifndef _LINUX_DIO_H
+#define _LINUX_DIO_H
+
+/* The DIO boards in a system are distinguished by 'select codes' which 
+ * range from 0-63 (DIO) and 132-255 (DIO-II). 
+ * The DIO board with select code sc is located at physical address 
+ *     0x600000 + sc * 0x10000
+ * So DIO cards cover [0x600000-0x800000); the areas [0x200000-0x400000) and
+ * [0x800000-0x1000000) are for additional space required by things
+ * like framebuffers. [0x400000-0x600000) is for miscellaneous internal I/O.
+ * On Linux, this is currently all mapped into the virtual address space
+ * at 0xf0000000 on bootup.
+ * DIO-II boards are at 0x1000000 + (sc - 132) * 0x400000
+ * which is address range [0x1000000-0x20000000) -- too big to map completely,
+ * so currently we just don't handle DIO-II boards.  It wouldn't be hard to 
+ * do with ioremap() though.
+ */
+#ifdef __KERNEL__
+/* DIO/DIO-II boards all have the following 8bit registers.
+ * These are offsets from the base of the device.
+ */
+#define DIO_IDOFF     0x01                        /* primary device ID */
+#define DIO_IPLOFF    0x03                        /* interrupt priority level */
+#define DIO_SECIDOFF  0x15                        /* secondary device ID */
+#define DIOII_SIZEOFF 0x101                       /* device size, DIO-II only */
+
+/* The internal HPIB device is special; this is its physaddr; its select code is 7. 
+ * The reason why we have to treat it specially is because apparently it's broken:
+ * the device ID isn't consistent/reliable. *sigh*
+ */
+#define DIO_IHPIBADDR 0x47800
+#define DIO_IHPIBSCODE 7
+
+/* If we don't have the internal HPIB defined, then treat select code 7 like
+ * any other. If we *do* have internal HPIB, then we just have to assume that
+ * select code 7 is the internal HPIB regardless of the ID register :-<
+ */
+#define CONFIG_IHPIB /* hack hack : not yet a proper config option */
+#ifdef CONFIG_IHPIB
+#define DIO_ISIHPIB(scode) ((scode) == DIO_IHPIBSCODE)
+#else
+#define DIO_ISIHPIB(scode) 0
+#endif
+
+#define DIO_VIRADDRBASE 0xf0000000                /* vir addr where IOspace is mapped */
+
+#define DIO_BASE                0x600000        /* start of DIO space */
+#define DIO_END                 0x1000000       /* end of DIO space */
+#define DIO_DEVSIZE             0x10000         /* size of a DIO device */
+
+#define DIOII_BASE              0x01000000      /* start of DIO-II space */
+#define DIOII_END               0x20000000      /* end of DIO-II space */
+#define DIOII_DEVSIZE           0x00400000      /* size of a DIO-II device */
+
+/* Highest valid select code. If we add DIO-II support this should become
+ * 256 for everything except HP320, which only has DIO.
+ */
+#define DIO_SCMAX 32                             
+#define DIOII_SCBASE 132 /* lowest DIO-II select code */
+#define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
+
+/* macros to read device IDs, given base address */
+#define DIO_ID(baseaddr) readb((baseaddr) + DIO_IDOFF)
+#define DIO_SECID(baseaddr) readb((baseaddr) + DIO_SECIDOFF)
+
+/* extract the interrupt level */
+#define DIO_IPL(baseaddr) (((readb((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
+
+/* find the size of a DIO-II board's address space.
+ * DIO boards are all fixed length.
+ */
+#define DIOII_SIZE(baseaddr) ((readb((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
+
+/* general purpose macro for both DIO and DIO-II */
+#define DIO_SIZE(scode, base) (DIO_ISDIOII((scode)) ? DIOII_SIZE((base)) : DIO_DEVSIZE)
+
+/* The hardware has primary and secondary IDs; we encode these in a single
+ * int as PRIMARY ID & (SECONDARY ID << 8).
+ * In practice this is only important for framebuffers,
+ * and everybody else just sets ID fields equal to the DIO_ID_FOO value.
+ */
+#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) & ((int)pr & 0xff))
+/* macro to determine whether a given primary ID requires a secondary ID byte */
+#define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+
+/* Now a whole slew of macros giving device IDs and descriptive strings: */
+#define DIO_ID_DCA0     0x02 /* 98644A serial */
+#define DIO_DESC_DCA0 "98644A DCA0 serial"
+#define DIO_ID_DCA0REM  0x82 /* 98644A serial */
+#define DIO_DESC_DCA0REM "98644A DCA0REM serial"
+#define DIO_ID_DCA1     0x42 /* 98644A serial */
+#define DIO_DESC_DCA1 "98644A DCA1 serial"
+#define DIO_ID_DCA1REM  0xc2 /* 98644A serial */
+#define DIO_DESC_DCA1REM "98644A DCA1REM serial"
+#define DIO_ID_DCM      0x05 /* 98642A serial MUX */
+#define DIO_DESC_DCM "98642A DCM serial MUX"
+#define DIO_ID_DCMREM   0x85 /* 98642A serial MUX */
+#define DIO_DESC_DCMREM "98642A DCMREM serial MUX"
+#define DIO_ID_LAN      0x15 /* 98643A LAN */
+#define DIO_DESC_LAN "98643A LAN"
+#define DIO_ID_FHPIB    0x08 /* 98625A/98625B fast HP-IB */
+#define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
+#define DIO_ID_NHPIB    0x80 /* 98624A HP-IB (normal ie slow) */
+#define DIO_DESC_NHPIB "98624A HPIB"
+#define DIO_ID_IHPIB    0x00 /* internal HPIB (not its real ID, it hasn't got one! */
+#define DIO_DESC_IHPIB "internal HPIB"
+#define DIO_ID_SCSI0    0x07 /* 98625A SCSI */
+#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI1    0x27 /* ditto */
+#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_ID_SCSI2    0x47 /* ditto */
+#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_ID_SCSI3    0x67 /* ditto */
+#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_ID_FBUFFER  0x39 /* framebuffer: flavour is distinguished by secondary ID */
+#define DIO_DESC_FBUFFER "bitmapped display"
+/* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
+#define DIO_ID_MISC0    0x03 /* 98622A */
+#define DIO_DESC_MISC0 "98622A"
+#define DIO_ID_MISC1    0x04 /* 98623A */
+#define DIO_DESC_MISC1 "98623A"
+#define DIO_ID_PARALLEL 0x06 /* internal parallel */
+#define DIO_DESC_PARALLEL "internal parallel"
+#define DIO_ID_MISC2    0x09 /* 98287A keyboard */
+#define DIO_DESC_MISC2 "98287A keyboard"
+#define DIO_ID_MISC3    0x0a /* HP98635A FP accelerator */
+#define DIO_DESC_MISC3 "HP98635A FP accelerator"
+#define DIO_ID_MISC4    0x0b /* timer */
+#define DIO_DESC_MISC4 "timer"
+#define DIO_ID_MISC5    0x12 /* 98640A */
+#define DIO_DESC_MISC5 "98640A"
+#define DIO_ID_MISC6    0x16 /* 98659A */
+#define DIO_DESC_MISC6 "98659A"
+#define DIO_ID_MISC7    0x19 /* 237 display */
+#define DIO_DESC_MISC7 "237 display"
+#define DIO_ID_MISC8    0x1a /* quad-wide card */
+#define DIO_DESC_MISC8 "quad-wide card"
+#define DIO_ID_MISC9    0x1b /* 98253A */
+#define DIO_DESC_MISC9 "98253A"
+#define DIO_ID_MISC10   0x1c /* 98627A */
+#define DIO_DESC_MISC10 "98253A"
+#define DIO_ID_MISC11   0x1d /* 98633A */
+#define DIO_DESC_MISC11 "98633A"
+#define DIO_ID_MISC12   0x1e /* 98259A */
+#define DIO_DESC_MISC12 "98259A"
+#define DIO_ID_MISC13   0x1f /* 8741 */
+#define DIO_DESC_MISC13 "8741"
+#define DIO_ID_VME      0x31 /* 98577A VME adapter */
+#define DIO_DESC_VME "98577A VME adapter"
+#define DIO_ID_DCL      0x34 /* 98628A serial */
+#define DIO_DESC_DCL "98628A DCL serial"
+#define DIO_ID_DCLREM   0xb4 /* 98628A serial */
+#define DIO_DESC_DCLREM "98628A DCLREM serial"
+/* These are the secondary IDs for the framebuffers */
+#define DIO_ID2_GATORBOX    0x01 /* 98700/98710 "gatorbox" */
+#define DIO_DESC2_GATORBOX       "98700/98710 \"gatorbox\" display"
+#define DIO_ID2_TOPCAT      0x02 /* 98544/98545/98547 "topcat" */
+#define DIO_DESC2_TOPCAT         "98544/98545/98547 \"topcat\" display"
+#define DIO_ID2_RENAISSANCE 0x04 /* 98720/98721 "renaissance" */
+#define DIO_DESC2_RENAISSANCE    "98720/98721 \"renaissance\" display"
+#define DIO_ID2_LRCATSEYE   0x05 /* lowres "catseye" */
+#define DIO_DESC2_LRCATSEYE      "low-res catseye display"
+#define DIO_ID2_HRCCATSEYE  0x06 /* highres colour "catseye" */
+#define DIO_DESC2_HRCCATSEYE     "high-res color catseye display"
+#define DIO_ID2_HRMCATSEYE  0x07 /* highres mono "catseye" */
+#define DIO_DESC2_HRMCATSEYE     "high-res mono catseye display"
+#define DIO_ID2_DAVINCI     0x08 /* 98730/98731 "davinci" */
+#define DIO_DESC2_DAVINCI        "98730/98731 \"davinci\" display"
+#define DIO_ID2_XXXCATSEYE  0x09 /* "catseye" */
+#define DIO_DESC2_XXXCATSEYE     "catseye display"
+#define DIO_ID2_HYPERION    0x0e /* A1096A "hyperion" */
+#define DIO_DESC2_HYPERION       "A1096A \"hyperion\" display"
+#define DIO_ID2_XGENESIS    0x0b /* "x-genesis"; no NetBSD support */
+#define DIO_DESC2_XGENESIS       "\"x-genesis\" display"
+#define DIO_ID2_TIGER       0x0c /* "tiger"; no NetBSD support */
+#define DIO_DESC2_TIGER          "\"tiger\" display"
+#define DIO_ID2_YGENESIS    0x0d /* "y-genesis"; no NetBSD support */
+#define DIO_DESC2_YGENESIS       "\"y-genesis\" display"
+/* if you add new IDs then you should tell dio.c about them so it can
+ * identify them...
+ */
+
+extern void dio_init(void);
+extern int dio_find(int deviceid);
+extern void *dio_scodetoviraddr(int scode);
+extern int dio_scodetoipl(int scode);
+extern void dio_config_board(int scode);
+extern void dio_unconfig_board(int scode);
+
+
+#endif /* __KERNEL__ */
+#endif /* ndef _LINUX_DIO_H */
diff -u --recursive --new-file v2.1.105/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.1.105/linux/include/linux/if_ether.h	Sun Feb  2 05:18:47 1997
+++ linux/include/linux/if_ether.h	Mon Jun  8 10:02:35 1998
@@ -72,6 +72,7 @@
 #define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
 #define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
 #define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
+#define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
 
 /*
  *	This is an Ethernet frame header.
diff -u --recursive --new-file v2.1.105/linux/include/linux/in_route.h linux/include/linux/in_route.h
--- v2.1.105/linux/include/linux/in_route.h	Tue Mar 10 10:03:35 1998
+++ linux/include/linux/in_route.h	Thu Jun 11 22:52:33 1998
@@ -18,7 +18,6 @@
 #define RTCF_MASQ	0x00400000
 #define RTCF_SNAT	0x00800000
 #define RTCF_DOREDIRECT 0x01000000
-#define RTCF_LOG	0x02000000
 #define RTCF_DIRECTSRC	0x04000000
 #define RTCF_DNAT	0x08000000
 #define RTCF_BROADCAST	0x10000000
diff -u --recursive --new-file v2.1.105/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.1.105/linux/include/linux/iso_fs.h	Thu Feb 12 20:56:13 1998
+++ linux/include/linux/iso_fs.h	Sat Jun 13 13:39:16 1998
@@ -182,6 +182,7 @@
 extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
 
 int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
 /* The stuff that follows may be totally unneeded. I have not checked to see 
  which prototypes we are still using.  */
@@ -227,6 +228,3 @@
 #endif /* __KERNEL__ */
 
 #endif
-
-
-
diff -u --recursive --new-file v2.1.105/linux/include/linux/iso_fs_sb.h linux/include/linux/iso_fs_sb.h
--- v2.1.105/linux/include/linux/iso_fs_sb.h	Thu Feb 12 20:56:13 1998
+++ linux/include/linux/iso_fs_sb.h	Sat Jun 13 13:39:16 1998
@@ -30,10 +30,3 @@
 };
 
 #endif
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.1.105/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.1.105/linux/include/linux/minix_fs.h	Tue Jan  6 12:26:59 1998
+++ linux/include/linux/minix_fs.h	Sat Jun 13 13:25:12 1998
@@ -15,6 +15,7 @@
 
 /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
 #define MINIX_LINK_MAX	250
+#define MINIX2_LINK_MAX	65530
 
 #define MINIX_I_MAP_SLOTS	8
 #define MINIX_Z_MAP_SLOTS	64
@@ -126,6 +127,7 @@
 extern struct inode_operations minix_file_inode_operations;
 extern struct inode_operations minix_dir_inode_operations;
 extern struct inode_operations minix_symlink_inode_operations;
+extern struct dentry_operations minix_dentry_operations;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.105/linux/include/linux/minix_fs_sb.h linux/include/linux/minix_fs_sb.h
--- v2.1.105/linux/include/linux/minix_fs_sb.h	Fri Jan 23 18:10:32 1998
+++ linux/include/linux/minix_fs_sb.h	Sat Jun 13 13:25:12 1998
@@ -12,8 +12,9 @@
 			unsigned long s_firstdatazone;
 			unsigned long s_log_zone_size;
 			unsigned long s_max_size;
-			unsigned long s_dirsize;
-			unsigned long s_namelen;
+			int s_dirsize;
+			int s_namelen;
+			int s_link_max;
 			struct buffer_head ** s_imap;
 			struct buffer_head ** s_zmap;
 			struct buffer_head * s_sbh;
diff -u --recursive --new-file v2.1.105/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.105/linux/include/linux/mm.h	Wed Apr  8 19:36:29 1998
+++ linux/include/linux/mm.h	Sat Jun 13 13:48:23 1998
@@ -290,6 +290,7 @@
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern void check_pgt_cache(void);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long start_mem, unsigned long end_mem);
@@ -299,13 +300,14 @@
 
 /* mmap.c */
 extern void vma_init(void);
-extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags, unsigned long off);
 extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
 extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void exit_mmap(struct mm_struct *);
-extern int do_munmap(unsigned long, size_t);
 extern unsigned long get_unmapped_area(unsigned long, unsigned long);
+
+extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
+	unsigned long, unsigned long, unsigned long);
+extern int do_munmap(unsigned long, size_t);
 
 /* filemap.c */
 extern unsigned long page_unuse(unsigned long);
diff -u --recursive --new-file v2.1.105/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.105/linux/include/linux/netdevice.h	Sat May  2 14:19:54 1998
+++ linux/include/linux/netdevice.h	Sat Jun 13 13:49:23 1998
@@ -253,6 +253,7 @@
 	
 	void 			*atalk_ptr;	/* Appletalk link 	*/
 	void			*ip_ptr;	/* IPv4 specific data	*/  
+	void                    *dn_ptr;        /* DECnet specific data */
 
 	struct Qdisc		*qdisc;
 	struct Qdisc		*qdisc_sleeping;
diff -u --recursive --new-file v2.1.105/linux/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h
--- v2.1.105/linux/include/linux/nfsd/nfsd.h	Fri Feb  6 15:34:24 1998
+++ linux/include/linux/nfsd/nfsd.h	Sat Jun 13 13:50:34 1998
@@ -60,6 +60,7 @@
 };
 typedef int		(*encode_dent_fn)(struct readdir_cd *, const char *,
 						int, off_t, ino_t);
+typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
 
 /*
  * Procedure table for NFSv2
@@ -72,6 +73,8 @@
  */
 int		nfsd_svc(unsigned short port, int nrservs);
 
+/* nfsd/vfs.c */
+int		fh_lock_parent(struct svc_fh *, struct dentry *);
 void		nfsd_racache_init(void);
 int		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
 				const char *, int, struct svc_fh *);
diff -u --recursive --new-file v2.1.105/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.1.105/linux/include/linux/parport.h	Tue Jun  9 11:57:31 1998
+++ linux/include/linux/parport.h	Sat Jun 13 12:56:47 1998
@@ -106,6 +106,11 @@
 	void (*release_resources)(struct parport *);
 	int (*claim_resources)(struct parport *);
 
+	void (*epp_write_data)(struct parport *, unsigned char);
+	unsigned char (*epp_read_data)(struct parport *);
+	void (*epp_write_addr)(struct parport *, unsigned char);
+	unsigned char (*epp_read_addr)(struct parport *);
+	int (*epp_check_timeout)(struct parport *);
 	size_t (*epp_write_block)(struct parport *, void *, size_t);
 	size_t (*epp_read_block)(struct parport *, void *, size_t);
 
@@ -330,6 +335,11 @@
 #define parport_change_mode(p,m)           parport_pc_change_mode(p,m)
 #define parport_release_resources(p)       parport_pc_release_resources(p)
 #define parport_claim_resources(p)         parport_pc_claim_resources(p)
+#define parport_epp_write_data(p,x)        parport_pc_write_epp(p,x)
+#define parport_epp_read_data(p)           parport_pc_read_epp(p)
+#define parport_epp_write_addr(p,x)        parport_pc_write_epp_addr(p,x)
+#define parport_epp_read_addr(p)           parport_pc_read_epp_addr(p)
+#define parport_epp_check_timeout(p)       parport_pc_check_epp_timeout(p)
 #endif
 
 #ifdef PARPORT_NEED_GENERIC_OPS
@@ -349,6 +359,11 @@
 #define parport_change_mode(p,m)           (p)->ops->change_mode(p,m)
 #define parport_release_resources(p)       (p)->ops->release_resources(p)
 #define parport_claim_resources(p)         (p)->ops->claim_resources(p)
+#define parport_epp_write_data(p,x)        (p)->ops->epp_write_data(p,x)
+#define parport_epp_read_data(p)           (p)->ops->epp_read_data(p)
+#define parport_epp_write_addr(p,x)        (p)->ops->epp_write_addr(p,x)
+#define parport_epp_read_addr(p)           (p)->ops->epp_read_addr(p)
+#define parport_epp_check_timeout(p)       (p)->ops->epp_check_timeout(p)
 #endif
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.105/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.1.105/linux/include/linux/parport_pc.h	Tue Jun  9 11:57:31 1998
+++ linux/include/linux/parport_pc.h	Sat Jun 13 12:56:47 1998
@@ -8,19 +8,41 @@
 #define ECONTROL 0x402
 #define CONFIGB  0x401
 #define CONFIGA  0x400
-#define EPPREG   0x4
+#define EPPDATA  0x4
+#define EPPADDR  0x3
 #define CONTROL  0x2
 #define STATUS   0x1
 #define DATA     0
 
+extern int parport_pc_epp_clear_timeout(struct parport *pb);
+
+
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPREG);
+	outb(d, p->base+EPPDATA);
 }
 
 extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPREG);
+	return inb(p->base+EPPDATA);
+}
+
+extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+	outb(d, p->base+EPPADDR);
+}
+
+extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+	return inb(p->base+EPPADDR);
+}
+
+extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
+{
+	if (!(inb(p->base+STATUS) & 1))
+		return 0;
+	parport_pc_epp_clear_timeout(p);
+	return 1;
 }
 
 extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
diff -u --recursive --new-file v2.1.105/linux/include/linux/pg.h linux/include/linux/pg.h
--- v2.1.105/linux/include/linux/pg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/pg.h	Sat Jun 13 12:08:20 1998
@@ -0,0 +1,63 @@
+/* 	pg.h (c) 1998  Grant R. Guenther <grant@torque.net>
+ 		       Under the terms of the GNU public license
+
+
+	pg.h defines the user interface to the generic ATAPI packet
+        command driver for parallel port ATAPI devices (pg). The
+	driver is loosely modelled after the generic SCSI driver, sg,
+	although the actual interface is different.
+
+	The pg driver provides a simple character device interface for
+        sending ATAPI commands to a device.  With the exception of the
+	ATAPI reset operation, all operations are performed by a pair
+        of read and write operations to the appropriate /dev/pgN device.
+	A write operation delivers a command and any outbound data in
+        a single buffer.  Normally, the write will succeed unless the
+        device is offline or malfunctioning, or there is already another
+	command pending.  If the write succeeds, it should be followed
+        immediately by a read operation, to obtain any returned data and
+        status information.  A read will fail if there is no operation
+        in progress.
+
+	As a special case, the device can be reset with a write operation,
+        and in this case, no following read is expected, or permitted.
+
+	There are no ioctl() operations.  Any single operation
+	may transfer at most PG_MAX_DATA bytes.  Note that the driver must
+        copy the data through an internal buffer.  In keeping with all
+	current ATAPI devices, command packets are assumed to be exactly
+	12 bytes in length.
+
+	To permit future changes to this interface, the headers in the
+	read and write buffers contain a single character "magic" flag.
+        Currently this flag must be the character "P".
+
+*/
+
+#define PG_MAGIC	'P'
+#define PG_RESET	'Z'
+#define PG_COMMAND	'C'
+
+#define PG_MAX_DATA	32768
+
+struct pg_write_hdr {
+
+	char	magic;		/* == PG_MAGIC */
+	char	func;		/* PG_RESET or PG_COMMAND */
+	int     dlen;		/* number of bytes expected to transfer */
+	int     timeout;	/* number of seconds before timeout */
+	char	packet[12];	/* packet command */
+
+};
+
+struct pg_read_hdr {
+
+	char	magic;		/* == PG_MAGIC */
+	char	scsi;		/* "scsi" status == sense key */
+	int	dlen;		/* size of device transfer request */
+	int     duration;	/* time in seconds command took */
+	char    pad[12];	/* not used */
+
+};
+
+/* end of pg.h */
diff -u --recursive --new-file v2.1.105/linux/include/linux/poll.h linux/include/linux/poll.h
--- v2.1.105/linux/include/linux/poll.h	Tue Mar 10 10:03:35 1998
+++ linux/include/linux/poll.h	Sat Jun 13 13:49:01 1998
@@ -79,8 +79,8 @@
 	if (ufdset) {
 		int error;
 		error = verify_area(VERIFY_WRITE, ufdset, nr);
-		if (!error)
-			error = __copy_from_user(fdset, ufdset, nr);
+		if (!error && __copy_from_user(fdset, ufdset, nr))
+			error = -EFAULT;
 		return error;
 	}
 	memset(fdset, 0, nr);
diff -u --recursive --new-file v2.1.105/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.105/linux/include/linux/proc_fs.h	Thu May 14 19:47:43 1998
+++ linux/include/linux/proc_fs.h	Sat Jun 13 13:48:33 1998
@@ -49,6 +49,7 @@
 	PROC_SLABINFO,
 	PROC_PARPORT,
 	PROC_PPC_HTAB,
+	PROC_STRAM,
 	PROC_SOUND,
 	PROC_MTRR, /* whether enabled or not */
 	PROC_FS
diff -u --recursive --new-file v2.1.105/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.1.105/linux/include/linux/rtnetlink.h	Sat May  2 14:19:54 1998
+++ linux/include/linux/rtnetlink.h	Sat Jun 13 11:40:31 1998
@@ -658,7 +658,7 @@
 	atomic_dec(&rtnl_rlockct);
 	if (atomic_read(&rtnl_rlockct) <= 1) {
 		wake_up(&rtnl_wait);
-		if (rtnl->receive_queue.qlen)
+		if (rtnl && rtnl->receive_queue.qlen)
 			rtnl->data_ready(rtnl, 0);
 	}
 }
@@ -672,7 +672,7 @@
 	atomic_dec(&rtnl_rlockct); \
 	if (atomic_read(&rtnl_rlockct) <= 1) { \
 		wake_up(&rtnl_wait); \
-		if (rtnl->receive_queue.qlen) \
+		if (rtnl && rtnl->receive_queue.qlen) \
 			rtnl->data_ready(rtnl, 0); \
 	} \
 })
diff -u --recursive --new-file v2.1.105/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.105/linux/include/linux/sched.h	Sun Jun  7 11:16:39 1998
+++ linux/include/linux/sched.h	Sat Jun 13 13:48:22 1998
@@ -284,6 +284,8 @@
 	struct signal_struct *sig;
 	sigset_t signal, blocked;
 	struct signal_queue *sigqueue, **sigqueue_tail;
+	unsigned long sas_ss_sp;
+	size_t sas_ss_size;
 /* SMP state */
 	int has_cpu;
 	int processor;
@@ -365,6 +367,7 @@
 /* files */	&init_files, \
 /* mm */	&init_mm, \
 /* signals */	&init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, \
+		0, 0, \
 /* SMP */	0,0,0,0, \
 /* locks */	INIT_LOCKS \
 }
@@ -480,6 +483,7 @@
 extern int kill_proc(pid_t, int, int);
 extern int do_sigaction(int sig, const struct k_sigaction *act,
 			struct k_sigaction *oact);
+extern int do_sigaltstack(const stack_t *ss, stack_t *oss, unsigned long sp);
 
 extern inline int signal_pending(struct task_struct *p)
 {
@@ -517,6 +521,19 @@
 	t->sigpending = (ready != 0);
 }
 
+/* True if we are on the alternate signal stack.  */
+
+static inline int on_sig_stack(unsigned long sp)
+{
+	return (sp >= current->sas_ss_sp
+		&& sp < current->sas_ss_sp + current->sas_ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+	return (current->sas_ss_size == 0 ? SS_DISABLE
+		: on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
 
 extern int request_irq(unsigned int irq,
 		       void (*handler)(int, void *, struct pt_regs *),
diff -u --recursive --new-file v2.1.105/linux/include/linux/signal.h linux/include/linux/signal.h
--- v2.1.105/linux/include/linux/signal.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/signal.h	Sat Jun 13 13:08:19 1998
@@ -162,6 +162,8 @@
 	}
 }
 
+extern char * render_sigset_t(sigset_t *set, char *buffer);
+
 /* Some extensions for manipulating the low 32 signals in particular.  */
 
 extern inline void sigaddsetmask(sigset_t *set, unsigned long mask)
diff -u --recursive --new-file v2.1.105/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.1.105/linux/include/linux/swap.h	Wed Apr  8 19:36:29 1998
+++ linux/include/linux/swap.h	Sat Jun 13 13:28:33 1998
@@ -75,6 +75,11 @@
 void si_swapinfo(struct sysinfo *);
 unsigned long get_swap_page(void);
 extern void FASTCALL(swap_free(unsigned long));
+struct swap_list_t {
+	int head;	/* head of priority-ordered swapfile list */
+	int next;	/* swapfile to be used next */
+};
+extern struct swap_list_t swap_list;
 
 /*
  * vm_ops not present page codes for shared memory.
diff -u --recursive --new-file v2.1.105/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.105/linux/include/linux/sysctl.h	Fri May  8 23:14:57 1998
+++ linux/include/linux/sysctl.h	Sat Jun 13 12:48:11 1998
@@ -80,7 +80,8 @@
 	VM_OVERCOMMIT_MEMORY,	/* Turn off the virtual memory safety limit */
 	VM_BUFFERMEM,		/* struct: Set buffer memory thresholds */
 	VM_PAGECACHE,		/* struct: Set cache memory thresholds */
-	VM_PAGERDAEMON		/* struct: Control kswapd behaviour */
+	VM_PAGERDAEMON,		/* struct: Control kswapd behaviour */
+	VM_PGT_CACHE		/* struct: Set page table cache parameters */
 };
 
 
diff -u --recursive --new-file v2.1.105/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.1.105/linux/include/linux/timer.h	Thu Mar 26 15:57:06 1998
+++ linux/include/linux/timer.h	Sat Jun 13 11:45:10 1998
@@ -71,4 +71,22 @@
 	timer->prev = NULL;
 }
 
+/*
+ *	These inlines deal with timer wrapping correctly. You are 
+ *	strongly encouraged to use them
+ *	1. Because people otherwise forget
+ *	2. Because if the timer wrap changes in future you wont have to
+ *	   alter your driver code.
+ */
+
+extern inline int time_before(unsigned long a, unsigned long b)
+{
+	return((long)((a) - (b)) < 0L);
+}
+
+extern inline int time_after(unsigned long a, unsigned long b)
+{
+	return((long)((a) - (b)) > 0L);
+}
+
 #endif
diff -u --recursive --new-file v2.1.105/linux/include/linux/utsname.h linux/include/linux/utsname.h
--- v2.1.105/linux/include/linux/utsname.h	Wed Dec  1 04:44:15 1993
+++ linux/include/linux/utsname.h	Sat Jun 13 11:45:09 1998
@@ -32,4 +32,5 @@
 
 extern struct new_utsname system_utsname;
 
+extern struct semaphore uts_sem;
 #endif
diff -u --recursive --new-file v2.1.105/linux/include/linux/vmalloc.h linux/include/linux/vmalloc.h
--- v2.1.105/linux/include/linux/vmalloc.h	Wed Apr  1 20:11:54 1998
+++ linux/include/linux/vmalloc.h	Sat Jun 13 13:48:23 1998
@@ -20,20 +20,5 @@
 void vmfree_area_pages(unsigned long address, unsigned long size);
 int vmalloc_area_pages(unsigned long address, unsigned long size);
 
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-#if !defined(__mc68000__) && !defined(__sparc_v9__)
-	struct task_struct * p;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-#endif
-}
-
 #endif
 
diff -u --recursive --new-file v2.1.105/linux/include/linux/zorro.h linux/include/linux/zorro.h
--- v2.1.105/linux/include/linux/zorro.h	Sun Jun  7 11:16:39 1998
+++ linux/include/linux/zorro.h	Mon Jun  8 11:03:50 1998
@@ -87,7 +87,7 @@
 #define ZORRO_ID(manuf, prod, epc) \
     ((ZORRO_MANUF_##manuf << 16) | ((prod) << 8) | (epc))
 
-typedef u32 zorro_id;
+typedef __u32 zorro_id;
 
 
 #define ZORRO_MANUF_PACIFIC_PERIPHERALS				0x00D3
@@ -462,6 +462,9 @@
 #define ZORRO_MANUF_ARMAX					0x0885
 #define  ZORRO_PROD_ARMAX_OMNIBUS				ZORRO_ID(ARMAX, 0x00, 0)
 
+#define ZORRO_MANUF_ZEUS					0x088d
+#define  ZORRO_PROD_ZEUS_SPIDER					ZORRO_ID(ZEUS, 0x04, 0)
+
 #define ZORRO_MANUF_NEWTEK					0x088F
 #define  ZORRO_PROD_NEWTEK_VIDEOTOASTER				ZORRO_ID(NEWTEK, 0x00, 0)
 
@@ -558,6 +561,7 @@
 #define  ZORRO_PROD_PHASE5_CYBERVISION64_3D_PROTOTYPE		ZORRO_ID(PHASE5, 0x32, 0)
 #define  ZORRO_PROD_PHASE5_CYBERVISION64_3D			ZORRO_ID(PHASE5, 0x43, 0)
 #define  ZORRO_PROD_PHASE5_CYBERSTORM_MK_III			ZORRO_ID(PHASE5, 0x64, 0)
+#define  ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS			ZORRO_ID(PHASE5, 0x6e, 0)
 
 #define ZORRO_MANUF_DPS						0x2169
 #define  ZORRO_PROD_DPS_PERSONAL_ANIMATION_RECORDER		ZORRO_ID(DPS, 0x01, 0)
@@ -576,6 +580,9 @@
 
 #define ZORRO_MANUF_UWE_GERLACH					0x3FF7
 #define  ZORRO_PROD_UWE_GERLACH_RAM_ROM				ZORRO_ID(UWE_GERLACH, 0xd4, 0)
+
+#define ZORRO_MANUF_ACT						0x4231
+#define  ZORRO_PROD_ACT_PRELUDE					ZORRO_ID(ACT, 0x01, 0)
 
 #define ZORRO_MANUF_MACROSYSTEMS_GERMANY			0x4754
 #define  ZORRO_PROD_MACROSYSTEMS_MAESTRO			ZORRO_ID(MACROSYSTEMS_GERMANY, 0x03, 0)
diff -u --recursive --new-file v2.1.105/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.105/linux/include/net/tcp.h	Thu May  7 22:51:55 1998
+++ linux/include/net/tcp.h	Sat Jun 13 13:51:26 1998
@@ -654,17 +654,24 @@
 	return mss_now; 
 }
 
-/* Compute the actual receive window we are currently advertising. */
+/* Compute the actual receive window we are currently advertising.
+ * Rcv_nxt can be after the window if our peer push more data
+ * than the offered window.
+ */
 static __inline__ u32 tcp_receive_window(struct tcp_opt *tp)
 {
-	return tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+	s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
+
+	if (win < 0)
+		win = 0;
+	return (u32) win;
 }
 
 /* Choose a new window, without checks for shrinking, and without
  * scaling applied to the result.  The caller does these things
  * if necessary.  This is a "raw" window selection.
  */
-extern u32	__tcp_select_window(struct sock *sk);
+extern u32	__tcp_select_window(struct sock *sk, u32 cur_win);
 
 /* Chose a new window to advertise, update state in tcp_opt for the
  * socket, and return result with RFC1323 scaling applied.  The return
@@ -674,8 +681,8 @@
 extern __inline__ u16 tcp_select_window(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	u32 new_win = __tcp_select_window(sk);
 	u32 cur_win = tcp_receive_window(tp);
+	u32 new_win = __tcp_select_window(sk, cur_win);
 
 	/* Never shrink the offered window */
 	if(new_win < cur_win)
@@ -694,8 +701,8 @@
 extern __inline__ int tcp_raise_window(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	u32 new_win = __tcp_select_window(sk);
 	u32 cur_win = tcp_receive_window(tp);
+	u32 new_win = __tcp_select_window(sk, cur_win);
 
 	return (new_win && (new_win > (cur_win << 1)));
 }
diff -u --recursive --new-file v2.1.105/linux/init/main.c linux/init/main.c
--- v2.1.105/linux/init/main.c	Tue Jun  9 11:57:31 1998
+++ linux/init/main.c	Sat Jun 13 13:14:32 1998
@@ -44,6 +44,10 @@
 #include <linux/pci.h>
 #endif
 
+#ifdef CONFIG_DIO
+#include <linux/dio.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -76,6 +80,10 @@
 extern void filescache_init(void);
 extern void signals_init(void);
 
+#ifdef CONFIG_ARCH_ACORN
+extern void ecard_init(void);
+#endif
+
 extern void smp_setup(char *str, int *ints);
 #ifdef __i386__
 extern void ioapic_pirq_setup(char *str, int *ints);
@@ -124,6 +132,9 @@
 #ifdef CONFIG_PARIDE_PT
 extern void pt_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_PARIDE_PG
+extern void pg_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_PARIDE_PCD
 extern void pcd_setup(char *str, int *ints);
 #endif
@@ -378,6 +389,17 @@
 	{ "sdc",     0x0820 },
 	{ "sdd",     0x0830 },
 	{ "sde",     0x0840 },
+	{ "sdf",     0x0850 },
+	{ "sdg",     0x0860 },
+	{ "sdh",     0x0870 },
+	{ "sdi",     0x0880 },
+	{ "sdj",     0x0890 },
+	{ "sdk",     0x08a0 },
+	{ "sdl",     0x08b0 },
+	{ "sdm",     0x08c0 },
+	{ "sdn",     0x08d0 },
+	{ "sdo",     0x08e0 },
+	{ "sdp",     0x08f0 },
 #endif
 #ifdef CONFIG_ATARI_ACSI
 	{ "ada",     0x1c00 },
@@ -667,7 +689,7 @@
 #ifdef CONFIG_ISP16_CDI
 	{ "isp16=", isp16_setup },
 #endif CONFIG_ISP16_CDI
-#ifdef CONFIG_SOUND
+#ifdef CONFIG_SOUND_OSS
 	{ "sound=", sound_setup },
 #endif
 #ifdef CONFIG_ISDN_DRV_ICN
@@ -778,6 +800,9 @@
 #ifdef CONFIG_PARIDE_PT
         { "pt.", pt_setup },
 #endif
+#ifdef CONFIG_PARIDE_PG
+        { "pg.", pg_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -1090,6 +1115,9 @@
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
+#ifdef CONFIG_DIO
+	dio_init();
+#endif
 
 	/*
 	 * Ok, at this point all CPU's should be initialized, so
@@ -1106,6 +1134,9 @@
 #endif
 #ifdef CONFIG_MCA
 	mca_init();
+#endif
+#ifdef CONFIG_ARCH_ACORN
+	ecard_init();
 #endif
 
 	/* 
diff -u --recursive --new-file v2.1.105/linux/ipc/shm.c linux/ipc/shm.c
--- v2.1.105/linux/ipc/shm.c	Thu May  7 22:51:55 1998
+++ linux/ipc/shm.c	Tue Jun  9 10:34:33 1998
@@ -136,6 +136,7 @@
 	struct shmid_ds *shp;
 	int err, id = 0;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (size < 0 || size > SHMMAX) {
 		err = -EINVAL;
@@ -160,6 +161,7 @@
 			err = (int) shp->shm_perm.seq * SHMMNI + id;
 	}
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return err;
 }
 
@@ -484,6 +486,7 @@
 	unsigned long addr;
 	unsigned long len;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (shmid < 0) {
 		/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
@@ -584,6 +587,7 @@
 	err = 0;
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return err;
 }
 
@@ -634,6 +638,7 @@
 {
 	struct vm_area_struct *shmd, *shmdnext;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
 		shmdnext = shmd->vm_next;
@@ -642,6 +647,7 @@
 			do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
 	}
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.105/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.105/linux/kernel/fork.c	Thu May  7 22:51:55 1998
+++ linux/kernel/fork.c	Tue Jun  9 10:37:17 1998
@@ -204,7 +204,6 @@
 	int retval;
 
 	flush_cache_mm(current->mm);
-	down(&current->mm->mmap_sem);
 	pprev = &mm->mmap;
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
 		struct file *file;
@@ -254,7 +253,6 @@
 
 fail_nomem:
 	flush_tlb_mm(current->mm);
-	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -466,6 +464,7 @@
 	int error = -ENOMEM;
 	struct task_struct *p;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	p = alloc_task_struct();
 	if (!p)
@@ -570,6 +569,7 @@
 	++total_forks;
 	error = p->pid;
 bad_fork:
+	up(&current->mm->mmap_sem);
 	unlock_kernel();
 	return error;
 
diff -u --recursive --new-file v2.1.105/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.1.105/linux/kernel/kmod.c	Tue Jun  9 11:57:31 1998
+++ linux/kernel/kmod.c	Sat Jun 13 10:23:41 1998
@@ -93,6 +93,13 @@
 	int pid;
 	int waitpid_result;
 
+	/* Don't allow request_module() before the root fs is mounted!  */
+	if ( ! current->fs->root ) {
+		printk(KERN_ERR "request_module[%s]: Root fs not mounted\n",
+			module_name);
+		return -EPERM;
+	}
+
 	pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS);
 	if (pid < 0) {
 		printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
diff -u --recursive --new-file v2.1.105/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.105/linux/kernel/ksyms.c	Fri May  8 23:14:57 1998
+++ linux/kernel/ksyms.c	Sat Jun 13 11:45:09 1998
@@ -326,7 +326,8 @@
 EXPORT_SYMBOL(vsprintf);
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(simple_strtoul);
-EXPORT_SYMBOL(system_utsname);
+EXPORT_SYMBOL(system_utsname);	/* UTS data */
+EXPORT_SYMBOL(uts_sem);		/* UTS semaphore */
 EXPORT_SYMBOL(sys_call_table);
 EXPORT_SYMBOL(machine_restart);
 EXPORT_SYMBOL(machine_halt);
diff -u --recursive --new-file v2.1.105/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.105/linux/kernel/sched.c	Sun Jun  7 11:16:40 1998
+++ linux/kernel/sched.c	Sat Jun 13 11:58:58 1998
@@ -1564,7 +1564,6 @@
 		printk("\n");
 
 	{
-		extern char * render_sigset_t(sigset_t *set, char *buffer);
 		struct signal_queue *q;
 		char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; 
 
@@ -1575,6 +1574,21 @@
 			printk(" %d", q->info.si_signo);
 		printk(" X\n");
 	}
+}
+
+char * render_sigset_t(sigset_t *set, char *buffer)
+{
+	int i = _NSIG, x;
+	do {
+		i -= 4, x = 0;
+		if (sigismember(set, i+1)) x |= 1;
+		if (sigismember(set, i+2)) x |= 2;
+		if (sigismember(set, i+3)) x |= 4;
+		if (sigismember(set, i+4)) x |= 8;
+		*buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
+	} while (i >= 4);
+	*buffer = 0;
+	return buffer;
 }
 
 void show_state(void)
diff -u --recursive --new-file v2.1.105/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.105/linux/kernel/signal.c	Thu May  7 22:51:55 1998
+++ linux/kernel/signal.c	Tue Jun  9 10:14:12 1998
@@ -840,6 +840,62 @@
 	return 0;
 }
 
+int 
+do_sigaltstack (const stack_t *uss, stack_t *uoss, unsigned long sp)
+{
+	stack_t oss;
+	int error;
+
+	if (uoss) {
+		oss.ss_sp = (void *) current->sas_ss_sp;
+		oss.ss_size = current->sas_ss_size;
+		oss.ss_flags = sas_ss_flags(sp);
+	}
+
+	if (uss) {
+		void *ss_sp;
+		size_t ss_size;
+		int ss_flags;
+
+		error = -EFAULT;
+		if (verify_area(VERIFY_READ, uss, sizeof(*uss))
+		    || __get_user(ss_sp, &uss->ss_sp)
+		    || __get_user(ss_flags, &uss->ss_flags)
+		    || __get_user(ss_size, &uss->ss_size))
+			goto out;
+
+		error = -EPERM;
+		if (on_sig_stack (sp))
+			goto out;
+
+		error = -EINVAL;
+		if (ss_flags & ~SS_DISABLE)
+			goto out;
+
+		if (ss_flags & SS_DISABLE) {
+			ss_size = 0;
+			ss_sp = NULL;
+		} else {
+			error = -ENOMEM;
+			if (ss_size < MINSIGSTKSZ)
+				goto out;
+		}
+
+		current->sas_ss_sp = (unsigned long) ss_sp;
+		current->sas_ss_size = ss_size;
+	}
+
+	if (uoss) {
+		error = -EFAULT;
+		if (copy_to_user(uoss, &oss, sizeof(oss)))
+			goto out;
+	}
+
+	error = 0;
+out:
+	return error;
+}
+
 #if !defined(__alpha__)
 /* Alpha has its own versions with special arguments.  */
 
@@ -908,6 +964,7 @@
 	return error;
 }
 
+#ifndef __sparc__
 asmlinkage int
 sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
 		 size_t sigsetsize)
@@ -933,6 +990,7 @@
 out:
 	return ret;
 }
+#endif /* __sparc__ */
 #endif
 
 #if !defined(__alpha__)
diff -u --recursive --new-file v2.1.105/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.105/linux/kernel/sysctl.c	Fri May  8 23:14:57 1998
+++ linux/kernel/sysctl.c	Sat Jun 13 12:48:11 1998
@@ -55,8 +55,12 @@
 extern unsigned long htab_reclaim_on, zero_paged_on;
 #endif
 
+extern int pgt_cache_water[];
+
 static int parse_table(int *, int, void *, size_t *, void *, size_t,
 		       ctl_table *, void **);
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp);
 
 
 static ctl_table root_table[];
@@ -138,15 +142,15 @@
 
 static ctl_table kern_table[] = {
 	{KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
-	 0444, NULL, &proc_dostring, &sysctl_string},
+	 0444, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
-	 0444, NULL, &proc_dostring, &sysctl_string},
+	 0444, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_VERSION, "version", system_utsname.version, 64,
-	 0444, NULL, &proc_dostring, &sysctl_string},
+	 0444, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_NODENAME, "hostname", system_utsname.nodename, 64,
-	 0644, NULL, &proc_dostring, &sysctl_string},
+	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
-	 0644, NULL, &proc_dostring, &sysctl_string},
+	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -202,6 +206,8 @@
 	 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
 	{VM_PAGERDAEMON, "kswapd",
 	 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
+	{VM_PGT_CACHE, "pagetable_cache", 
+	 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
 	{0}
 };
 
@@ -627,6 +633,21 @@
 		filp->f_pos += len;
 	}
 	return 0;
+}
+
+/*
+ *	Special case of dostring for the UTS structure. This has locks
+ *	to observe. Should this be in kernel/sys.c ????
+ */
+ 
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp)
+{
+	int r;
+	down(&uts_sem);
+	r=proc_dostring(table,write,filp,buffer,lenp);
+	up(&uts_sem);
+	return r;
 }
 
 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
diff -u --recursive --new-file v2.1.105/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.105/linux/mm/filemap.c	Thu Mar 26 15:57:06 1998
+++ linux/mm/filemap.c	Tue Jun  9 10:34:03 1998
@@ -1256,6 +1256,7 @@
 	struct vm_area_struct * vma;
 	int unmapped_error, error = -EINVAL;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (start & ~PAGE_MASK)
 		goto out;
@@ -1303,6 +1304,7 @@
 	}
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
diff -u --recursive --new-file v2.1.105/linux/mm/memory.c linux/mm/memory.c
--- v2.1.105/linux/mm/memory.c	Tue Mar 10 10:03:36 1998
+++ linux/mm/memory.c	Sat Jun 13 12:48:11 1998
@@ -44,6 +44,8 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -68,8 +70,6 @@
 	copy_page(to, from);
 }
 
-#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
-
 mem_map_t * mem_map = NULL;
 
 /*
@@ -163,13 +163,10 @@
 
 int new_page_tables(struct task_struct * tsk)
 {
-	pgd_t * page_dir, * new_pg;
+	pgd_t * new_pg;
 
 	if (!(new_pg = pgd_alloc()))
 		return -ENOMEM;
-	page_dir = pgd_offset(&init_mm, 0);
-	memcpy(new_pg + USER_PTRS_PER_PGD, page_dir + USER_PTRS_PER_PGD,
-	       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof (pgd_t));
 	SET_PAGE_DIR(tsk, new_pg);
 	tsk->mm->pgd = new_pg;
 	return 0;
@@ -895,6 +892,9 @@
 	do_wp_page(tsk, vma, address, write_access, pte);
 }
 
+/*
+ * By the time we get here, we already hold the mm semaphore
+ */
 void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
@@ -909,9 +909,30 @@
 	pte = pte_alloc(pmd, address);
 	if (!pte)
 		goto no_memory;
+	lock_kernel();
 	handle_pte_fault(tsk, vma, address, write_access, pte);
+	unlock_kernel();
 	update_mmu_cache(vma, address, *pte);
 	return;
 no_memory:
 	oom(tsk);
+}
+
+/* Low and high watermarks for page table cache.
+   The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
+ */
+int pgt_cache_water[2] = { 25, 50 };
+
+void check_pgt_cache(void)
+{
+        if(pgtable_cache_size > pgt_cache_water[0]) {
+                do {
+                        if(pgd_quicklist)
+                                free_pgd_slow(get_pgd_fast());
+                        if(pmd_quicklist)
+                                free_pmd_slow(get_pmd_fast());
+                        if(pte_quicklist)
+                                free_pte_slow(get_pte_fast());
+                } while(pgtable_cache_size > pgt_cache_water[1]);
+        }
 }
diff -u --recursive --new-file v2.1.105/linux/mm/mlock.c linux/mm/mlock.c
--- v2.1.105/linux/mm/mlock.c	Fri May  8 23:14:57 1998
+++ linux/mm/mlock.c	Tue Jun  9 11:10:20 1998
@@ -127,13 +127,25 @@
 			pages = -pages;
 		vma->vm_mm->locked_vm += pages;
 
-		if (newflags & VM_LOCKED)
+#if 0
+/*
+ * This is horribly broken. See the comment on the same
+ * brokenness in mm/mmap.c (essentially, this doesn't
+ * work anyway for PROT_NONE and writable pages, and now
+ * that we properly get the mmap semaphore it would just
+ * lock up on us).
+ *
+ * Fix the same way.
+ */
+		if (newflags & VM_LOCKED) {
 			while (start < end) {
 				int c;
 				get_user(c,(int *) start);
 				__asm__ __volatile__("": :"r" (c));
 				start += PAGE_SIZE;
 			}
+		}
+#endif
 	}
 	return retval;
 }
@@ -192,6 +204,7 @@
 	unsigned long lock_limit;
 	int error = -ENOMEM;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
@@ -214,6 +227,7 @@
 	error = do_mlock(start, len, 1);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -221,11 +235,13 @@
 {
 	int ret;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
 	ret = do_mlock(start, len, 0);
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -263,6 +279,7 @@
 	unsigned long lock_limit;
 	int ret = -EINVAL;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 		goto out;
@@ -282,6 +299,7 @@
 	ret = do_mlockall(flags);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -289,8 +307,10 @@
 {
 	int ret;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	ret = do_mlockall(0);
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.1.105/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.105/linux/mm/mmap.c	Tue Mar 10 10:03:36 1998
+++ linux/mm/mmap.c	Sat Jun 13 13:13:20 1998
@@ -92,6 +92,7 @@
 	unsigned long newbrk, oldbrk;
 	struct mm_struct *mm = current->mm;
 
+	down(&mm->mmap_sem);
 	lock_kernel();
 	if (brk < mm->end_code)
 		goto out;
@@ -109,9 +110,7 @@
 
 	/* Check against rlimit and stack.. */
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
-	if (rlim >= RLIM_INFINITY)
-		rlim = ~0;
-	if (brk - mm->end_code > rlim)
+	if (rlim < RLIM_INFINITY && brk - mm->end_code > rlim)
 		goto out;
 
 	/* Check against existing mmap mappings. */
@@ -132,6 +131,7 @@
 out:
 	retval = mm->brk;
 	unlock_kernel();
+	up(&mm->mmap_sem);
 	return retval;
 }
 
@@ -316,9 +316,21 @@
 	merge_segments(mm, vma->vm_start, vma->vm_end);
 	
 	mm->total_vm += len >> PAGE_SHIFT;
-	if ((flags & VM_LOCKED) && !(flags & VM_IO)) {
-		unsigned long start = addr;
+	if (flags & VM_LOCKED) {
 		mm->locked_vm += len >> PAGE_SHIFT;
+
+/*
+ * This used to be just slightly broken, now it's just completely
+ * buggered. We can't take a page fault here, because we already
+ * hold the mm semaphore (as is proper). We should do this by hand
+ * by calling the appropriate fault-in routine.
+ *
+ * That would also fix this routine wrt writes and PROT_NONE
+ * areas, both of which can't be handled by the page fault
+ * approach anyway.
+ */
+#if 0
+		unsigned long start = addr;
 		do {
 			char c;
 			get_user(c,(char *) start);
@@ -326,6 +338,7 @@
 			start += PAGE_SIZE;
 			__asm__ __volatile__("": :"r" (c));
 		} while (len > 0);
+#endif
 	}
 	return addr;
 
@@ -442,16 +455,6 @@
 	return 1;
 }
 
-asmlinkage int sys_munmap(unsigned long addr, size_t len)
-{
-	int ret;
-
-	lock_kernel();
-	ret = do_munmap(addr, len);
-	unlock_kernel();
-	return ret;
-}
-
 /* Munmap is split into 2 main parts -- this part which finds
  * what needs doing, and the areas themselves, which do the
  * work.  This now handles partial unmappings.
@@ -460,7 +463,7 @@
 int do_munmap(unsigned long addr, size_t len)
 {
 	struct mm_struct * mm;
-	struct vm_area_struct *mpnt, *next, *free, *extra;
+	struct vm_area_struct *mpnt, *free, *extra;
 	int freed;
 
 	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
@@ -481,6 +484,11 @@
 	if (!mpnt)
 		return 0;
 
+	/* If we'll make "hole", check the vm areas limit */
+	if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len) &&
+	    mm->map_count > MAX_MAP_COUNT)
+		return -ENOMEM;
+
 	/*
 	 * We may need one additional vma to fix up the mappings ... 
 	 * and this is the last chance for an easy error exit.
@@ -489,9 +497,7 @@
 	if (!extra)
 		return -ENOMEM;
 
-	next = mpnt->vm_next;
-
-	/* we have mpnt->vm_next = next and addr < mpnt->vm_end */
+	/* we have addr < mpnt->vm_end */
 	free = NULL;
 	for ( ; mpnt && mpnt->vm_start < addr+len; ) {
 		struct vm_area_struct *next = mpnt->vm_next;
@@ -505,13 +511,6 @@
 		mpnt = next;
 	}
 
-	if (free && (free->vm_start < addr) && (free->vm_end > addr+len)) {
-		if (mm->map_count > MAX_MAP_COUNT) {
-			kmem_cache_free(vm_area_cachep, extra);
-			return -ENOMEM;
-		}
-	}
-
 	/* Ok - we have the memory areas we should free on the 'free' list,
 	 * so release them, and unmap the page range..
 	 * If the one of the segments is only being partially unmapped,
@@ -555,6 +554,18 @@
 	return 0;
 }
 
+asmlinkage int sys_munmap(unsigned long addr, size_t len)
+{
+	int ret;
+
+	down(&current->mm->mmap_sem);
+	lock_kernel();
+	ret = do_munmap(addr, len);
+	unlock_kernel();
+	up(&current->mm->mmap_sem);
+	return ret;
+}
+
 /* Release all mmaps. */
 void exit_mmap(struct mm_struct * mm)
 {
@@ -630,13 +641,13 @@
  * This assumes that the list is ordered by address.
  * We don't need to traverse the entire list, only those segments
  * which intersect or are adjacent to a given interval.
+ *
+ * We must already hold the mm semaphore when we get here..
  */
 void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
 {
 	struct vm_area_struct *prev, *mpnt, *next;
 
-	down(&mm->mmap_sem);
-
 	prev = NULL;
 	mpnt = mm->mmap;
 	while(mpnt && mpnt->vm_end <= start_addr) {
@@ -644,7 +655,7 @@
 		mpnt = mpnt->vm_next;
 	}
 	if (!mpnt)
-		goto no_vma;
+		return;
 
 	next = mpnt->vm_next;
 
@@ -700,8 +711,6 @@
 		mpnt = prev;
 	}
 	mm->mmap_cache = NULL;		/* Kill the cache. */
-no_vma:
-	up(&mm->mmap_sem);
 }
 
 __initfunc(void vma_init(void))
diff -u --recursive --new-file v2.1.105/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.1.105/linux/mm/mprotect.c	Thu Mar 26 15:57:06 1998
+++ linux/mm/mprotect.c	Tue Jun  9 10:33:10 1998
@@ -208,18 +208,20 @@
 	struct vm_area_struct * vma, * next;
 	int error = -EINVAL;
 
-	lock_kernel();
 	if (start & ~PAGE_MASK)
-		goto out;
+		return -EINVAL;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
 	end = start + len;
 	if (end < start)
-		goto out;
+		return -EINVAL;
 	if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
-		goto out;
-	error = 0;
+		return -EINVAL;
 	if (end == start)
-		goto out;
+		return 0;
+
+	down(&current->mm->mmap_sem);
+	lock_kernel();
+
 	vma = find_vma(current->mm, start);
 	error = -EFAULT;
 	if (!vma || vma->vm_start > start)
@@ -256,5 +258,6 @@
 	merge_segments(current->mm, start, end);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
diff -u --recursive --new-file v2.1.105/linux/mm/mremap.c linux/mm/mremap.c
--- v2.1.105/linux/mm/mremap.c	Tue Mar 10 10:03:36 1998
+++ linux/mm/mremap.c	Tue Jun  9 10:33:20 1998
@@ -167,6 +167,7 @@
 	struct vm_area_struct *vma;
 	unsigned long ret = -EINVAL;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (addr & ~PAGE_MASK)
 		goto out;
@@ -233,5 +234,6 @@
 		ret = -ENOMEM;
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.1.105/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.105/linux/mm/swapfile.c	Thu May  7 22:51:55 1998
+++ linux/mm/swapfile.c	Sat Jun 13 13:28:34 1998
@@ -28,10 +28,7 @@
 
 unsigned int nr_swapfiles = 0;
 
-static struct {
-	int head;	/* head of priority-ordered swapfile list */
-	int next;	/* swapfile to be used next */
-} swap_list = {-1, -1};
+struct swap_list_t swap_list = {-1, -1};
 
 struct swap_info_struct swap_info[MAX_SWAPFILES];
 
@@ -595,7 +592,7 @@
 	p->flags = SWP_WRITEOK;
 	p->pages = j;
 	nr_swap_pages += j;
-	printk("Adding Swap: %dk swap-space (priority %d)\n",
+	printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
 	       j<<(PAGE_SHIFT-10), p->prio);
 
 	/* insert swap space into swap_list: */
diff -u --recursive --new-file v2.1.105/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v2.1.105/linux/mm/vmalloc.c	Wed Apr  1 20:11:55 1998
+++ linux/mm/vmalloc.c	Sat Jun 13 12:48:11 1998
@@ -133,12 +133,16 @@
 	dir = pgd_offset_k(address);
 	flush_cache_all();
 	while (address < end) {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		pmd_t *pmd;
+		pgd_t olddir = *dir;
+		
+		pmd = pmd_alloc_kernel(dir, address);
 		if (!pmd)
 			return -ENOMEM;
 		if (alloc_area_pmd(pmd, address, end - address))
 			return -ENOMEM;
-		set_pgdir(address, *dir);
+		if (pgd_val(olddir) != pgd_val(*dir))
+			set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
@@ -155,14 +159,13 @@
 	if (!area)
 		return NULL;
 	addr = (void *) VMALLOC_START;
-	area->size = size + PAGE_SIZE;
-	area->next = NULL;
 	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
 		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
 			break;
 		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
 	}
 	area->addr = addr;
+	area->size = size + PAGE_SIZE;
 	area->next = *p;
 	*p = area;
 	return area;
@@ -210,16 +213,18 @@
 
 long vread(char *buf, char *addr, unsigned long count)
 {
-	struct vm_struct **p, *tmp;
+	struct vm_struct *tmp;
 	char *vaddr, *buf_start = buf;
-	int n;
+	unsigned long n;
 
 	/* Don't allow overflow */
 	if ((unsigned long) addr + count < count)
 		count = -(unsigned long) addr;
 
-	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+	for (tmp = vmlist; tmp; tmp = tmp->next) {
 		vaddr = (char *) tmp->addr;
+		if (addr >= vaddr + tmp->size - PAGE_SIZE)
+			continue;
 		while (addr < vaddr) {
 			if (count == 0)
 				goto finished;
@@ -228,17 +233,15 @@
 			addr++;
 			count--;
 		}
-		n = tmp->size - PAGE_SIZE;
-		if (addr > vaddr)
-			n -= addr - vaddr;
-		while (--n >= 0) {
+		n = vaddr + tmp->size - PAGE_SIZE - addr;
+		do {
 			if (count == 0)
 				goto finished;
 			put_user(*addr, buf);
 			buf++;
 			addr++;
 			count--;
-		}
+		} while (--n > 0);
 	}
 finished:
 	return buf - buf_start;
diff -u --recursive --new-file v2.1.105/linux/net/802/psnap.c linux/net/802/psnap.c
--- v2.1.105/linux/net/802/psnap.c	Mon Feb 23 18:12:12 1998
+++ linux/net/802/psnap.c	Sat Jun 13 10:23:41 1998
@@ -95,7 +95,7 @@
 }
 
 /*
- *	Register SNAP clients. We don't yet use this for IP or IPX.
+ *	Register SNAP clients. We don't yet use this for IP.
  */
 
 struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
diff -u --recursive --new-file v2.1.105/linux/net/Config.in linux/net/Config.in
--- v2.1.105/linux/net/Config.in	Sat May  2 14:19:54 1998
+++ linux/net/Config.in	Mon Jun  8 10:02:34 1998
@@ -56,7 +56,7 @@
   if [ "$CONFIG_NET_SCHED" = "y" ]; then
     source net/sched/Config.in
   fi
-  bool 'Network code profiler' CONFIG_NET_PROFILE
+#  bool 'Network code profiler' CONFIG_NET_PROFILE
   fi
 fi
 endmenu
diff -u --recursive --new-file v2.1.105/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.105/linux/net/core/dev.c	Thu May  7 22:51:55 1998
+++ linux/net/core/dev.c	Sat Jun 13 12:10:31 1998
@@ -1097,7 +1097,7 @@
 	int size;
 	
 	if (stats)
-		size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu %4lu\n",
+		size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
  		   dev->name,
 		   stats->rx_bytes,
 		   stats->rx_packets, stats->rx_errors,
@@ -1325,7 +1325,7 @@
 	dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP|
 			       IFF_SLAVE|IFF_MASTER|
 			       IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
-				       (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC));
+				       (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
 
 	/*
 	 *	Load in the correct multicast list now the flags have changed.
@@ -1346,13 +1346,11 @@
 
 		if (ret == 0) 
 			dev_mc_upload(dev);
-	}       
+	}
 
 	if (dev->flags&IFF_UP &&
-	    ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_VOLATILE))) {
-		printk(KERN_DEBUG "SIFFL %s(%s)\n", dev->name, current->comm);
+	    ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))
 		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
-	}
 
 	if ((flags^dev->gflags)&IFF_PROMISC) {
 		int inc = (flags&IFF_PROMISC) ? +1 : -1;
@@ -1360,6 +1358,16 @@
 		dev_set_promiscuity(dev, inc);
 	}
 
+	/* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI
+	   is important. Some (broken) drivers set IFF_PROMISC, when
+	   IFF_ALLMULTI is requested not asking us and not reporting.
+	 */
+	if ((flags^dev->gflags)&IFF_ALLMULTI) {
+		int inc = (flags&IFF_ALLMULTI) ? +1 : -1;
+		dev->gflags ^= IFF_ALLMULTI;
+		dev_set_allmulti(dev, inc);
+	}
+
 	return ret;
 }
 
@@ -1378,7 +1386,8 @@
 	switch(cmd) 
 	{
 		case SIOCGIFFLAGS:	/* Get interface flags */
-			ifr->ifr_flags = (dev->flags&~IFF_PROMISC)|(dev->gflags&IFF_PROMISC);
+			ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+				|(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
 			return 0;
 
 		case SIOCSIFFLAGS:	/* Set interface flags */
diff -u --recursive --new-file v2.1.105/linux/net/core/profile.c linux/net/core/profile.c
--- v2.1.105/linux/net/core/profile.c	Thu Feb 12 20:56:14 1998
+++ linux/net/core/profile.c	Sat Jun 13 10:23:41 1998
@@ -277,7 +277,7 @@
 	printk("Evaluating net profiler cost ...");
 #if CPU == 586 || CPU == 686
 	if (!(boot_cpu_data.x86_capability & 16)) {
-		panic("Sorry, you CPU does not support tsc. I am dying...\n");
+		printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n");
 		return -1;
 	}
 #endif
diff -u --recursive --new-file v2.1.105/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.105/linux/net/core/sock.c	Thu May  7 22:51:55 1998
+++ linux/net/core/sock.c	Sat Jun 13 11:45:10 1998
@@ -206,18 +206,14 @@
 			sk->broadcast=valbool;
 			break;
 		case SO_SNDBUF:
-			/*
-			 *	The spec isnt clear if ENOBUFS or EINVAL
-			 *	is best
-			 */
-			 
-			/* printk(KERN_DEBUG "setting SO_SNDBUF %d\n", val); */
+			/* Don't error on this BSD doesn't and if you think
+			   about it this is right. Otherwise apps have to
+			   play 'guess the biggest size' games. RCVBUF/SNDBUF
+			   are treated in BSD as hints */
+			   
 			if (val > sysctl_wmem_max)
-				return -EINVAL;
+				return 0;
 
-			/* FIXME: the tcp code should be made to work even
-			 * with small sndbuf values.
-			 */
 			sk->sndbuf = max(val*2,2048);
 
 			/*
@@ -228,10 +224,13 @@
 			break;
 
 		case SO_RCVBUF:
-			/* printk(KERN_DEBUG "setting SO_RCVBUF %d\n", val); */
-
+			/* Don't error on this BSD doesn't and if you think
+			   about it this is right. Otherwise apps have to
+			   play 'guess the biggest size' games. RCVBUF/SNDBUF
+			   are treated in BSD as hints */
+			  
 			if (val > sysctl_rmem_max)
-				return -EINVAL;
+				return 0;
 
 			/* FIXME: is this lower bound the right one? */
 			sk->rcvbuf = max(val*2,256);
@@ -480,8 +479,8 @@
 {
 	struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
 
-	if(sk && zero_it) {
-		memset(sk, 0, sizeof(struct sock));
+	if(sk) {
+		if (zero_it) memset(sk, 0, sizeof(struct sock));
 		sk->family = family;
 	}
 
@@ -564,15 +563,18 @@
 
 void *sock_kmalloc(struct sock *sk, int size, int priority)
 {
-	void *mem = NULL;
 	if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
+		void *mem;
 		/* First do the add, to avoid the race if kmalloc
  		 * might sleep.
 		 */
 		atomic_add(size, &sk->omem_alloc);
 		mem = kmalloc(size, priority);
+		if (mem)
+			return mem;
+		atomic_sub(size, &sk->omem_alloc);
 	}
-	return mem;
+	return NULL;
 }
 
 void sock_kfree_s(struct sock *sk, void *mem, int size)
@@ -880,7 +882,7 @@
 
 unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
 {
-	return -EOPNOTSUPP;
+	return 0;
 }
 
 int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.1.105/linux/net/ipv4/fib_frontend.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/fib_frontend.c	Thu Jun 11 22:52:34 1998
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:	$Id: fib_frontend.c,v 1.10 1998/05/08 21:06:27 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.11 1998/06/11 03:15:40 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -271,6 +271,8 @@
 				if (tb)
 					err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
 			}
+			if (rta.rta_mx)
+				kfree(rta.rta_mx);
 		}
 		rtnl_unlock();
 		return err;
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
--- v2.1.105/linux/net/ipv4/fib_semantics.c	Sat May  2 14:19:55 1998
+++ linux/net/ipv4/fib_semantics.c	Thu Jun 11 22:52:34 1998
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: semantics.
  *
- * Version:	$Id: fib_semantics.c,v 1.8 1998/04/28 06:21:58 davem Exp $
+ * Version:	$Id: fib_semantics.c,v 1.9 1998/06/11 03:15:41 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -866,8 +866,36 @@
 			*rta->rta_mtu = r->rt_mtu;
 	}
 #else
-	if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT))
-	    printk(KERN_DEBUG "SIOCRT*: mtu/window/irtt are not implemnted.\n");
+	if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
+		struct rtattr *rec;
+		struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
+		if (mx == NULL)
+			return -ENOMEM;
+		rta->rta_mx = mx;
+		mx->rta_type = RTA_METRICS;
+		mx->rta_len  = RTA_LENGTH(0);
+		if (r->rt_flags&RTF_MTU) {
+			rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+			rec->rta_type = RTAX_MTU;
+			rec->rta_len = RTA_LENGTH(4);
+			mx->rta_len += RTA_LENGTH(4);
+			*(u32*)RTA_DATA(rec) = r->rt_mtu;
+		}
+		if (r->rt_flags&RTF_WINDOW) {
+			rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+			rec->rta_type = RTAX_WINDOW;
+			rec->rta_len = RTA_LENGTH(4);
+			mx->rta_len += RTA_LENGTH(4);
+			*(u32*)RTA_DATA(rec) = r->rt_window;
+		}
+		if (r->rt_flags&RTF_IRTT) {
+			rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+			rec->rta_type = RTAX_RTT;
+			rec->rta_len = RTA_LENGTH(4);
+			mx->rta_len += RTA_LENGTH(4);
+			*(u32*)RTA_DATA(rec) = r->rt_irtt;
+		}
+	}
 #endif
 	return 0;
 }
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.105/linux/net/ipv4/icmp.c	Sat May  2 14:19:55 1998
+++ linux/net/ipv4/icmp.c	Thu Jun 11 22:52:35 1998
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@cymru.net>
  *
- *	Version: $Id: icmp.c,v 1.41 1998/04/29 22:12:10 alan Exp $
+ *	Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -539,7 +539,7 @@
 	 */
 	
 	saddr = iph->daddr;
-	if (!(rt->rt_flags&RTCF_LOCAL))
+	if (!(rt->rt_flags & RTCF_LOCAL))
 		saddr = 0;
 
 	tos = icmp_pointers[type].error ?
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.105/linux/net/ipv4/ip_fragment.c	Thu Apr 23 20:21:39 1998
+++ linux/net/ipv4/ip_fragment.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.36 1998/04/18 02:13:07 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -16,6 +16,7 @@
  *		Andi Kleen	:	Add sysctls.
  *		xxxx		:	Overlapfrag bug.
  *		Ultima          :       ip_expire() kernel panic.
+ *		Bill Hawes	:	Frag accounting and evictor fixes.
  */
 
 #include <linux/types.h>
@@ -76,8 +77,6 @@
 
 atomic_t ip_frag_mem = ATOMIC_INIT(0);		/* Memory used for fragments */
 
-char *in_ntoa(__u32 in);
-
 /* Memory Tracking Functions. */
 extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
 {
@@ -88,12 +87,12 @@
 extern __inline__ void frag_kfree_s(void *ptr, int len)
 {
 	atomic_sub(len, &ip_frag_mem);
-	kfree_s(ptr,len);
+	kfree(ptr);
 }
  
 extern __inline__ void *frag_kmalloc(int size, int pri)
 {
-	void *vp=kmalloc(size,pri);
+	void *vp = kmalloc(size, pri);
 
 	if(!vp)
 		return NULL;
@@ -108,10 +107,8 @@
 	struct ipfrag *fp;
 
 	fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
-	if (fp == NULL) {
-		NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
-		return(NULL);
-	}
+	if (fp == NULL)
+		goto out_nomem;
 
 	/* Fill in the structure. */
 	fp->offset = offset;
@@ -125,6 +122,10 @@
 	atomic_add(skb->truesize, &ip_frag_mem);
 
 	return(fp);
+
+out_nomem:
+	NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
+	return(NULL);
 }
 
 /* Find the correct entry in the "incomplete datagrams" queue for
@@ -139,7 +140,7 @@
 	unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
 	struct ipq *qp;
 
-	start_bh_atomic();
+	/* Always, we are in a BH context, so no locking.  -DaveM */
 	for(qp = ipq_hash[hash]; qp; qp = qp->next) {
 		if(qp->iph->id == id		&&
 		   qp->iph->saddr == saddr	&&
@@ -149,13 +150,15 @@
 			break;
 		}
 	}
-	end_bh_atomic();
 	return qp;
 }
 
 /* Remove an entry from the "incomplete datagrams" queue, either
  * because we completed, reassembled and processed it, or because
  * it timed out.
+ *
+ * This is called _only_ from BH contexts, on packet reception
+ * processing and from frag queue expiration timers.  -DaveM
  */
 static void ip_free(struct ipq *qp)
 {
@@ -165,11 +168,9 @@
 	del_timer(&qp->timer);
 
 	/* Remove this entry from the "incomplete datagrams" queue. */
-	start_bh_atomic();
 	if(qp->next)
 		qp->next->pprev = qp->pprev;
 	*qp->pprev = qp->next;
-	end_bh_atomic();
 
 	/* Release all fragment data. */
 	fp = qp->fragments;
@@ -188,7 +189,9 @@
 	frag_kfree_s(qp, sizeof(struct ipq));
 }
 
-/* Oops, a fragment queue timed out.  Kill it and send an ICMP reply. */
+/*
+ * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
+ */
 static void ip_expire(unsigned long arg)
 {
 	struct ipq *qp = (struct ipq *) arg;
@@ -198,15 +201,15 @@
 #ifdef IP_EXPIRE_DEBUG
 	  	printk("warning: possible ip-expire attack\n");
 #endif
-		ip_free(qp);
-		return;
+		goto out;
   	}
   
 	/* Send an ICMP "Fragment Reassembly Timeout" message. */
 	ip_statistics.IpReasmTimeout++;
 	ip_statistics.IpReasmFails++;   
-	icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+	icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
 
+out:
 	/* Nuke the fragment queue. */
 	ip_free(qp);
 }
@@ -216,17 +219,30 @@
  */
 static void ip_evictor(void)
 {
-	while(atomic_read(&ip_frag_mem)>sysctl_ipfrag_low_thresh) {
-		int i;
+	int i, progress;
 
-		/* FIXME: Make LRU queue of frag heads. -DaveM */
-		for(i = 0; i < IPQ_HASHSZ; i++)
-			if(ipq_hash[i])
-				break;
-		if(i >= IPQ_HASHSZ)
-			panic("ip_evictor: memcount");
-		ip_free(ipq_hash[i]);
+restart:
+	progress = 0;
+	/* FIXME: Make LRU queue of frag heads. -DaveM */
+	for (i = 0; i < IPQ_HASHSZ; i++) {
+		struct ipq *qp;
+		if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
+			return;
+		/* We are in a BH context, so these queue
+		 * accesses are safe.  -DaveM
+		 */
+		qp = ipq_hash[i];
+		if (qp) {
+			/* find the oldest queue for this hash bucket */
+			while (qp->next)
+				qp = qp->next;
+			ip_free(qp);
+			progress = 1;
+		}
 	}
+	if (progress)
+		goto restart;
+	panic("ip_evictor: memcount");
 }
 
 /* Add an entry to the 'ipq' queue for a newly received IP datagram.
@@ -241,20 +257,15 @@
 	int ihlen;
 
 	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
-	if (qp == NULL) {
-		NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
-		return(NULL);
-	}
+	if (qp == NULL)
+		goto out_nomem;
 
 	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
 	ihlen = iph->ihl * 4;
 
 	qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
-	if (qp->iph == NULL) {
-		NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
-		frag_kfree_s(qp, sizeof(struct ipq));
-		return NULL;
-	}
+	if (qp->iph == NULL)
+		goto out_free;
 
 	memcpy(qp->iph, iph, ihlen + 8);
 	qp->len = 0;
@@ -262,24 +273,28 @@
 	qp->fragments = NULL;
 	qp->dev = skb->dev;
 
-	/* Start a timer for this entry. */
+	/* Initialize a timer for this entry. */
 	init_timer(&qp->timer);
-	qp->timer.expires = jiffies + sysctl_ipfrag_time;	/* about 30 seconds	*/
-	qp->timer.data = (unsigned long) qp;		/* pointer to queue	*/
-	qp->timer.function = ip_expire;			/* expire function	*/
-	add_timer(&qp->timer);
+	qp->timer.expires = 0;			/* (to be set later)	*/
+	qp->timer.data = (unsigned long) qp;	/* pointer to queue	*/
+	qp->timer.function = ip_expire;		/* expire function	*/
 
 	/* Add this entry to the queue. */
 	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
-	start_bh_atomic();
+	/* We are in a BH context, no locking necessary.  -DaveM */
 	if((qp->next = ipq_hash[hash]) != NULL)
 		qp->next->pprev = &qp->next;
 	ipq_hash[hash] = qp;
 	qp->pprev = &ipq_hash[hash];
-	end_bh_atomic();
 
 	return qp;
+
+out_free:
+	frag_kfree_s(qp, sizeof(struct ipq));
+out_nomem:
+	NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
+	return(NULL);
 }
 
 /* See if a fragment queue is complete. */
@@ -323,24 +338,16 @@
 	/* Allocate a new buffer for the datagram. */
 	len = qp->ihlen + qp->len;
 	
-	if(len>65535) {
-		if (net_ratelimit())
-			printk(KERN_INFO "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->iph->saddr));
-		ip_statistics.IpReasmFails++;
-		ip_free(qp);
-		return NULL;
-	}
+	if(len > 65535)
+		goto out_oversize;
 	
-	if ((skb = dev_alloc_skb(len)) == NULL) {
-		ip_statistics.IpReasmFails++;
- 		NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing queue %p\n", qp));
-		ip_free(qp);
-		return NULL;
-	}
+	skb = dev_alloc_skb(len);
+	if (!skb)
+		goto out_nomem;
 
 	/* Fill in the basic details. */
 	skb->mac.raw = ptr = skb->data;
-	skb->nh.iph = iph = (struct iphdr*)skb_put(skb,len);
+	skb->nh.iph = iph = (struct iphdr *) skb_put(skb, len);
 
 	/* Copy the original IP headers into the new buffer. */
 	memcpy(ptr, qp->iph, qp->ihlen);
@@ -350,14 +357,8 @@
 	fp = qp->fragments;
 	count = qp->ihlen;
 	while(fp) {
-		if (fp->len < 0 || count+fp->len > skb->len) {
-			NETDEBUG(printk(KERN_ERR "Invalid fragment list: "
-					"Fragment over size.\n"));
-			ip_free(qp);
-			kfree_skb(skb);
-			ip_statistics.IpReasmFails++;
-			return NULL;
-		}
+		if ((fp->len < 0) || ((count + fp->len) > skb->len))
+			goto out_invalid;
 		memcpy((ptr + fp->offset), fp->ptr, fp->len);
 		if (count == qp->ihlen) {
 			skb->dst = dst_clone(fp->skb->dst);
@@ -369,26 +370,40 @@
 
 	skb->pkt_type = qp->fragments->skb->pkt_type;
 	skb->protocol = qp->fragments->skb->protocol;
-	/* We glued together all fragments, so remove the queue entry. */
-	ip_free(qp);
 
 	/* Done with all fragments. Fixup the new IP header. */
 	iph = skb->nh.iph;
 	iph->frag_off = 0;
 	iph->tot_len = htons(count);
-
 	ip_statistics.IpReasmOKs++;
 	return skb;
+
+out_invalid:
+	NETDEBUG(printk(KERN_ERR
+			"Invalid fragment list: Fragment over size.\n"));
+	kfree_skb(skb);
+	goto out_fail;
+out_nomem:
+ 	NETDEBUG(printk(KERN_ERR 
+			"IP: queue_glue: no memory for gluing queue %p\n",
+			qp));
+	goto out_fail;
+out_oversize:
+	if (net_ratelimit())
+		printk(KERN_INFO
+			"Oversized IP packet from %d.%d.%d.%d.\n",
+			NIPQUAD(qp->iph->saddr));
+out_fail:
+	ip_statistics.IpReasmFails++;
+	return NULL;
 }
 
 /* Process an incoming IP datagram fragment. */
 struct sk_buff *ip_defrag(struct sk_buff *skb)
 {
 	struct iphdr *iph = skb->nh.iph;
-	struct ipfrag *prev, *next, *tmp;
-	struct ipfrag *tfp;
+	struct ipfrag *prev, *next, *tmp, *tfp;
 	struct ipq *qp;
-	struct sk_buff *skb2;
 	unsigned char *ptr;
 	int flags, offset;
 	int i, ihl, end;
@@ -396,65 +411,58 @@
 	ip_statistics.IpReasmReqds++;
 
 	/* Start by cleaning up the memory. */
-	if(atomic_read(&ip_frag_mem)>sysctl_ipfrag_high_thresh)
+	if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
 		ip_evictor();
 
-	/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
+	/*
+	 * Look for the entry for this IP datagram in the
+	 * "incomplete datagrams" queue. If found, the
+	 * timer is removed.
+	 */
 	qp = ip_find(iph, skb->dst);
 
 	/* Is this a non-fragmented datagram? */
 	offset = ntohs(iph->frag_off);
 	flags = offset & ~IP_OFFSET;
 	offset &= IP_OFFSET;
-	if (((flags & IP_MF) == 0) && (offset == 0)) {
-		if (qp != NULL) {
-			/* Fragmented frame replaced by full unfragmented copy. */
-			ip_free(qp);
-		}
-		return skb;
-	}
 
 	offset <<= 3;		/* offset is in 8-byte chunks */
 	ihl = iph->ihl * 4;
 
-	/* If the queue already existed, keep restarting its timer as long
-	 * as we still are receiving fragments.  Otherwise, create a fresh
-	 * queue entry.
+	/*
+	 * Check whether to create a fresh queue entry. If the
+	 * queue already exists, its timer will be restarted as
+	 * long as we continue to receive fragments.
 	 */
 	if (qp) {
 		/* ANK. If the first fragment is received,
 		 * we should remember the correct IP header (with options)
 		 */
 	        if (offset == 0) {
+			/* Fragmented frame replaced by unfragmented copy? */
+			if ((flags & IP_MF) == 0)
+				goto out_freequeue;
 			qp->ihlen = ihl;
-			memcpy(qp->iph, iph, ihl+8);
+			memcpy(qp->iph, iph, (ihl + 8));
 		}
-		/* about 30 seconds */
-		mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time);
 	} else {
+		/* Fragmented frame replaced by unfragmented copy? */
+		if ((offset == 0) && ((flags & IP_MF) == 0))
+			goto out_skb;
+
 		/* If we failed to create it, then discard the frame. */
-		if ((qp = ip_create(skb, iph)) == NULL) {
-			kfree_skb(skb);
-			ip_statistics.IpReasmFails++;
-			return NULL;
-		}
+		qp = ip_create(skb, iph);
+		if (!qp)
+			goto out_freeskb;
 	}
 	
 	/* Attempt to construct an oversize packet. */
-	if(ntohs(iph->tot_len)+(int)offset>65535) {
-		if (net_ratelimit())
-			printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
-		frag_kfree_skb(skb);
-		ip_statistics.IpReasmFails++;
-		return NULL;
-	}	
+	if((ntohs(iph->tot_len) + ((int) offset)) > 65535)
+		goto out_oversize;
 
 	/* Determine the position of this fragment. */
 	end = offset + ntohs(iph->tot_len) - ihl;
 
-	/* Point into the IP datagram 'data' part. */
-	ptr = skb->data + ihl;
-
 	/* Is this the final fragment? */
 	if ((flags & IP_MF) == 0)
 		qp->len = end;
@@ -470,11 +478,14 @@
 		prev = next;
 	}
 
+	/* Point into the IP datagram 'data' part. */
+	ptr = skb->data + ihl;
+
 	/* We found where to put this one.  Check for overlap with
 	 * preceding fragment, and, if needed, align things so that
 	 * any overlaps are eliminated.
 	 */
-	if (prev != NULL && offset < prev->end) {
+	if ((prev != NULL) && (offset < prev->end)) {
 		i = prev->end - offset;
 		offset += i;	/* ptr into datagram */
 		ptr += i;	/* ptr into fragment data */
@@ -483,14 +494,14 @@
 	/* Look for overlap with succeeding segments.
 	 * If we can merge fragments, do it.
 	 */
-	for(tmp=next; tmp != NULL; tmp = tfp) {
+	for (tmp = next; tmp != NULL; tmp = tfp) {
 		tfp = tmp->next;
 		if (tmp->offset >= end)
-			break;		/* no overlaps at all */
+			break;		/* no overlaps at all	*/
 
-		i = end - next->offset;			/* overlap is 'i' bytes */
-		tmp->len -= i;				/* so reduce size of	*/
-		tmp->offset += i;			/* next fragment	*/
+		i = end - next->offset;	/* overlap is 'i' bytes */
+		tmp->len -= i;		/* so reduce size of	*/
+		tmp->offset += i;	/* next fragment	*/
 		tmp->ptr += i;
 
 		/* If we get a frag size of <= 0, remove it and the packet
@@ -513,15 +524,15 @@
 		}
 	}
 
-	/* Insert this fragment in the chain of fragments. */
-	tfp = NULL;
+	/*
+	 * Create a fragment to hold this skb.
+	 * No memory to save the fragment? throw the lot ...
+	 */
 	tfp = ip_frag_create(offset, end, skb, ptr);
+	if (!tfp)
+		goto out_freeskb;
 
-	/* No memory to save the fragment - so throw the lot. */
-	if (!tfp) {
-		frag_kfree_skb(skb);
-		return NULL;
-	}
+	/* Insert this fragment in the chain of fragments. */
 	tfp->prev = prev;
 	tfp->next = next;
 	if (prev != NULL)
@@ -538,8 +549,34 @@
 	 */
 	if (ip_done(qp)) {
 		/* Glue together the fragments. */
-		skb2 = ip_glue(qp);
-		return(skb2);
+ 		skb = ip_glue(qp);
+		/* Free the queue entry. */
+out_freequeue:
+		ip_free(qp);
+out_skb:
+		return skb;
 	}
+
+	/*
+	 * The queue is still active ... reset its timer.
+	 */
+out_timer:
+	mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
+out:
 	return NULL;
+
+	/*
+	 * Error exits ... we need to reset the timer if there's a queue.
+	 */
+out_oversize:
+	if (net_ratelimit())
+		printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
+			NIPQUAD(iph->saddr));
+	/* the skb isn't in a fragment, so fall through to free it */
+out_freeskb:
+	kfree_skb(skb);
+	ip_statistics.IpReasmFails++;
+	if (qp)
+		goto out_timer;
+	goto out;
 }
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.1.105/linux/net/ipv4/ip_fw.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/ip_fw.c	Thu Jun 11 22:52:35 1998
@@ -1,6 +1,6 @@
 /*
- * This code is heavily based on the code in ip_fw.c; see that file for
- * copyrights and attributions.  This code is basically GPL.
+ * This code is heavily based on the code on the old ip_fw.c code; see below for
+ * copyrights and attributions of the old code.  This code is basically GPL.
  *
  * 15-Aug-1997: Major changes to allow graphs for firewall rules.
  *              Paul Russell <Paul.Russell@rustcorp.com.au> and
@@ -26,10 +26,32 @@
  *              Added packet and byte counters for policy matches.
  * 26-Feb-1998: Fixed race conditions, added SMP support.
  * 18-Mar-1998: Fix SMP, fix race condition fix.
- * 1-May-1998:  Remove caching of device pointer, added caching
- *              for proc output (no longer order n^2).
+ * 1-May-1998:  Remove caching of device pointer.
+ * 12-May-1998: Allow tiny fragment case for TCP/UDP.
+ * 15-May-1998: Treat short packets as fragments, don't just block.
  */
 
+/*
+ *
+ * The origina Linux port was done Alan Cox, with changes/fixes from
+ * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
+ * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
+ * 
+ * Copyright from the original FreeBSD version follows:
+ *
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.  */
+
+
 #include <linux/config.h>
 
 #include <asm/uaccess.h>
@@ -76,6 +98,12 @@
  *
  * For SMP (kernel v2.1+), multiply this by # CPUs.
  *
+ * [Note that this in not correct for 2.2 - because the socket code always
+ *  uses lock_kernel() to serialize, and bottom halves (timers and net_bhs)
+ *  only run on one CPU at a time.  This will probably change for 2.3.
+ *  It is still good to use spinlocks because that avoids the global cli() 
+ *  for updating the tables, which is rather costly in SMP kernels -AK]
+ *
  * This means counters and backchains can get corrupted if no precautions
  * are taken.
  *
@@ -573,14 +601,10 @@
 		return FW_BLOCK;
 	}
 
-	/* Check for too-small packets (not non-first fragments).
-	 * For each protocol, we assume that we can get the required
-	 * information, eg. port number or ICMP type.  If this fails,
-	 * reject it. 
-	 * 
-	 * Sizes might as well be rounded up to 8 here, since either
-	 * there are more fragments to come (which must be on 8-byte
-	 * boundaries), or this is a bogus packet anyway.
+	/* If we can't investigate ports, treat as fragment.  It's
+	 * either a trucated whole packet, or a truncated first
+	 * fragment, or a TCP first fragment of length 8-15, in which
+	 * case the above rule stops reassembly.
 	 */
 	if (offset == 0) {
 		unsigned int size_req;
@@ -598,13 +622,7 @@
 		default:
 			size_req = 0;
 		}
-		if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
-			if (!testing && net_ratelimit()) {
-				printk("Packet too short.\n");
-				dump_packet(ip,rif,NULL,NULL,0,0);
-			}
-			return FW_BLOCK;
-		}
+		offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);
 	}
 
 	src = ip->saddr;
@@ -613,10 +631,10 @@
 	
 	/*
 	 *	If we got interface from which packet came
-	 *	we can use the address directly. This is unlike
-	 *	4.4BSD derived systems that have an address chain
-	 *	per device. We have a device per address with dummy
-	 *	devices instead.
+	 *	we can use the address directly. Linux 2.1 now uses address
+	 *	chains per device too, but unlike BSD we first check if the
+	 *	incoming packet matches a device address and the routing
+	 *	table before calling the firewall. 
 	 */
 	 
 	dprintf("Packet ");
@@ -1117,7 +1135,7 @@
 		return NULL;
 	}
 
-#if DEBUG_IP_FIREWALL_USER
+#ifdef DEBUG_IP_FIREWALL_USER
 	/* These are sanity checks that don't really matter.
 	 * We can get rid of these once testing is complete. 
 	 */
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.1.105/linux/net/ipv4/ip_input.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/ip_input.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.30 1998/05/08 01:54:54 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.31 1998/05/17 02:19:15 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -97,7 +97,6 @@
  *		Alan Cox	:	Multicast routing hooks
  *		Jos Vos		:	Do accounting *before* call_in_firewall
  *	Willy Konynenberg	:	Transparent proxying support
- *	Mike McLagan		:	Routing by source
  *
  *  
  *
@@ -470,6 +469,15 @@
 
 	/*
 	 *	See if the firewall wants to dispose of the packet. 
+	 *
+	 *	Note: the current standard firewall code expects that the 
+	 *	destination address was already checked against the interface 
+	 *	address lists.
+	 *
+	 *	If this code is ever moved in front of ip_route_input() you need
+	 *	to fix the fw code [moving it might be a good idea anyways,
+	 *	so that we can firewall against potentially bugs in the options
+	 *	or routing code]
 	 */
 	
 #ifdef	CONFIG_FIREWALL
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.1.105/linux/net/ipv4/ip_output.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/ip_output.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.57 1998/05/08 01:54:56 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -99,6 +99,7 @@
 {
 	struct rtable *rt = (struct rtable *)skb->dst;
 	struct iphdr *iph;
+	struct device *dev;
 	
 	/* Build the IP header. */
 	if (opt)
@@ -126,10 +127,19 @@
 		ip_options_build(skb, opt, daddr, rt, 0);
 	}
 
+	dev = rt->u.dst.dev;
+
+	if (call_out_firewall(PF_INET, dev, iph, NULL, &skb) < FW_ACCEPT)
+		goto drop;
+
 	ip_send_check(iph);
 
 	/* Send it out. */
 	skb->dst->output(skb);
+	return;
+
+drop:
+	kfree_skb(skb);
 }
 
 int __ip_finish_output(struct sk_buff *skb)
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.1.105/linux/net/ipv4/ipconfig.c	Fri May  8 23:14:57 1998
+++ linux/net/ipv4/ipconfig.c	Sat Jun 13 11:46:12 1998
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.12 1998/05/03 14:30:53 alan Exp $
+ *  $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -248,6 +248,11 @@
 
 __initfunc(int ic_defaults(void))
 {
+	/*
+	 *	At this point we have no userspace running so need not
+	 *	claim locks on system_utsname
+	 */
+	 
 	if (!ic_host_name_set)
 		strcpy(system_utsname.nodename, in_ntoa(ic_myaddr));
 
@@ -1072,8 +1077,8 @@
 }
 
 /*
- *  Decode any IP configuration options in the "ipconfig" kernel command
- *  line parameter. It consists of option fields separated by colons in
+ *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
+ *  command line parameter. It consists of option fields separated by colons in
  *  the following order:
  *
  *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.105/linux/net/ipv4/route.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/route.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.50 1998/05/13 06:23:25 davem Exp $
+ * Version:	$Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1095,11 +1095,12 @@
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->u.dst.input= ip_local_deliver;
+	rth->rt_flags 	= flags|RTCF_LOCAL;
 	if (res.type == RTN_UNREACHABLE) {
 		rth->u.dst.input= ip_error;
-		rth->u.dst.error= err;
+		rth->u.dst.error= -err;
+		rth->rt_flags 	&= ~RTCF_LOCAL;
 	}
-	rth->rt_flags 	= flags|RTCF_LOCAL;
 	rth->rt_type	= res.type;
 	skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
 	return 0;
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c
--- v2.1.105/linux/net/ipv4/syncookies.c	Sun Jun  7 11:16:40 1998
+++ linux/net/ipv4/syncookies.c	Thu Jun 11 22:52:35 1998
@@ -9,7 +9,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  * 
- *  $Id: syncookies.c,v 1.5 1998/04/03 09:49:46 freitag Exp $
+ *  $Id: syncookies.c,v 1.6 1998/06/10 07:29:22 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.105/linux/net/ipv4/tcp.c	Sat May  2 14:19:55 1998
+++ linux/net/ipv4/tcp.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.114 1998/04/26 01:11:33 davem Exp $
+ * Version:	$Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1069,6 +1069,13 @@
 
 	add_wait_queue(sk->sleep, &wait);
 	lock_sock(sk);
+	
+	/*
+	 *	BUG BUG BUG
+	 *	This violates 1003.1g compliance. We must wait for 
+	 *	data to exist even if we read none!
+	 */
+	 
 	while (len > 0) {
 		struct sk_buff * skb;
 		u32 offset;
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.105/linux/net/ipv4/tcp_input.c	Fri May  8 23:14:57 1998
+++ linux/net/ipv4/tcp_input.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.118 1998/05/06 04:53:48 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1686,8 +1686,13 @@
 			}
 		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
 			/* Bulk data transfer: receiver */
-			if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) 
+			if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+				/* We must send an ACK for zero window probes. */
+				if (!before(TCP_SKB_CB(skb)->seq,
+						tp->rcv_wup + tp->rcv_wnd))
+					tcp_send_ack(sk);
 				goto discard;
+			}
 			
 			skb_pull(skb,th->doff*4);
 
@@ -1714,15 +1719,21 @@
 	}
 
 	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
-		if (!th->rst) {
-			if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
-				SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
-					   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-					   tp->rcv_wup, tp->rcv_wnd);
-			}
-			tcp_send_ack(sk);
+		/* RFC793, page 37: "In all states except SYN-SENT, all reset
+		 * (RST) segments are validated by checking their SEQ-fields."
+		 * And page 69: "If an incoming segment is not acceptable,
+		 * an acknowledgment should be sent in reply (unless the RST bit
+		 * is set, if so drop the segment and return)".
+		 */
+		if (th->rst)
 			goto discard;
+		if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+			SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
+				   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+				   tp->rcv_wup, tp->rcv_wnd);
 		}
+		tcp_send_ack(sk);
+		goto discard;
 	}
 
 	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.105/linux/net/ipv4/tcp_output.c	Fri May  8 23:14:57 1998
+++ linux/net/ipv4/tcp_output.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.90 1998/05/06 04:59:15 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -331,16 +331,18 @@
  *
  * Note, we don't "adjust" for TIMESTAMP or SACK option bytes.
  */
-u32 __tcp_select_window(struct sock *sk)
+u32 __tcp_select_window(struct sock *sk, u32 cur_win)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	unsigned int mss = sk->mss;
-	unsigned int free_space;
-	u32 window, cur_win;
+	int free_space;
+	u32 window;
 
+	/* Sometimes free_space can be < 0. */
 	free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2;
 	if (tp->window_clamp) {
-		free_space = min(tp->window_clamp, free_space);
+		if (free_space > ((int) tp->window_clamp))
+			free_space = tp->window_clamp;
 		mss = min(tp->window_clamp, mss);
 	} else {
 		printk("tcp_select_window: tp->window_clamp == 0.\n");
@@ -351,8 +353,7 @@
 		printk("tcp_select_window: sk->mss fell to 0.\n");
 	}
 	
-	cur_win = tcp_receive_window(tp);
-	if (free_space < sk->rcvbuf/4 && free_space < mss/2) {
+	if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) {
 		window = 0;
 	} else {
 		/* Get the largest window that is a nice multiple of mss.
@@ -364,8 +365,9 @@
 		 * is too small.
 		 */
 		window = tp->rcv_wnd;
-		if ((window <= (free_space - mss)) || (window > free_space))
-			window = (free_space/mss)*mss;
+		if ((((int) window) <= (free_space - ((int) mss))) ||
+				(((int) window) > free_space))
+			window = (((unsigned int) free_space)/mss)*mss;
 	}
 	return window;
 }
diff -u --recursive --new-file v2.1.105/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.105/linux/net/ipv4/udp.c	Thu May 14 19:47:45 1998
+++ linux/net/ipv4/udp.c	Thu Jun 11 22:52:35 1998
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.56 1998/05/08 21:06:30 davem Exp $
+ * Version:	$Id: udp.c,v 1.57 1998/05/14 06:32:44 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -57,6 +57,8 @@
  *		Andi Kleen	:	Some cleanups, cache destination entry
  *					for connect. 
  *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
+ *		Melvin Smith	:	Check msg_name not msg_namelen in sendto(),
+ *					return ENOTCONN for unconnected sockets (POSIX)
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -657,7 +659,7 @@
 	 *	Get and verify the address. 
 	 */
 	 
-	if (msg->msg_namelen) {
+	if (msg->msg_name) {
 		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
 		if (msg->msg_namelen < sizeof(*usin))
 			return(-EINVAL);
@@ -684,7 +686,7 @@
 		 */
 	} else {
 		if (sk->state != TCP_ESTABLISHED)
-			return -EINVAL;
+			return -ENOTCONN;
 		ufh.daddr = sk->daddr;
 		ufh.uh.dest = sk->dport;
 
diff -u --recursive --new-file v2.1.105/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.105/linux/net/ipv6/af_inet6.c	Sun Jun  7 11:16:40 1998
+++ linux/net/ipv6/af_inet6.c	Thu Jun 11 22:52:36 1998
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.33 1998/05/08 21:06:32 davem Exp $
+ *	$Id: af_inet6.c,v 1.36 1998/06/10 07:29:25 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -422,6 +422,11 @@
 }
 #endif
 
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
 #ifdef MODULE
 int init_module(void)
 #else
@@ -515,7 +520,7 @@
 void cleanup_module(void)
 {
 	/* First of all disallow new sockets creation. */
-	sock_unregister(AF_INET6);
+	sock_unregister(PF_INET6);
 #ifdef CONFIG_PROC_FS
 	proc_net_unregister(proc_net_raw6.low_ino);
 	proc_net_unregister(proc_net_tcp6.low_ino);
diff -u --recursive --new-file v2.1.105/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.105/linux/net/ipv6/tcp_ipv6.c	Fri May  8 23:14:57 1998
+++ linux/net/ipv6/tcp_ipv6.c	Thu Jun 11 22:52:36 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.81 1998/05/03 14:31:10 alan Exp $
+ *	$Id: tcp_ipv6.c,v 1.82 1998/06/11 03:15:52 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -64,9 +64,7 @@
 {
 	int hashent = (lport ^ fport);
 
-	hashent ^= (laddr->s6_addr32[0] ^ laddr->s6_addr32[1]);
-	hashent ^= (faddr->s6_addr32[0] ^ faddr->s6_addr32[1]);
-	hashent ^= (faddr->s6_addr32[2] ^ faddr->s6_addr32[3]);
+	hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
 	return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
 }
 
@@ -145,6 +143,13 @@
 
 static void tcp_v6_hash(struct sock *sk)
 {
+	/* Well, I know that it is ugly...
+	   All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
+	 */
+	if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
+		tcp_prot.hash(sk);
+		return;
+	}
 	if(sk->state != TCP_CLOSE) {
 		struct sock **skp;
 
@@ -415,8 +420,14 @@
 		if (err) {
 			sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
 			sk->backlog_rcv = tcp_v6_do_rcv;
+		} else {
+			/* Yuup... And it is not the only place... --ANK */
+			ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+				      sk->saddr);
+			ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF),
+				      sk->rcv_saddr);
 		}
-		
+
 		return err;
 	}
 
diff -u --recursive --new-file v2.1.105/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.105/linux/net/ipv6/udp.c	Fri May  8 23:14:57 1998
+++ linux/net/ipv6/udp.c	Thu Jun 11 22:52:36 1998
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.28 1998/05/03 14:31:12 alan Exp $
+ *	$Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -689,7 +689,7 @@
 		}
 	} else {
 		if (sk->state != TCP_ESTABLISHED)
-			return(-EINVAL);
+			return(-ENOTCONN);
 		
 		udh.uh.dest = sk->dport;
 		daddr = &sk->net_pinfo.af_inet6.daddr;
diff -u --recursive --new-file v2.1.105/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h
--- v2.1.105/linux/net/sched/cls_rsvp.h	Thu May 14 19:47:45 1998
+++ linux/net/sched/cls_rsvp.h	Thu Jun 11 22:52:36 1998
@@ -525,6 +525,7 @@
 					break;
 			f->next = *fp;
 			*fp = f;
+			*arg = (unsigned long)f;
 			return 0;
 		}
 	}
diff -u --recursive --new-file v2.1.105/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.1.105/linux/net/sched/sch_cbq.c	Thu May 14 19:47:45 1998
+++ linux/net/sched/sch_cbq.c	Thu Jun 11 22:52:36 1998
@@ -1435,7 +1435,7 @@
 
 	if (cl->police) {
 		opt.police = cl->police;
-		RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
+		RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
 	}
 	return skb->len;
 
diff -u --recursive --new-file v2.1.105/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c
--- v2.1.105/linux/net/sched/sch_teql.c	Thu May 14 19:47:45 1998
+++ linux/net/sched/sch_teql.c	Thu Jun 11 22:52:36 1998
@@ -252,7 +252,7 @@
 		return 0;
 	}
 	neigh_release(n);
-	return (skb_res != NULL);
+	return (skb_res == NULL) ? -EAGAIN : 1;
 }
 
 static __inline__ int
@@ -280,7 +280,7 @@
 
 restart:
 	nores = 0;
-	busy = 1;
+	busy = 0;
 
 	if ((q = start) == NULL)
 		goto drop;
@@ -288,34 +288,39 @@
 	do {
 		struct device *slave = q->dev;
 		
-		if (!slave->tbusy && slave->qdisc_sleeping == q) {
-			busy = 0;
-			
-			if (q->h.forw == NULL) {
-				q->h.forw = qdisc_head.forw;
-				qdisc_head.forw = &q->h;
-			}
+		if (slave->qdisc_sleeping != q)
+			continue;
+		if (slave->tbusy) {
+			busy = 1;
+			continue;
+		}
 
-			switch (teql_resolve(skb, skb_res, slave)) {
-			case 0:
-				if (slave->hard_start_xmit(skb, slave) == 0) {
-					master->slaves = NEXT_SLAVE(q);
-					dev->tbusy = 0;
-					master->stats.tx_packets++;
-					master->stats.tx_bytes += len;
-					return 0;
-				}
-				break;
-			case 1:
+		if (q->h.forw == NULL) {
+			q->h.forw = qdisc_head.forw;
+			qdisc_head.forw = &q->h;
+		}
+
+		switch (teql_resolve(skb, skb_res, slave)) {
+		case 0:
+			if (slave->hard_start_xmit(skb, slave) == 0) {
 				master->slaves = NEXT_SLAVE(q);
 				dev->tbusy = 0;
-				return 0;
-			default:
-				nores = 1;
-				break;
+				master->stats.tx_packets++;
+				master->stats.tx_bytes += len;
+					return 0;
 			}
-			__skb_pull(skb, skb->nh.raw - skb->data);
+			if (dev->tbusy)
+				busy = 1;
+			break;
+		case 1:
+			master->slaves = NEXT_SLAVE(q);
+			dev->tbusy = 0;
+			return 0;
+		default:
+			nores = 1;
+			break;
 		}
+		__skb_pull(skb, skb->nh.raw - skb->data);
 	} while ((q = NEXT_SLAVE(q)) != start);
 
 	if (nores && skb_res == NULL) {
diff -u --recursive --new-file v2.1.105/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.105/linux/net/unix/af_unix.c	Fri May  8 23:14:58 1998
+++ linux/net/unix/af_unix.c	Tue Jun  9 01:21:50 1998
@@ -86,6 +86,7 @@
 #include <linux/proc_fs.h>
 #include <net/scm.h>
 #include <linux/init.h>
+#include <linux/poll.h>
 
 #include <asm/checksum.h>
 
@@ -100,6 +101,8 @@
 
 #define UNIX_ABSTRACT(sk)	((sk)->protinfo.af_unix.addr->hash!=UNIX_HASH_SIZE)
 
+static void unix_destroy_socket(unix_socket *sk);
+
 extern __inline__ unsigned unix_hash_fold(unsigned hash)
 {
 	hash ^= hash>>16;
@@ -127,7 +130,7 @@
 
 extern __inline__ int unix_unlock(unix_socket *sk)
 {
-	return sk->sock_readers--;
+	return --sk->sock_readers;
 }
 
 extern __inline__ int unix_locked(unix_socket *sk)
@@ -254,6 +257,10 @@
 	if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
 		sk_free(sk);
+		unix_remove_socket(sk);
+	
+		/* socket destroyed, decrement count		      */
+		MOD_DEC_USE_COUNT;
 		return;
 	}
 	
@@ -273,28 +280,56 @@
 	sk->timer.function=unix_destroy_timer;
 	add_timer(&sk->timer);
 }
+
+static int unix_release_sock (unix_socket *sk)
+{
+	unix_socket *skpair;
+
+	sk->state_change(sk);
+	sk->dead=1;
+	sk->socket = NULL;
+
+	skpair=unix_peer(sk);
+
+	/* Try to flush out this socket. Throw out buffers at least */
+	unix_destroy_socket(sk);
+
+	if (skpair!=NULL)
+	{
+		if (sk->type==SOCK_STREAM && unix_our_peer(sk, skpair))
+		{
+			skpair->state_change(skpair);
+			skpair->shutdown=SHUTDOWN_MASK;	/* No more writes*/
+		}
+		unix_unlock(skpair); /* It may now die */
+	}
+
+	/*
+	 * Fixme: BSD difference: In BSD all sockets connected to use get
+	 *	  ECONNRESET and we die on the spot. In Linux we behave
+	 *	  like files and pipes do and wait for the last
+	 *	  dereference.
+	 *
+	 * Can't we simply set sock->err?
+	 */
+
+	unix_gc();		/* Garbage collect fds */	
+	return 0;
+}
 	
 static void unix_destroy_socket(unix_socket *sk)
 {
 	struct sk_buff *skb;
 
-	unix_remove_socket(sk);
-	
 	while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
 	{
 		if(sk->state==TCP_LISTEN)
 		{
-			unix_socket *osk=skb->sk;
-			osk->state=TCP_CLOSE;
-			kfree_skb(skb);			/* Now surplus - free the skb first before the socket */
-			osk->state_change(osk);		/* So the connect wakes and cleans up (if any) */
-			/* osk will be destroyed when it gets to close or the timer fires */			
-		}
-		else
-		{
-			/* passed fds are erased in the kfree_skb hook */
-			kfree_skb(skb);
+			unix_unlock(sk);
+			unix_release_sock(skb->sk);
 		}
+		/* passed fds are erased in the kfree_skb hook	      */
+		kfree_skb(skb);
 	}
 	
 	if(sk->protinfo.af_unix.dentry!=NULL)
@@ -306,15 +341,18 @@
 	if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
 		sk_free(sk);
+		unix_remove_socket(sk);
+	
+		/* socket destroyed, decrement count		      */
+		MOD_DEC_USE_COUNT;
 	}
 	else
 	{
+		sk->state=TCP_CLOSE;
 		sk->dead=1;
 		unix_delayed_delete(sk);	/* Try every so often until buffers are all freed */
 	}
 
-	/* socket destroyed, decrement count */
-	MOD_DEC_USE_COUNT;
 }
 
 static int unix_listen(struct socket *sock, int backlog)
@@ -332,23 +370,29 @@
 		sk->state_change(sk);
 	sk->state=TCP_LISTEN;
 	sock->flags |= SO_ACCEPTCON;
+	/* set credentials so connect can copy them */
+	sk->peercred.pid = current->pid;
+	sk->peercred.uid = current->euid;
+	sk->peercred.gid = current->egid;
 	return 0;
 }
 
 extern struct proto_ops unix_stream_ops;
 extern struct proto_ops unix_dgram_ops;
 
-static int unix_create(struct socket *sock, int protocol)
+static int unix_create1(struct socket *sock, struct sock **skp, int protocol)
 {
 	struct sock *sk;
 
-	sock->state = SS_UNCONNECTED;
-
 	if (protocol && protocol != PF_UNIX)
 		return -EPROTONOSUPPORT;
 
-	switch (sock->type)
+	if (sock)
 	{
+		sock->state = SS_UNCONNECTED;
+
+		switch (sock->type)
+		{
 		case SOCK_STREAM:
 			sock->ops = &unix_stream_ops;
 			break;
@@ -363,6 +407,7 @@
 			break;
 		default:
 			return -ESOCKTNOSUPPORT;
+		}
 	}
 	sk = sk_alloc(PF_UNIX, GFP_KERNEL, 1);
 	if (!sk)
@@ -378,51 +423,32 @@
 	sk->mtu=4096;
 	sk->protinfo.af_unix.list=&unix_sockets_unbound;
 	unix_insert_socket(sk);
-
+	if (skp)
+		*skp =sk;
+	
 	/* socket created, increment count */
 	MOD_INC_USE_COUNT;
 
 	return 0;
 }
 
+static int unix_create(struct socket *sock, int protocol)
+{
+	return unix_create1(sock, NULL, protocol);
+}
+
 static int unix_release(struct socket *sock, struct socket *peer)
 {
 	unix_socket *sk = sock->sk;
-	unix_socket *skpair;
 
 	if (!sk)
 		return 0;
 	
+	sock->sk = NULL;
 	if (sock->state != SS_UNCONNECTED)
 		sock->state = SS_DISCONNECTING;
 
-	sk->state_change(sk);
-	sk->dead=1;
-	skpair=unix_peer(sk);
-	if (sock->type==SOCK_STREAM && skpair)
-	{
-		if (unix_our_peer(sk, skpair))
-			skpair->shutdown=SHUTDOWN_MASK;	/* No more writes */
-		if (skpair->state!=TCP_LISTEN)
-			skpair->state_change(skpair);	/* Wake any blocked writes */
-	}
-	if (skpair!=NULL)
-		unix_unlock(skpair);			/* It may now die */
-	unix_peer(sk)=NULL;				/* No pair */
-	unix_destroy_socket(sk);			/* Try to flush out this socket. Throw out buffers at least */
-	unix_gc();					/* Garbage collect fds */	
-
-	/*
-	 *	FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
-	 *	Linux we behave like files and pipes do and wait for the last dereference.
-	 */
-	if (sk->socket)
-	{
-		sk->socket = NULL;
-		sock->sk = NULL;
-	}
-	 
-	return 0;
+	return unix_release_sock (sk);
 }
 
 static int unix_autobind(struct socket *sock)
@@ -625,18 +651,17 @@
 	return 0;
 }
 
-static int unix_stream_connect1(struct socket *sock, struct msghdr *msg,
-				int len, struct unix_skb_parms *cmsg, int nonblock)
+static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
+			       int addr_len, int flags)
 {
-	struct sockaddr_un *sunaddr=(struct sockaddr_un *)msg->msg_name;
-	struct sock *sk = sock->sk;
+	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
+	struct sock *sk = sock->sk, *newsk;
 	unix_socket *other;
 	struct sk_buff *skb;
 	int err;
 	unsigned hash;
-	int addr_len;
 
-	addr_len = unix_mkname(sunaddr, msg->msg_namelen, &hash);
+	addr_len = unix_mkname(sunaddr, addr_len, &hash);
 	if (addr_len < 0)
 		return addr_len;
 
@@ -648,123 +673,80 @@
 		case SS_CONNECTED:
 			/* Socket is already connected */
 			return -EISCONN;
-		case SS_CONNECTING:
-			/* Not yet connected... we will check this. */
-			break;
 		default:
 			return(-EINVAL);
 	}
 
+	/*
+	 *	Now ready to connect
+	 */
+	 
+	sk->state=TCP_CLOSE;
+	
+	/*  Find listening sock */
+	other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
+	if(other==NULL)
+		goto out;
 
-	if (unix_peer(sk))
-	{
-		if (sock->state==SS_CONNECTING && sk->state==TCP_ESTABLISHED)
-		{
-			sock->state=SS_CONNECTED;
-			if (!sk->protinfo.af_unix.addr)
-				unix_autobind(sock);
-			return 0;
-		}
-		if (sock->state==SS_CONNECTING && sk->state == TCP_CLOSE)
-		{
-			sock->state=SS_UNCONNECTED;
-			return -ECONNREFUSED;
-		}
-		if (sock->state!=SS_CONNECTING)
-			return -EISCONN;
-		if (nonblock)
-			return -EALREADY;
-		/*
-		 *	Drop through the connect up logic to the wait.
-		 */
-	}
+	/* create new sock for complete connection */
+	err = unix_create1(NULL, &newsk, PF_UNIX);
+	if (newsk == NULL)
+		goto out;
 
-	if (sock->state==SS_UNCONNECTED)
-	{
+	/* Allocate skb for sending to listening sock */
+	skb=sock_alloc_send_skb(newsk, 0, 0, flags&O_NONBLOCK, &err);
+	if(skb==NULL)
 		/*
-		 *	Now ready to connect
+		 * if it gives EAGAIN we should give back
+		 * EINPROGRESS. But this should not happen since the
+		 * socket should have some writespace left (it did not
+		 * allocate any memory until now)
 		 */
-	 
-		skb=sock_alloc_send_skb(sk, len, 0, nonblock, &err); /* Marker object */
-		if(skb==NULL)
-			goto out;
-		memcpy(&UNIXCB(skb), cmsg, sizeof(*cmsg));
-		if (len) {
-			err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov,
-						len);
-			if (err)
-				goto out_free;
-		}
+		goto out_release;
 
-		sk->state=TCP_CLOSE;
-		other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
-		if(other==NULL)
-			goto out_free;
-		other->ack_backlog++;
-		unix_peer(sk)=other;
-		skb_queue_tail(&other->receive_queue,skb);
-		sk->state=TCP_SYN_SENT;
-		sock->state=SS_CONNECTING;
-		other->data_ready(other,0);		/* Wake up ! */		
-	}
-			
-	
-	/* Wait for an accept */
-	
-	while(sk->state==TCP_SYN_SENT)
-	{
-		if(nonblock)
-			return -EINPROGRESS;
-		interruptible_sleep_on(sk->sleep);
-		if(signal_pending(current))
-			return -ERESTARTSYS;
-	}
-	
-	/*
-	 *	Has the other end closed on us ?
-	 */
-	 
-	if(sk->state==TCP_CLOSE)
-	{
-		unix_unlock(unix_peer(sk));
-		unix_peer(sk)=NULL;
-		sock->state=SS_UNCONNECTED;
-		return -ECONNREFUSED;
-	}
-	
-	/*
-	 *	Amazingly it has worked
-	 */
-	 
+	UNIXCB(skb).attr = MSG_SYN;
+
+	/* set up connecting socket */
 	sock->state=SS_CONNECTED;
 	if (!sk->protinfo.af_unix.addr)
 		unix_autobind(sock);
+	unix_peer(sk)=newsk;
+	unix_lock(sk);
+	sk->state=TCP_ESTABLISHED;
+	/* Set credentials */
+	sk->peercred = other->peercred;
+	
+	/* set up newly created sock */
+	unix_peer(newsk)=sk;
+	unix_lock(newsk);
+	newsk->state=TCP_ESTABLISHED;
+	newsk->type=SOCK_STREAM;
+	newsk->peercred.pid = current->pid;
+	newsk->peercred.uid = current->euid;
+	newsk->peercred.gid = current->egid;
+
+	/* copy address information from listening to new sock*/
+	if (other->protinfo.af_unix.addr)
+	{
+		atomic_inc(&other->protinfo.af_unix.addr->refcnt);
+		newsk->protinfo.af_unix.addr=other->protinfo.af_unix.addr;
+	}
+	if (other->protinfo.af_unix.dentry)
+		newsk->protinfo.af_unix.dentry=dget(other->protinfo.af_unix.dentry);
+
+	/* send info to listening sock */
+	other->ack_backlog++;
+	skb_queue_tail(&other->receive_queue,skb);
+	other->data_ready(other,0);		/* Wake up !	      */
+
 	return 0;
 
-out_free:
-	kfree_skb(skb);
+out_release:
+	unix_destroy_socket(newsk);
 out:
 	return err;
 }
 
-
-static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
-			       int addr_len, int flags)
-{
-	struct msghdr msg;
-	struct unix_skb_parms cmsg;
-
-	msg.msg_name = uaddr;
-	msg.msg_namelen = addr_len;
-	cmsg.fp = NULL;
-	cmsg.attr = MSG_SYN;
-	cmsg.creds.pid = current->pid;
-	cmsg.creds.uid = current->euid;
-	cmsg.creds.gid = current->egid;
-
-	return unix_stream_connect1(sock, &msg, 0, &cmsg, flags&O_NONBLOCK);
-}
-
 static int unix_socketpair(struct socket *socka, struct socket *sockb)
 {
 	struct sock *ska=socka->sk, *skb = sockb->sk;
@@ -802,14 +784,6 @@
 	if (sk->state!=TCP_LISTEN)
 		return -EINVAL;
 		
-	if (sk->protinfo.af_unix.addr)
-	{
-		atomic_inc(&sk->protinfo.af_unix.addr->refcnt);
-		newsk->protinfo.af_unix.addr=sk->protinfo.af_unix.addr;
-	}
-	if (sk->protinfo.af_unix.dentry)
-		newsk->protinfo.af_unix.dentry=dget(sk->protinfo.af_unix.dentry);
-		
 	for (;;)
 	{
 		skb=skb_dequeue(&sk->receive_queue);
@@ -834,20 +808,19 @@
 
 	tsk=skb->sk;
 	sk->ack_backlog--;
-	unix_peer(newsk)=tsk;
-	unix_peer(tsk)=newsk;
-	tsk->state=TCP_ESTABLISHED;
-	newsk->state=TCP_ESTABLISHED;
-	memcpy(&newsk->peercred, UNIXCREDS(skb), sizeof(struct ucred));
-	tsk->peercred.pid = current->pid;
-	tsk->peercred.uid = current->euid;
-	tsk->peercred.gid = current->egid;
-	unix_lock(newsk);		/* Swap lock over */
-	unix_unlock(sk);		/* Locked to child socket not master */
-	unix_lock(tsk);			/* Back lock */
-	kfree_skb(skb);			/* The buffer is just used as a tag */
-	tsk->state_change(tsk);		/* Wake up any sleeping connect */
-	sock_wake_async(tsk->socket, 0);
+	unix_unlock(sk);	/* No longer locked to master	   */
+	kfree_skb(skb);
+
+	/* attach accepted sock to socket */
+	newsock->state=SS_CONNECTED;
+	newsock->sk=tsk;
+	tsk->sleep=newsk->sleep;
+	tsk->socket=newsock;
+
+	/* destroy handed sock */
+	newsk->socket = NULL;
+	unix_destroy_socket(newsk);
+
 	return 0;
 }
 
@@ -1389,6 +1362,38 @@
 	return(0);
 }
 
+static unsigned int unix_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	unsigned int mask;
+
+	poll_wait(file, sk->sleep, wait);
+	mask = 0;
+
+	/* exceptional events? */
+	if (sk->err)
+		mask |= POLLERR;
+	if (sk->shutdown & RCV_SHUTDOWN)
+		mask |= POLLHUP;
+
+	/* readable? */
+	if (!skb_queue_empty(&sk->receive_queue))
+		mask |= POLLIN | POLLRDNORM;
+
+	/* Connection-based need to check for termination and startup */
+	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
+		mask |= POLLHUP;
+
+	/*
+	 * we set writable also when the other side has shut down the
+	 * connection. This prevents stuck sockets.
+	 */
+	if (sk->sndbuf - atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE)
+			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+	return mask;
+}
+
 #ifdef CONFIG_PROC_FS
 static int unix_read_proc(char *buffer, char **start, off_t offset,
 			  int length, int *eof, void *data)
@@ -1410,7 +1415,9 @@
 			0,
 			s->socket ? s->socket->flags : 0,
 			s->type,
-			s->socket ? s->socket->state : 0,
+			s->socket ? s->socket->state :
+			     (s->state == TCP_ESTABLISHED ?
+			      SS_CONNECTING : SS_DISCONNECTING),
 			s->socket ? s->socket->inode->i_ino : 0);
 
 		if (s->protinfo.af_unix.addr)
@@ -1426,7 +1433,7 @@
 		}
 		buffer[len++]='\n';
 		
-		pos=begin+len;
+		pos+=len;
 		if(pos<offset)
 		{
 			len=0;
@@ -1441,6 +1448,8 @@
 	len-=(offset-begin);
 	if(len>length)
 		len=length;
+	if (len < 0)
+		len = 0;
 	return len;
 }
 #endif
@@ -1455,7 +1464,7 @@
 	unix_socketpair,
 	unix_accept,
 	unix_getname,
-	datagram_poll,
+	unix_poll,
 	unix_ioctl,
 	unix_listen,
 	unix_shutdown,
@@ -1537,6 +1546,9 @@
 	sock_unregister(PF_UNIX);
 #ifdef CONFIG_SYSCTL
 	unix_sysctl_unregister();
+#endif
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("net/unix", 0);
 #endif
 }
 #endif
diff -u --recursive --new-file v2.1.105/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.1.105/linux/scripts/mkdep.c	Mon Jan  5 01:41:01 1998
+++ linux/scripts/mkdep.c	Sat Jun 13 13:36:13 1998
@@ -118,7 +118,7 @@
 /*
  * Clear the set of configuration strings.
  */
-void clear_config( )
+void clear_config(void)
 {
 	len_config = 0;
 	define_config(0, "", 0);
@@ -193,7 +193,7 @@
  * Thus, there is one memory access per sizeof(unsigned long) characters.
  */
 
-#if defined(__alpha__) || defined(__i386__)
+#if defined(__alpha__) || defined(__i386__) || defined(__arm__)
 #define LE_MACHINE
 #endif
 
