diff -u --recursive --new-file v1.3.95/linux/CREDITS linux/CREDITS
--- v1.3.95/linux/CREDITS	Wed Apr 24 17:00:32 1996
+++ linux/CREDITS	Sat Apr 27 14:24:47 1996
@@ -1372,3 +1372,7 @@
 S: 3078 Sulphur Spring Court
 S: San Jose, California 95148
 S: USA
+
+# Don't add your name here, unless you really _are_ after Leonard
+# alphabetically.  Leonard is very proud of being the last entry,
+# and this file really _is_ supposed to be in alphabetic order.
diff -u --recursive --new-file v1.3.95/linux/Documentation/Changes linux/Documentation/Changes
--- v1.3.95/linux/Documentation/Changes	Sun Apr 21 12:38:59 1996
+++ linux/Documentation/Changes	Sat Apr 27 14:40:12 1996
@@ -2,9 +2,9 @@
 important packages for Linux as well as instructions for newcomers to
 the 1.3.x series of kernels.
 
-Last updated: Apr 17, 1996.
-Authors: Alessandro Sigala (ssigala@globalnet.it) and Chris Ricker
-(gt1355b@prism.gatech.edu).
+Last updated: Apr 27, 1996.
+Author: Chris Ricker (gt1355b@prism.gatech.edu), based on the original by
+Alessandro Sigala (ssigala@globalnet.it.
 
 Note:  Due to time constraints, Alessandro is getting out of the Changes
 business and I'll be picking up the job.  Be gentle while I get my feet
@@ -14,11 +14,11 @@
 ****************
 
 - Kernel modules	 Stable: 1.3.57, Exp: 1.3.69f
-- PPP daemon		 Stable: 2.2.0e, Exp: 2.2.0f-BETA6
+- PPP daemon		 Stable: 2.2.0f
 - Dynamic linker (ld.so) 1.7.14
 - GNU CC		 2.7.2
 - Binutils		 2.6.0.12
-- Linux C Library	 Stable:  5.2.18, Exp:  5.3.9, Alpha:  5.3.11
+- Linux C Library	 Stable:  5.2.18, Exp:  5.3.9, Alpha:  5.3.12
 - Linux C++ Library	 2.7.1.4
 - Termcap		 2.0.8
 - Procps		 0.99a
@@ -45,13 +45,17 @@
 ========================
 
    To use the PPP protocol with the 1.3.x linux kernel, you need to
-upgrade the PPP package to version 2.2.0e or the experimental 2.2.0f.
+upgrade the PPP package to version 2.2.0f.
 
 Procps utilities
 ================
 
    In the latest 1.3.x kernel releases the /proc filesystem structure
-was changed, so you need to upgrade the Procps package to version 0.99a.
+was changed, so you need to upgrade the Procps package to version
+0.99a.  In the very latest kernels, /proc has changed again.  There's
+not yet an officially updated version of procps, so make due with
+0.99a; you might want to look for one of the patches floating around to
+update 0.99a for use with 1.3.94 and later kernels.
 
 Installation notes
 ******************
@@ -83,6 +87,27 @@
 `release.libc-.5.3.9', and the address to obtain a precompiled binary
 is at the end of this file).
 
+   Also, the libc-5.3.x line has a known security hole relating to
+rlogin.  Unless you really need to upgrade for some reason, just stick
+with 5.2.18 for now.
+
+   If you're getting an error message that is something to the effect of
+
+   `fcntl_setlk() called by process 123 with broken flock() emulation'
+
+   then you need to upgrade to libc-5.2.18 as well.  A proper (in other
+words, BSD-style ;-) flock system call was added in 1.3.x, and older
+libc's will now give this error.  It doesn't *really* matter, so you
+can just ignore it.  If it really annoys you, upgrade libc (and
+recompile any static binaries you might have that are linked against
+the old libc).  If you're feeling lazy, just comment out
+
+   `                printk(KERN_WARNING
+"fcntl_setlk() called by process %d with broken flock()
+  emulation\n",                        current->pid);'
+
+   in linux/fs/locks.c and recompile.
+
 The Termcap Library
 ===================
 
@@ -152,9 +177,8 @@
 ==========
 
    You need to be running a pppd from ppp-2.2.0.tar.gz or greater.  The
-latest stable release is 2.2.0e and is available at
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz,
-along with a patch necessary to make it compile.
+latest stable release is 2.2.0f and is available at
+ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz.
 
 Named pipes
 ===========
@@ -168,6 +192,16 @@
 fix, upgrade to
 ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.60.tar.gz.
 
+   If you're trying to run NCSA httpd, you have to set pre-spawning of
+daemons to zero, as it incorrectly assumes SunOS behavior.  Some people
+have said that the Apache httpd has problems with the new named pipes,
+but I've never noticed any.
+
+   The new named pipe behavior also causes problems with Hylafax.  If
+you're running the hylafax daemon, it will just keep eating up CPU time
+until you have no idle time free.  I'm not currently aware of any
+patches that eliminate this behavior.
+
 Uugetty
 =======
 
@@ -283,6 +317,25 @@
 This will compile just fine after you copy its mntent.h over to
 /usr/include/mntent.h.
 
+APM support
+===========
+
+   Advanced Power Management (APM) support has been added to the kernel
+as well.  APM, which is primarily of use in laptops, provides access to
+battery status information and may help to conserve battery power.  The
+support files can be found in
+ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.2.tar.gz
+
+iBCS and Dosemu
+===============
+
+   For a version of iBCS that works with 1.3.x kernels, grab
+ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz
+
+   For a version of Dosemu that works (well, at least as well as DOS
+ever works ;-), get
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz.
+
 Please send info about any other packages that 1.3.x "broke" or about
 any new features of 1.3.x that require extra packages for use to Chris
 Ricker (gt1355b@prism.gatech.edu).
@@ -333,7 +386,7 @@
 Patched make binary:
 ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz
 
-The 5.2.18 release:
+The stable 5.2.18 release:
 ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz
 Installation notes:
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
@@ -367,9 +420,7 @@
 ========================
 
 The latest public release:
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz
-The latest experimental release:
-ftp://ftp.sii.com/pub/linux/ppp-2.2/ppp-2.2.0f.BETA6.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz
 
 Procps utilities
 ================
@@ -386,8 +437,6 @@
 ==================
 
 At the time of writing:
-ftp://sunsite.unc.edu/pub/Linux/Incoming/sysvinit-2.60.tar.gz
-Next location:
 ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz
 
 Util-linux
diff -u --recursive --new-file v1.3.95/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.95/linux/Documentation/Configure.help	Wed Apr 24 17:00:33 1996
+++ linux/Documentation/Configure.help	Sat Apr 27 14:40:12 1996
@@ -1155,7 +1155,8 @@
   Unit Number), e.g. a CD jukebox, you should say Y here so that all
   will be found by the SCSI driver. An SCSI device with multiple LUNs
   acts logically like multiple SCSI devices. The vast majority of SCSI
-  devices have only one LUN, and so most people can say N here.
+  devices have only one LUN, and so most people can say N here and
+  should in fact do so, because it is safer.
 
 Verbose SCSI error reporting (kernel size +=12K)
 CONFIG_SCSI_CONSTANTS
@@ -1163,16 +1164,6 @@
   understand if you enable this; it will enlarge your kernel by about
   12KB. If in doubt, say Y.
 
-Automatic Disk Geometry Translation 
-CONFIG_SCSI_AUTO_BIOSP
-  When this is set to Y, Linux will examine the partition table to
-  determine the mapping used under the other operating systems (e.g.
-  DOS), and set these parameters to the determined values, or if the
-  disk has no valid partition table, to an optimal value.
-###
-### What are the advantages/disadvantages? What is a safe value?
-###
-
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
   This is a driver for all SCSI host adaptors manufactured by
@@ -1607,18 +1598,19 @@
 
 STRIP (Starmode Radio IP) support
 CONFIG_STRIP
-  Say Y if you have a Metricom radio and intend to use Starmode Radio IP.
-  STRIP is a radio protocol developed for the MosquitoNet project
-  (http://mosquitonet.stanford.edu/) to send Internet traffic using Metricom
-  radios.  Metricom radios are small, battery powered, 100kbit/sec packet
-  radio transceivers, about the size and weight of a cellular telephone.
-  (You may also have heard them called "Metricom modems" but we avoid the
-  term "modem" because it misleads many people into thinking that you can
-  plug a Metricom modem into a phone line and use it as a modem.)
-  You can use STRIP on any Linux machine with a serial port, although
-  it is obviously most useful for people with laptop computers. If you
-  think you might get a Metricom radio in the future, there is no harm in
-  saying yes to STRIP now, except that it makes the kernel a bit bigger.
+  Say Y if you have a Metricom radio and intend to use Starmode Radio
+  IP.  STRIP is a radio protocol developed for the MosquitoNet project
+  (http://mosquitonet.stanford.edu/) to send Internet traffic using
+  Metricom radios.  Metricom radios are small, battery powered,
+  100kbit/sec packet radio transceivers, about the size and weight of
+  a cellular telephone.  (You may also have heard them called
+  "Metricom modems" but we avoid the term "modem" because it misleads
+  many people into thinking that you can plug a Metricom modem into a
+  phone line and use it as a modem.)  You can use STRIP on any Linux
+  machine with a serial port, although it is obviously most useful for
+  people with laptop computers. If you think you might get a Metricom
+  radio in the future, there is no harm in saying yes to STRIP now,
+  except that it makes the kernel a bit bigger.
 
 WIC (Radio IP bridge)
 CONFIG_WIC
@@ -1632,37 +1624,51 @@
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   and communicate with other computers.  If you want to use this, read
-  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available via
-  ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available
+  via ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.
 
 PLIP (parallel port) support
 CONFIG_PLIP
-  PLIP (Parallel Line Internet Protocol) is mainly used to create a
-  mini network consisting of two local machines. The parallel ports
-  are connected using a "null printer" or "Turbo Laplink" cable (you
-  can find the wiring in drivers/net/README?.plip).  This works also
-  if one of the two machines runs DOS and has some PLIP software
-  installed, e.g. NCSA telnet.  If you want to use this, say Y and
-  read the NET-2-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You need to say N or M to
-  "parallel printer support" below if you say Y here. Also, you might
-  have to edit the file drivers/net/Space.c and adjust the parallel
-  port's IRQ (there is a small number of Interrupt ReQuest lines in
-  your computer that are used by the periphery to gain the CPU's
-  attention - often a source of trouble if two different devices are
-  mistakenly configured to use the same IRQ. If you have the /proc
-  filesystem installed (see below), you can say "cat /proc/interrupts"
-  to see what the different IRQs are currently used for.)  This option
-  enlarges your kernel by about 8kB. If unsure, say N.  If you want to
-  compile this as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you want to use both a
-  parallel printer and PLIP, it is best to compile both drivers as
-  modules.
+  PLIP (Parallel Line Internet Protocol) is used to create a mini
+  network consisting of two (or, rarely, more) local machines. The
+  parallel ports (the connectors at the computers with 25 holes) are
+  connected using "null printer" or "Turbo Laplink" cables which can
+  transmit 4 bits at a time or using special PLIP cables, to be used
+  on bidirectional parallel ports only, which can transmit 8 bits at a
+  time (you can find the wiring of these cables in
+  drivers/net/README?.plip). The cables can be up to 15m long. This
+  works also if one of the machines runs DOS and has some PLIP
+  software installed, e.g. NCSA telnet.  If you want to use this, say
+  Y and read the PLIP mini-HOWTO, available via ftp (user: anonymous)
+  in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
+  NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
+  PLIP protocol was changed and this PLIP driver won't work together
+  with the PLIP support in Linux versions 1.0.x.  This option enlarges
+  your kernel by about 8kB. If you want to compile this as a module (
+  = code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you want to use
+  both a parallel printer and PLIP, there are two cases: 1) If the
+  printer and the PLIP cable are to use the same parallel port
+  (presumably because you have just one), it is best to compile both
+  drivers as modules and load and unload them as needed. 2) To use
+  different parallel ports for the printer and the PLIP cable, you can
+  say Y to the printer driver, specify the base address of the
+  parallel port(s) to use for the printer(s) with the "lp" kernel
+  command line option. (See the documentation of your boot loader
+  (lilo or loadlin) about how to pass options to the kernel at boot
+  time. The lilo procedure is also explained in the SCSI-HOWTO,
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
+  as well as the syntax of the "lp" command line option can be found
+  in drivers/char/lp.c. You can then say Y to this PLIP driver or,
+  preferably, M in which case Documentation/networking/net-modules.txt
+  tells you how to specify the port and IRQ to be used by PLIP at
+  module load time.
+  It's safe to say N here.
 
 EQL (serial line load balancing) support
 CONFIG_EQUALIZER
@@ -2052,8 +2058,8 @@
 
 EtherExpress support
 CONFIG_EEXPRESS
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  If you have an EtherExpress16 network (ethernet) card, say Y and
+  read the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel
   EtherExpress16 card used to be regarded as a very poor choice
   because the driver was very unreliable. We now have a new driver
@@ -2523,7 +2529,7 @@
   usage (also called diskquotas). Currently, it works only for the
   ext2 filesystem; you need the software available via ftp (user:
   anonymous) in
-  ftp.funet.fi:/pub/Linux/People/Linux/subsystems/quota/ in order to
+  ftp.funet.fi:/pub/Linux/PEOPLE/Linus/subsystems/quota/ in order to
   use it. Probably this is only useful for multi user systems. If
   unsure, say N.
 
@@ -2784,6 +2790,61 @@
   Documentation/modules.txt. If you haven't heard about all of this
   before, it's safe to say N.
 
+BSD UFS filesystem support (read only)
+CONFIG_UFS_FS
+  BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD
+  and NeXTstep) use a filesystem called UFS. Some System V Unixes can
+  create and mount partitions and diskettes using this filesystem
+  as well. Enabling this option allows you to mount these partitions
+  and diskettes read-only. If you only intend to mount files from
+  some other Unix over the network using NFS, you don't need the
+  UFS filesystem support (but you need nfs filesystem support
+  obviously). Note that this option is generally not needed for
+  floppies, since a good portable way to transport files and
+  directories between unixes (and even other operating systems)
+  is given by the tar program ("man tar"). When accessing NeXTstep
+  files, you may need to convert them from the NeXT character set
+  to the Latin1 character set; use GNU recode for this purpose.
+  Say Y to build UFS support into your kernel. If you want to compile
+  this as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want), say M here and read
+  Documentation/modules.txt. If you haven't heard about all of this
+  before, it's safe to say N.
+
+BSD disklabel (FreeBSD partition tables) support
+CONFIG_BSD_DISKLABEL
+  FreeBSD uses its own partition scheme on your PC. It requires only
+  one entry in the primary partition table of your disk and manages it
+  similarly to DOS extended partitions, putting in its first sector a
+  new partition table in disklabel format. Enabling this option allow
+  you to read these disklabels and further mount FreeBSD partitions on
+  your Linux box if you also have configured BSD ufs filesystem
+  support. If you don't know what all this is about, say N.
+
+SMD disklabel (Sun partition tables) support
+CONFIG_SMD_DISKLABEL
+  Like most systems, SunOS uses its own partition table format,
+  incompatible with each other. Enabling this option allow you to read
+  these partition tables and further mount SunOS disks on your Linux
+  box if you also have configured BSD ufs filesystem support. This is
+  mainly used to carry data from a Sparc under SunOS to your Linux box
+  via a removable medium like magneto-optical or ZIP drives. If you
+  don't know what all this is about, say N.
+
+AFFS filesystem support
+CONFIG_AFFS_FS
+  AFFS is the filesystem used on Commodore Amiga computers. People
+  running Linux on other systems can say N here.
+
+UFS filesystem support (read only)
+CONFIG_UFS_FS
+  UFS (Unix File System) is the way files are organized on Sun Solaris
+  harddisks and floppies. If you want to be able to read those, say Y
+  here. Note that this option is generally not needed for floppies,
+  since a good portable way to transport files and directories between
+  unixes (and even other operating systems) is given by the tar
+  program ("man tar").
+
 SMB filesystem support (to mount WfW shares etc..)
 CONFIG_SMB_FS
   SMB (Server Message Buffer) is the protocol Windows for Workgroups
@@ -2817,6 +2878,24 @@
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt.
 
+Amiga FFS filesystem support (read only)
+CONFIG_AFFS_FS
+  The Fast File System (FFS) is the common filesystem used on harddisks
+  by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also
+  possible to mount Diskfiles used by the Un*X Amiga Emulator by Bernd
+  Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html)
+  If you want to do this, you will also need the loopback device
+  support. Because it's in an early development state, the AFFS is 
+  read only. Say Y if you want to be able to read files from an Amiga
+  FFS partition of your harddrive. Amiga floppies however cannot be
+  read with this driver due to an incompatibility of the floppy
+  controller used in an Amiga and the standard floppy controller in
+  PCs and workstations. Read Documentation/filesystems/affs.txt. This
+  filesystem is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say N.
+
 Standard/generic serial support
 CONFIG_SERIAL
   This selects whether you want to include the driver for the standard
@@ -2896,12 +2975,23 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. If you intend to use PLIP (Parallel Line
-  Internet Protocol is mainly used to create a mini network by
-  connecting the parallel ports of two local machines) or a ethernet
-  network pocket adaptor attaching to the parallel port and a parallel
-  printer as well, you should compile both drivers as modules because
-  the drivers both want the same resources.
+  Documentation/modules.txt. If you want to use both a parallel
+  printer and PLIP, there are two cases: 1) If the printer and the
+  PLIP cable are to use the same parallel port (presumably because you
+  have just one), it is best to compile both drivers as modules and
+  load and unload them as needed. 2) To use different parallel ports
+  for the printer and the PLIP cable, you can say Y to this printer
+  driver, specify the base address of the parallel port(s) to use for
+  the printer(s) with the "lp" kernel command line option. (See the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time. The lilo procedure is also
+  explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses
+  as well as the syntax of the "lp" command line option can be found
+  in drivers/char/lp.c. You can then say Y to the PLIP driver or,
+  preferably, M in which case Documentation/networking/net-modules.txt
+  tells you how to specify the port and IRQ to be used by PLIP at
+  module load time.
 
 Logitech busmouse support
 CONFIG_BUSMOUSE
@@ -2975,10 +3065,11 @@
 
 Support for user miscellaneous modules
 CONFIG_UMISC
-  This option forces generic miscellaneous minor device  support in the
-  kernel, and allows later loading of user miscellaneous device  modules,
-  such as drivers for optic pens and touchscreens. Unless you need such
-  specific modules, or are willing to write/test one, just say N.
+  This option forces generic miscellaneous minor device support in the
+  kernel, and allows later loading of user miscellaneous device
+  modules, such as drivers for optic pens and touchscreens. Unless you
+  need such specific modules, or are willing to write/test one, just
+  say N.
 
 QIC-02 tape support
 CONFIG_QIC02_TAPE
@@ -3196,7 +3287,8 @@
   This enables synchronous PPP via ISDN. This protocol is used by
   Cisco or Sun for example. You will need a special version of pppd
   (called ipppd) for using this feature. See
-  Documentation/isdn/README.syncppp for more information.
+  Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ
+  for more information.
 
 Support generic MP (RFC 1717)
 CONFIG_ISDN_MPP
@@ -3230,10 +3322,11 @@
 PCBIT-D support
 CONFIG_ISDN_DRV_PCBIT
   This enables support for the PCBIT ISDN-cards. This card is
-  manufactured in Portugal by Octal. For running this card, 
-  additional firmware is necessary, which has to be downloaded into
-  the card using a utility which is distributed separately.  
-  See Documentation/isdn/README for more information.	
+  manufactured in Portugal by Octal. For running this card, additional
+  firmware is necessary, which has to be downloaded into the card
+  using a utility which is distributed separately.  See
+  Documentation/isdn/README and Documentation/isdn/README.pcbit for
+  more information.
 
 Support for AP1000 multicomputer
 CONFIG_AP1000
@@ -3311,4 +3404,5 @@
 # LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
 # 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
+# LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
+# LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au
diff -u --recursive --new-file v1.3.95/linux/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt
--- v1.3.95/linux/Documentation/filesystems/affs.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/filesystems/affs.txt	Thu Apr 25 13:19:52 1996
@@ -0,0 +1,23 @@
+Linux can read, but not write, Amiga FFS partitions.
+
+Mount options are
+    size	has the size in 512 byte blocks of the mounted medium. 
+
+Case is significant in filename matching, different to real AFFS.
+
+
+Command line example
+    mount  Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760
+    mount  /dev/sda3 /Amiga -t affs
+
+/etc/fstab example
+    /dev/sdb5	/d/f    affs    ro
+
+This file system will probably be writeable in future releases.
+
+It's not possible to read floppy disks with a normal PC or workstation
+due to an incompatibility to the Amiga floppy controller.
+
+If you are interested in an Amiga Emulator for Linux, look at
+
+http://www-users.informatik.rwth-aachen.de/~crux/uae.html
diff -u --recursive --new-file v1.3.95/linux/Documentation/ramdisk.txt linux/Documentation/ramdisk.txt
--- v1.3.95/linux/Documentation/ramdisk.txt	Thu Jan 25 21:01:32 1996
+++ linux/Documentation/ramdisk.txt	Sat Apr 27 11:07:18 1996
@@ -28,10 +28,15 @@
 of the "rdev -r" or "ramsize" (usually a symbolic link to "rdev")
 command has changed.
 
-The old "ramdisk=<ram_size>" is now obsolete. The kernel will ignore
-such old commands, and thus they will be passed on through to the init
-program, which will then complain. You should remove any of these old
-style commands from config files such as "/etc/lilo.config".
+Also, the new ramdisk supports up to 16 ramdisks out of the box, and can
+be reconfigured in rd.c to support up to 255 ramdisks.  To use multiple
+ramdisk support with your system, run 'mknod /dev/ramX b 1 X' and chmod
+(to change it's permissions) it to your liking.  The default /dev/ram(disk)
+uses minor #1, so start with ram2 and go from there.
+
+The old "ramdisk=<ram_size>" has been changed to "ramdisk_size=<ram_size>"
+to make it clearer.  The original "ramdisk=<ram_size>" has been kept around
+for compatiblity reasons, but it will probably be removed in 2.1.x.
 
 The new ramdisk also has the ability to load compressed ramdisk images,
 allowing one to squeeze more programs onto an average installation or 
@@ -92,6 +97,11 @@
 and thus "prompt_ramdisk=1" can be used. Since this is the default 
 value, it doesn't really need to be specified.
 
+	ramdisk_size=N
+	==============
+
+This parameter tells the ramdisk driver to set up ramdisks of Nk size.  The
+default is 4096 (4MB). 
 
 3) Using "rdev -r" With New Kernels
 -----------------------------------
diff -u --recursive --new-file v1.3.95/linux/Documentation/riscom8.txt linux/Documentation/riscom8.txt
--- v1.3.95/linux/Documentation/riscom8.txt	Tue Apr 23 13:57:00 1996
+++ linux/Documentation/riscom8.txt	Fri Apr 26 12:12:36 1996
@@ -5,7 +5,7 @@
 NOTE: English is not my native language. 
       I'm sorry for any mistakes in this text.
 
-Misc. notes for RISCom/8 serial driver, in no particule order :)
+Misc. notes for RISCom/8 serial driver, in no particular order :)
 
 1) This driver can support up to 4 boards at time.
    Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for
diff -u --recursive --new-file v1.3.95/linux/Makefile linux/Makefile
--- v1.3.95/linux/Makefile	Wed Apr 24 17:00:33 1996
+++ linux/Makefile	Fri Apr 26 10:42:04 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 95
+SUBLEVEL = 96
 
 ARCH = i386
 
@@ -142,6 +142,10 @@
 DRIVERS := $(DRIVERS) drivers/pci/pci.a
 endif
 
+ifdef CONFIG_SBUS
+DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
+endif
+
 include arch/$(ARCH)/Makefile
 
 ifdef SMP
@@ -202,7 +206,7 @@
 	@if [ ! -f .version ]; then \
 		echo 1 > .version; \
 	else \
-		expr `cat .version` + 1 > .version; \
+		expr 0`cat .version` + 1 > .version; \
 	fi
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
@@ -326,7 +330,7 @@
 	rm -f .hdepend
 	rm -f $(TOPDIR)/include/linux/modversions.h
 	rm -f $(TOPDIR)/include/linux/modules/*
-	
+
 
 distclean: mrproper
 	rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
diff -u --recursive --new-file v1.3.95/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.3.95/linux/arch/alpha/kernel/entry.S	Wed Apr 24 17:00:33 1996
+++ linux/arch/alpha/kernel/entry.S	Fri Apr 26 12:12:34 1996
@@ -541,7 +541,7 @@
 	jsr     $26,($27),syscall_trace
 	bsr	$1,undo_switch_stack
 
-	/* get the system call number and the argments back.. */
+	/* get the system call number and the arguments back.. */
 	ldq     $0,0($30)
 	ldq     $16,SP_OFF+24($30)
 	ldq     $17,SP_OFF+32($30)
@@ -574,9 +574,9 @@
 
 	.align  3
 strace_error:
-	ldq	$9,0($30)	/* old syscall nr (zero if success) */
-	beq	$9,strace_success
-	ldq	$10,72($30)	/* .. and this a3 */
+	ldq	$19,0($30)	/* old syscall nr (zero if success) */
+	beq	$19,strace_success
+	ldq	$20,72($30)	/* .. and this a3 */
 
 	subq	$31,$0,$0	/* with error in v0 */
 	addq	$31,1,$1	/* set a3 for errno return */
@@ -584,13 +584,15 @@
 	stq	$1,72($30)	/* a3 for return */
 
 	bsr	$1,do_switch_stack
+	bis	$19,$19,$9	/* save old syscall number */
+	bis	$20,$20,$10	/* save old a3 */
 	lda     $27,syscall_trace
 	jsr     $26,($27),syscall_trace
+	bis	$9,$9,$19
+	bis	$10,$10,$20	
 	bsr	$1,undo_switch_stack
 
 	bis	$31,$31,$26	/* tell "ret_from_sys_call" that we can restart */
-	bis	$9,$9,$19	/*  .. old syscall nr */
-	bis	$10,$10,$20	/*  .. old a3 */
 	br	$31,ret_from_sys_call
 
 	.align 3
diff -u --recursive --new-file v1.3.95/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v1.3.95/linux/arch/alpha/kernel/traps.c	Sun Apr 21 12:39:00 1996
+++ linux/arch/alpha/kernel/traps.c	Thu Apr 25 08:50:31 1996
@@ -67,7 +67,7 @@
 	printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
 		current->comm, regs.pc, summary, write_mask);
 	die_if_kernel("Arithmetic fault", &regs, 0);
-	send_sig(SIGFPE, current, 1);
+	force_sig(SIGFPE, current);
 }
 
 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
@@ -82,7 +82,7 @@
 		if (ptrace_cancel_bpt(current)) {
 			regs.pc -= 4;	/* make pc point to former bpt */
 		}
-		send_sig(SIGTRAP, current, 1);
+		force_sig(SIGTRAP, current);
 		break;
 
 	      case 2: /* gentrap */
@@ -97,7 +97,7 @@
 		      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
 		      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
 		      case GEN_FLTINE:
-			send_sig(SIGFPE, current, 1);
+			force_sig(SIGFPE, current);
 			break;
 
 		      case GEN_DECOVF:
@@ -118,14 +118,14 @@
 		      case GEN_SUBRNG5:
 		      case GEN_SUBRNG6:
 		      case GEN_SUBRNG7:
-			send_sig(SIGILL, current, 1);
+			force_sig(SIGILL, current);
 			break;
 		}
 		break;
 
 	      case 1: /* bugcheck */
 	      case 3: /* FEN fault */
-		send_sig(SIGILL, current, 1);
+		force_sig(SIGILL, current);
 		break;
 
 	      case 4: /* opDEC */
@@ -142,12 +142,12 @@
 				 * (we don't do no stinkin' VAX fp...)
 				 */
 				if (!alpha_fp_emul(regs.pc - 4))
-					send_sig(SIGFPE, current, 1);
+					force_sig(SIGFPE, current);
 				break;
 			}
 		}
 #endif
-		send_sig(SIGILL, current, 1);
+		force_sig(SIGILL, current);
 		break;
 
 	      default:
@@ -314,7 +314,7 @@
 	}
 	if (verify_area(dir, va, size)) {
 		*pc_addr -= 4;	/* make pc point to faulting insn */
-		send_sig(SIGSEGV, current, 1);
+		force_sig(SIGSEGV, current);
 		return;
 	}
 
@@ -362,7 +362,7 @@
 	      case 0x2d: stq_u(*reg_addr, va);		     break;	/* stq */
 	      default:
 		*pc_addr -= 4;	/* make pc point to faulting insn */
-		send_sig(SIGBUS, current, 1);
+		force_sig(SIGBUS, current);
 		return;
 	}
 
diff -u --recursive --new-file v1.3.95/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v1.3.95/linux/arch/alpha/mm/fault.c	Sun Apr 21 12:39:00 1996
+++ linux/arch/alpha/mm/fault.c	Thu Apr 25 08:43:43 1996
@@ -97,7 +97,7 @@
 		printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n",
 			current->comm, regs.pc, regs.r26, address);
 		die_if_kernel("oops", &regs, cause);
-		send_sig(SIGSEGV, current, 1);
+		force_sig(SIGSEGV, current);
 		return;
 	}
 /*
diff -u --recursive --new-file v1.3.95/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v1.3.95/linux/arch/i386/kernel/traps.c	Sun Apr 21 12:39:00 1996
+++ linux/arch/i386/kernel/traps.c	Thu Apr 25 08:48:34 1996
@@ -40,9 +40,7 @@
 { \
 	tsk->tss.error_code = error_code; \
 	tsk->tss.trap_no = trapnr; \
-	if (signr == SIGTRAP && current->flags & PF_PTRACED) \
-		current->blocked &= ~(1 << (SIGTRAP-1)); \
-	send_sig(signr, tsk, 1); \
+	force_sig(signr, tsk); \
 	die_if_kernel(str,regs,error_code); \
 }
 
@@ -187,7 +185,7 @@
 	die_if_kernel("general protection",regs,error_code);
 	current->tss.error_code = error_code;
 	current->tss.trap_no = 13;
-	send_sig(SIGSEGV, current, 1);	
+	force_sig(SIGSEGV, current);	
 }
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
@@ -209,9 +207,7 @@
 		handle_vm86_debug((struct vm86_regs *) regs, error_code);
 		return;
 	}
-	if (current->flags & PF_PTRACED)
-		current->blocked &= ~(1 << (SIGTRAP-1));
-	send_sig(SIGTRAP, current, 1);
+	force_sig(SIGTRAP, current);
 	current->tss.trap_no = 1;
 	current->tss.error_code = error_code;
 	if ((regs->cs & 3) == 0) {
@@ -260,7 +256,7 @@
 	__asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
 	task->flags&=~PF_USEDFPU;
 
-	send_sig(SIGFPE, task, 1);
+	force_sig(SIGFPE, task);
 	task->tss.trap_no = 16;
 	task->tss.error_code = 0;
 
@@ -327,7 +323,7 @@
 {
   printk("math-emulation not enabled and no coprocessor found.\n");
   printk("killing %s.\n",current->comm);
-  send_sig(SIGFPE,current,1);
+  force_sig(SIGFPE,current);
   schedule();
 }
 
diff -u --recursive --new-file v1.3.95/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v1.3.95/linux/arch/i386/mm/fault.c	Wed Apr  3 16:06:55 1996
+++ linux/arch/i386/mm/fault.c	Thu Apr 25 08:43:05 1996
@@ -104,7 +104,7 @@
 		current->tss.cr2 = address;
 		current->tss.error_code = error_code;
 		current->tss.trap_no = 14;
-		send_sig(SIGSEGV, current, 1);
+		force_sig(SIGSEGV, current);
 		return;
 	}
 /*
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- v1.3.95/linux/arch/m68k/amiga/amifb.c	Tue Apr 23 13:57:02 1996
+++ linux/arch/m68k/amiga/amifb.c	Fri Apr 26 12:12:34 1996
@@ -184,7 +184,7 @@
    -------------------------------------------
 
    Since there are much more parameters for the Amiga display than for the
-   frame buffer interface, there must be some depencies among the Amiga display
+   frame buffer interface, there must be some dependencies among the Amiga display
    parameters. Here's what I found out:
 
       - ddfstrt and ddfstop are best aligned to 64 pixels.
@@ -1138,13 +1138,13 @@
  *
  * History:
  *   - 03 Jan 95: Original version my Martin Schaller: The TT driver and
- *                all the device independant stuff
+ *                all the device independent stuff
  *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
  *                and wrote the Falcon, ST(E), and External drivers
  *                based on the original TT driver.
  *   - 26 Jan 95: Geert: Amiga version
  *   - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga
- *		  frame buffer device.  This provdes ECS support and the
+ *		  frame buffer device.  This provides ECS support and the
  *		  following screen-modes: multiscan, multiscan-lace,
  * 		  super72, super72-lace, dblntsc, dblpal & euro72.
  *		  He suggests that we remove the old AGA screenmodes,
@@ -1255,7 +1255,7 @@
  * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could
  * be used as well). -wjr
  *
- * The code now supports ECS aswell, except for FMODE all control registers
+ * The code now supports ECS as well, except for FMODE all control registers
  * are the same under ECS. A special color-table has to be generated though.
  * -Jes
  */
@@ -1782,7 +1782,7 @@
  *    0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter
  *    is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff),
  *    WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use
- *    WAIT(0xe2,0xff) to ensure that wrap occures by next copper
+ *    WAIT(0xe2,0xff) to ensure that wrap occurred by next copper
  *    instruction. Argghh!
  *
  * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2].
@@ -2392,7 +2392,7 @@
 	static ushort cursorstate = 0;
 
 	/* I *think* that you should only change display lists on long frame.
-	 * At least it goes awfully perculiar on my A500 without the following
+	 * At least it goes awfully peculiar on my A500 without the following
 	 * test. Not really in a position to test this hypothesis, so sorry
 	 * for the slow scrolling, all you flicker-fixed souls
 	 */
@@ -2490,6 +2490,7 @@
 	fix->ypanstep = 0;
 	fix->ywrapstep = 1;
 
+	fix->line_length = 0;
 	for (i = 0; i < arraysize(fix->reserved); i++)
 		fix->reserved[i] = 0;
 	return(0);
@@ -2567,6 +2568,7 @@
 	disp[con].type_aux = fix.type_aux;
 	disp[con].ypanstep = fix.ypanstep;
 	disp[con].ywrapstep = fix.ywrapstep;
+	disp[con].line_length = fix.line_length;
 	disp[con].can_soft_blank = 1;
 	disp[con].inverse = mono_amifb_inverse;
 }
@@ -3164,6 +3166,7 @@
    else
       fix->ywrapstep = 0;
 
+   fix->line_length = 0;
    for (i = 0; i < arraysize(fix->reserved); i++)
       fix->reserved[i] = 0;
 
@@ -4460,6 +4463,7 @@
    disp[con].type_aux = fix.type_aux;
    disp[con].ypanstep = fix.ypanstep;
    disp[con].ywrapstep = fix.ywrapstep;
+   disp[con].line_length = fix.line_length;
    disp[con].can_soft_blank = 1;
    disp[con].inverse = amifb_inverse;
 }
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v1.3.95/linux/arch/m68k/amiga/config.c	Tue Apr 23 13:57:02 1996
+++ linux/arch/m68k/amiga/config.c	Fri Apr 26 12:12:34 1996
@@ -370,7 +370,7 @@
     time_finetune = finetune+0.5;
 #endif
 
-    ciab.cra &= 0xC0;	 /* turn off timer A, continous mode, from Eclk */
+    ciab.cra &= 0xC0;	 /* turn off timer A, continuous mode, from Eclk */
     ciab.talo = jiffy_ticks % 256;
     ciab.tahi = jiffy_ticks / 256;
     /* CIA interrupts when counter underflows, so adjust ticks by 1 */
@@ -378,7 +378,7 @@
 
     /* install interrupt service routine for CIAB Timer A */
     /*
-     * Please don't change this to use ciaa, as it interfers with the
+     * Please don't change this to use ciaa, as it interferes with the
      * SCSI code. We'll have to take a look at this later
      */
 #if 0
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/amiga/ksyms.c linux/arch/m68k/amiga/ksyms.c
--- v1.3.95/linux/arch/m68k/amiga/ksyms.c	Tue Apr 23 13:57:02 1996
+++ linux/arch/m68k/amiga/ksyms.c	Fri Apr 26 12:12:34 1996
@@ -7,7 +7,7 @@
    * Add things here when you find the need for it.
    */
 
-  /* examble
+  /* example
   X(something_you_need),
   */
 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- v1.3.95/linux/arch/m68k/atari/atafb.c	Tue Apr 23 13:57:02 1996
+++ linux/arch/m68k/atari/atafb.c	Fri Apr 26 12:12:34 1996
@@ -118,7 +118,7 @@
 	} hw;
 } current_par;
 
-/* Don't calculate an own resoltion, and thus don't change the one found when
+/* Don't calculate an own resolution, and thus don't change the one found when
  * booting (currently used for the Falcon to keep settings for internal video
  * hardware extensions (e.g. ScreenBlaster)  */
 static int DontCalcRes = 0; 
@@ -786,7 +786,7 @@
 	short right, hsync, left;	/* standard timing in clock cycles, not pixel */
 		/* hsync initialized in falcon_detect() */
 	short sync_mask;	/* or-mask for hw.falcon.sync to set this clock */
-	short control_mask; /* dito, for hw.falcon.vid_control */
+	short control_mask; /* ditto, for hw.falcon.vid_control */
 }
 f25  = {25175000, 39722, 18, 0, 42, 0x0, VCO_CLOCK25},
 f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
@@ -1683,7 +1683,7 @@
 	falcon_get_par(&par);
 	falcon_encode_var(&atari_fb_predefined[0], &par);
 
-	/* Detectet mode is always the "autodetect" slot */
+	/* Detected mode is always the "autodetect" slot */
 	return 1;
 }
 
@@ -2303,7 +2303,7 @@
 
 
 /* =========================================================== */
-/* ============== Hardware Independant Functions ============= */
+/* ============== Hardware Independent Functions ============= */
 /* =========================================================== */
 
 
@@ -2992,7 +2992,7 @@
     }
 
     if (*int_str) {
-	/* Format to config extendet internal video hardware like OverScan:
+	/* Format to config extended internal video hardware like OverScan:
 	"<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
 	Explanation:
 	<switch-type> type to switch on higher resolution
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v1.3.95/linux/arch/m68k/atari/ataints.c	Tue Apr 23 13:57:02 1996
+++ linux/arch/m68k/atari/ataints.c	Fri Apr 26 12:12:34 1996
@@ -5,7 +5,7 @@
  *  Added support for TT interrupts; setup for TT SCU (may someone has
  *  twiddled there and we won't get the right interrupts :-()
  *
- *  Major change: The device-independant code in m68k/ints.c didn't know
+ *  Major change: The device-independent code in m68k/ints.c didn't know
  *  about non-autovec ints yet. It hardcoded the number of possible ints to
  *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
  *  number of possible ints a constant defined in interrupt.h, which is
@@ -321,7 +321,7 @@
 	movel	%sp@+,%d0
 	rte");
 
-/* Defined in entry.S; only increments 'num_suprious' */
+/* Defined in entry.S; only increments 'num_spurious' */
 asmlinkage void bad_interrupt(void);
 
 extern void atari_microwire_cmd( int cmd );
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v1.3.95/linux/arch/m68k/atari/atakeyb.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/atakeyb.c	Fri Apr 26 12:12:34 1996
@@ -302,7 +302,7 @@
  * it's really hard to decide whether they're mouse or keyboard bytes. Since
  * overruns usually occur when moving the Atari mouse rapidly, they're seen as
  * mouse bytes here. If this is wrong, only a make code of the keyboard gets
- * lost, which isn't too bad. Loosing a break code would be desasterous,
+ * lost, which isn't too bad. Loosing a break code would be disastrous,
  * because then the keyboard repeat strikes...
  */
 
@@ -541,7 +541,7 @@
     
     ikbd_write(cmd, 2);
 
-    /* if allswell code 0xF1 is returned, else the break codes of
+    /* if all's well code 0xF1 is returned, else the break codes of
        all keys making contact */
 }
 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/atapart.c linux/arch/m68k/atari/atapart.c
--- v1.3.95/linux/arch/m68k/atari/atapart.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/atapart.c	Fri Apr 26 12:12:34 1996
@@ -98,7 +98,7 @@
 			break;
 		}
 		if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
-			printk( "\nID of extended partion is not XGM!\n" );
+			printk( "\nID of extended partition is not XGM!\n" );
 			brelse( xbh );
 			break;
 		}
@@ -128,7 +128,7 @@
   if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
   {
     pi = &rs->icdpart[0];
-    /* sanity check: no ICD format if first partion invalid */
+    /* sanity check: no ICD format if first partition invalid */
     if (memcmp (pi->id, "GEM", 3) == 0 ||
         memcmp (pi->id, "BGM", 3) == 0 ||
         memcmp (pi->id, "RAW", 3) == 0 )
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c
--- v1.3.95/linux/arch/m68k/atari/atasound.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/atasound.c	Fri Apr 26 12:12:34 1996
@@ -81,7 +81,7 @@
 
 	if (count == 750 && ticks == HZ/8) {
 		/* Special case: These values are used by console.c to
-		 * generate the console bell. They are catched here and the
+		 * 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.
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v1.3.95/linux/arch/m68k/atari/config.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/config.c	Fri Apr 26 12:12:34 1996
@@ -650,7 +650,7 @@
     tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
 
     ctrl = RTC_READ(RTC_CONTROL); /* control registers are
-                                   * independant from the UIP */
+                                   * independent from the UIP */
 
     if (op) {
         /* write: prepare values */
@@ -1109,7 +1109,7 @@
 
 int atari_get_hardware_list(char *buffer)
 {
-    int len = 0;
+    int len = 0, i;
 
     for (i = 0; i < boot_info.num_memory; i++)
 	len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v1.3.95/linux/arch/m68k/atari/stdma.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/stdma.c	Fri Apr 26 12:12:34 1996
@@ -59,13 +59,13 @@
 /*
  * Function: void stdma_lock( isrfunc isr, void *data )
  *
- * Purpose: Trys to get a lock on the ST-DMA chip that is used by more
+ * Purpose: Tries to get a lock on the ST-DMA chip that is used by more
  *   then one device driver. Waits on stdma_wait until lock is free.
  *   stdma_lock() may not be called from an interrupt! You have to
  *   get the lock in your main routine and release it when your
  *   request is finished.
  *
- * Inputs: A interupt function that is called until the lock is
+ * Inputs: A interrupt function that is called until the lock is
  *   released.
  *
  * Returns: nothing
@@ -126,7 +126,7 @@
  *
  * Inputs: none
  *
- * Returns: 0 if noone is waiting, != 0 otherwise
+ * Returns: 0 if no one is waiting, != 0 otherwise
  *
  */
 
@@ -182,7 +182,7 @@
 /*
  * Function: void stdma_int()
  *
- * Purpose: The interupt routine for the ST-DMA. It calls the isr
+ * Purpose: The interrupt routine for the ST-DMA. It calls the isr
  *   registered by stdma_lock().
  *
  */
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c
--- v1.3.95/linux/arch/m68k/boot/amiga/bootstrap.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/boot/amiga/bootstrap.c	Fri Apr 26 12:12:34 1996
@@ -290,7 +290,7 @@
 			}
 
 		/* if we suspect that Kickstart is zkicked,
-		   modify the entry to show 512K more at the botton of RAM */
+		   modify the entry to show 512K more at the bottom of RAM */
 		if (mh.mh_Lower == (void *)0x00280020) {
 		    mh.mh_Lower =  (void *)0x00200000;
 		    printf("ZKick detected.\n");
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c
--- v1.3.95/linux/arch/m68k/boot/atari/bootstrap.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/boot/atari/bootstrap.c	Fri Apr 26 12:12:34 1996
@@ -15,7 +15,7 @@
 **		    (Andreas)
 **      14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
 **		    start address is KSTART_ADDR + PAGE_SIZE, this
-**		    does not need the ugly klugde with
+**		    does not need the ugly kludge with
 **		    -fwritable-strings (++andreas)
 **      09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
 **                  mentions all ST-Ram and the mover is located somewhere
@@ -684,7 +684,7 @@
 	    && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
 	  {
 	    elf_kernel = 1;
-	    /* A few plausability checks */
+	    /* A few plausibility checks */
 	    if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
 		|| kexec_elf.e_version != EV_CURRENT)
 	      {
@@ -703,7 +703,7 @@
 		      kexec_elf.e_phnum * sizeof (*kernel_phdrs))
 		!= kexec_elf.e_phnum * sizeof (*kernel_phdrs))
 	      {
-		fprintf (stderr, "Unable to read programm headers from %s\n",
+		fprintf (stderr, "Unable to read program headers from %s\n",
 			 kernel_name);
 		boot_exit (EXIT_FAILURE);
 	      }
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c
--- v1.3.95/linux/arch/m68k/console/fbcon.c	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/console/fbcon.c	Fri Apr 26 12:12:35 1996
@@ -47,6 +47,7 @@
 #include <linux/string.h>
 #include <linux/config.h>
 #include <linux/kd.h>
+#include <linux/malloc.h>
 
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
@@ -578,7 +579,7 @@
    if (p->fontwidth != 8)
       panic("fbcon_setup: No support for fontwidth != 8");
 
-   if (divides(p->ywrapstep, p->fontheight))
+   if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual))
       p->scrollmode = SCROLL_YWRAP;
    else if (divides(p->ypanstep, p->fontheight) &&
             p->var.yres_virtual >= p->var.yres+p->fontheight)
@@ -588,11 +589,15 @@
 
    conp->vc_cols = p->var.xres/p->fontwidth;
    conp->vc_rows = p->var.yres/p->fontheight;
+   p->vrows = p->var.yres_virtual/p->fontheight;
    conp->vc_can_do_color = p->var.bits_per_pixel != 1;
 
 #ifdef CONFIG_FBCON_MONO
    if (p->var.bits_per_pixel == 1) {
-      p->next_line = p->var.xres_virtual>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = 0;
       p->dispsw = &dispsw_mono;
    } else
@@ -621,14 +626,22 @@
 #endif /* CONFIG_FBCON_IPLAN2 */
 #ifdef CONFIG_FBCON_ILBM
    if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) {
-      p->next_line = p->type_aux;
-      p->next_plane = p->type_aux/p->var.bits_per_pixel;
+      if (p->line_length) {
+         p->next_line = p->line_length*p->var.bits_per_pixel;
+         p->next_plane = p->line_length;
+      } else {
+         p->next_line = p->type_aux;
+         p->next_plane = p->type_aux/p->var.bits_per_pixel;
+      }
       p->dispsw = &dispsw_ilbm;
    } else
 #endif /* CONFIG_FBCON_ILBM */
 #ifdef CONFIG_FBCON_PLANES
    if (p->type == FB_TYPE_PLANES) {
-      p->next_line = p->var.xres_virtual>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = p->var.yres_virtual*p->next_line;
       p->dispsw = &dispsw_plan;
    } else
@@ -670,7 +683,10 @@
 #ifdef CONFIG_FBCON_MONO
       printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n",
              p->type, p->type_aux);
-      p->next_line = (p->var.xres_virtual)>>3;
+      if (p->line_length)
+         p->next_line = p->line_length;
+      else
+         p->next_line = p->var.xres_virtual>>3;
       p->next_plane = 0;
       p->var.bits_per_pixel = 1;
       p->dispsw = &dispsw_mono;
@@ -708,7 +724,7 @@
  * equivalents for large blits, and thats important to the lowest level of
  * a graphics driver. Question is whether some scheme with the blitter
  * would be faster. I suspect not for simple text system - not much
- * asynchronisity.
+ * asynchrony.
  *
  * Code is very simple, just gruesome expansion. Basic strategy is to
  * increase data moved/cleared at each step to 16 bytes to reduce
@@ -732,7 +748,7 @@
    subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
    addal is faster than addaw
    movep is rather expensive compared to ordinary move's
-   some functions rewritten in C for clearity, no speed loss */
+   some functions rewritten in C for clarity, no speed loss */
 
 static __inline__ void *mymemclear_small(void *s, size_t count)
 {
@@ -1375,10 +1391,10 @@
 
 static __inline__ int real_y(struct display *p, int y)
 {
-   int rows = p->conp->vc_rows;
+   int rows = p->vrows;
 
    y += p->yscroll;
-   return(y < rows || p->scrollmode != SCROLL_YWRAP ? y : y-rows);
+   return(y < rows ? y : y-rows);
 }
 
 
@@ -1398,7 +1414,7 @@
 
    /* Split blits that cross physical y_wrap boundary */
 
-   y_break = conp->vc_rows-p->yscroll;
+   y_break = p->vrows-p->yscroll;
    if (sy < y_break && sy+height-1 >= y_break) {
       u_int b = y_break-sy;
       p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
@@ -1513,8 +1529,8 @@
             switch (p->scrollmode) {
                case SCROLL_YWRAP:
                   p->yscroll += count;
-                  if (p->yscroll >= conp->vc_rows) /* Deal with wrap */
-                     p->yscroll -= conp->vc_rows;
+                  if (p->yscroll >= p->vrows) /* Deal with wrap */
+                     p->yscroll -= p->vrows;
                   p->var.xoffset = 0;
                   p->var.yoffset = p->yscroll*p->fontheight;
                   p->var.vmode |= FB_VMODE_YWRAP;
@@ -1523,8 +1539,7 @@
 
                case SCROLL_YPAN:
                   p->yscroll += count;
-                  if (p->yscroll*p->fontheight+p->var.yres >
-                      p->var.yres_virtual) {
+                  if (p->yscroll+conp->vc_rows > p->vrows) {
                      p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count,
                                       conp->vc_cols);
                      p->yscroll = 0;
@@ -1553,7 +1568,7 @@
                case SCROLL_YWRAP:
                   p->yscroll -= count;
                   if (p->yscroll < 0)              /* Deal with wrap */
-                     p->yscroll += conp->vc_rows;
+                     p->yscroll += p->vrows;
                   p->var.xoffset = 0;
                   p->var.yoffset = p->yscroll*p->fontheight;
                   p->var.vmode |= FB_VMODE_YWRAP;
@@ -1563,8 +1578,7 @@
                case SCROLL_YPAN:
                   p->yscroll -= count;
                   if (p->yscroll < 0) {
-                     p->yscroll = (p->var.yres_virtual-p->var.yres)/
-                                  p->fontheight;
+                     p->yscroll = p->vrows-conp->vc_rows;
                      p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count,
                                       conp->vc_cols);
                   }
@@ -1582,7 +1596,7 @@
             fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
 
          /* Fixed bmove() should end Arno's frustration with copying?
-          * Confusius says:
+          * Confucius says:
           *    Man who copies in wrong direction, end up with trashed data
           */
          fbcon_clear(conp, t, 0, count, conp->vc_cols);
@@ -1625,7 +1639,7 @@
     * Recursive invocations don't need to erase the cursor over and
     * over again, so we use fbcon_bmove_rec()
     */
-   fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, conp->vc_rows-p->yscroll);
+   fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
 
    return(0);
 }
@@ -1695,6 +1709,134 @@
 }
 
 
+static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
+{
+	int unit = conp->vc_num;
+	struct display *p = &disp[unit];
+	int i, size, alloc;
+
+	size = (p->fontwidth+7)/8 * p->fontheight * 256;
+	alloc = (*w+7)/8 * *h * 256;
+	*w = p->fontwidth;
+	*h = p->fontheight;
+   
+	if (alloc < size)
+		/* allocation length not sufficient */
+		return( -ENAMETOOLONG );
+
+	if ((i = verify_area( VERIFY_WRITE, (void *)data, size )))
+		return i;
+
+	memcpy_tofs( data, p->fontdata, size );
+	return( 0 );
+}
+
+
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+
+static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
+{
+	int unit = conp->vc_num;
+	struct display *p = &disp[unit];
+	int i, size, userspace = 1, resize;
+	char *old_data = NULL, *new_data;
+
+	if (w < 0)
+		w = p->fontwidth;
+	if (h < 0)
+		h = p->fontheight;
+	
+	if (w == 0) {
+		/* engage predefined font, name in 'data' */
+		char name[MAX_FONT_NAME+1];
+	   
+		if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
+			return i;
+		memcpy_fromfs( name, data, MAX_FONT_NAME );
+		name[sizeof(name)-1] = 0;
+		
+		if (!findsoftfont( name, &w, &h, (u_char **)&data ))
+			return( -ENOENT );
+		userspace = 0;
+	}
+	else if (w == 1) {
+		/* copy font from some other console in 'h'*/
+		struct display *op;
+
+		if (h < 0 || !vc_cons_allocated( h ))
+			return( -ENOTTY );
+		if (h == unit)
+			return( 0 ); /* nothing to do */
+		op = &disp[h];
+		if (op->fontdata == p->fontdata)
+			return( 0 ); /* already the same font... */
+
+		resize = (op->fontwidth != p->fontwidth) ||
+			     (op->fontheight != p->fontheight);
+		if (p->userfont)
+			old_data = p->fontdata;
+		p->fontdata = op->fontdata;
+		w = p->fontwidth = op->fontwidth;
+		h = p->fontheight = op->fontheight;
+		if ((p->userfont = op->userfont))
+			REFCOUNT(p->fontdata)++; /* increment usage counter */
+		goto activate;
+	}
+
+	if (w != 8)
+		/* Currently only fontwidth == 8 supported */
+		return( -ENXIO );
+	
+	resize = (w != p->fontwidth) || (h != p->fontheight);
+	size = (w+7)/8 * h * 256;
+	
+	if (p->userfont)
+		old_data = p->fontdata;
+	
+	if (userspace) {
+		if ((i = verify_area( VERIFY_READ, (void *)data, size )))
+			return i;
+		if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
+			return( -ENOMEM );
+		new_data += sizeof(int);
+		REFCOUNT(new_data) = 1; /* usage counter */
+		memcpy_fromfs( new_data, data, size );
+		p->fontdata = new_data;
+		p->userfont = 1;
+	}
+	else {
+		p->fontdata = data;
+		p->userfont = 0;
+	}
+	p->fontwidth = w;
+	p->fontheight = h;
+
+  activate:
+	if (resize) {
+		p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
+		if (divides(p->ywrapstep, p->fontheight))
+			p->scrollmode = SCROLL_YWRAP;
+		else if (divides(p->ypanstep, p->fontheight) &&
+				 p->var.yres_virtual >= p->var.yres+p->fontheight)
+			p->scrollmode = SCROLL_YPAN;
+		else
+			p->scrollmode = SCROLL_YMOVE;
+
+		vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
+	}
+	else if (unit == fg_console)
+		update_screen( unit );
+	
+	if (old_data) {
+		if (--REFCOUNT(old_data) == 0) {
+			kfree( old_data - sizeof(int) );
+		}
+	}
+	
+	return( 0 );
+}
+
+
 /* ====================================================================== */
 
 /*
@@ -1946,7 +2088,7 @@
 
 
 /*
- *    I splitted the console character loop in two parts:
+ *    I split the console character loop in two parts:
  *
  *      - slow version: this blits one character at a time
  *
@@ -2179,7 +2321,7 @@
 
 
 /*
- *    I splitted the console character loop in two parts
+ *    I split the console character loop in two parts
  *    (cfr. fbcon_putcs_ilbm())
  */
 
@@ -2326,7 +2468,7 @@
 	 * destination, start at even addresses or both are at odd
 	 * addresses, just the first odd and last even column (if present)
 	 * require special treatment (memmove_col()). The rest between
-	 * then can be copied by normal operations, because all adjancent
+	 * then can be copied by normal operations, because all adjacent
 	 * bytes are affected and are to be stored in the same order.
 	 *   The pathological case is when the move should go from an odd
 	 * address to an even or vice versa. Since the bytes in the plane
@@ -2590,7 +2732,7 @@
 	 * destination, start at even addresses or both are at odd
 	 * addresses, just the first odd and last even column (if present)
 	 * require special treatment (memmove_col()). The rest between
-	 * then can be copied by normal operations, because all adjancent
+	 * then can be copied by normal operations, because all adjacent
 	 * bytes are affected and are to be stored in the same order.
 	 *   The pathological case is when the move should go from an odd
 	 * address to an even or vice versa. Since the bytes in the plane
@@ -3614,5 +3756,5 @@
 struct consw fb_con = {
    fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
    fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
-   fbcon_blank
+   fbcon_blank, fbcon_get_font, fbcon_set_font
 };
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v1.3.95/linux/arch/m68k/defconfig	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/defconfig	Fri Apr 26 10:30:50 1996
@@ -123,6 +123,7 @@
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_UFS_FS is not set
 
 #
 # Character devices
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/bindec.S linux/arch/m68k/fpsp040/bindec.S
--- v1.3.95/linux/arch/m68k/fpsp040/bindec.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/bindec.S	Fri Apr 26 12:12:35 1996
@@ -70,7 +70,7 @@
 |		in INEX2.
 |
 |	A10.	Or in INEX.
-|		If INEX is set, round error occured.  This is
+|		If INEX is set, round error occurred.  This is
 |		compensated for by 'or-ing' in the INEX2 flag to
 |		the lsb of Y.
 |
@@ -518,7 +518,7 @@
 
 
 | A10. Or in INEX.
-|      If INEX is set, round error occured.  This is compensated
+|      If INEX is set, round error occurred.  This is compensated
 |      for by 'or-ing' in the INEX2 flag to the lsb of Y.
 |
 | Register usage:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/decbin.S linux/arch/m68k/fpsp040/decbin.S
--- v1.3.95/linux/arch/m68k/fpsp040/decbin.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/decbin.S	Fri Apr 26 12:12:35 1996
@@ -63,7 +63,7 @@
 |	in an inex2 exception.  If so, set inex1 in the fpsr and 
 |	check if the inex1 exception is enabled.  If so, set d7 upper
 |	word to $0100.  This will signal unimp.sa that an enabled inex1
-|	exception occured.  Unimp will fix the stack.
+|	exception occurred.  Unimp will fix the stack.
 |	
 
 |		Copyright (C) Motorola, Inc. 1990
@@ -204,7 +204,7 @@
 |  Get the rest of the mantissa.
 |
 loadlw:
-	movel	(%a0,%d1.L*4),%d4	|load mantissa lonqword into d4
+	movel	(%a0,%d1.L*4),%d4	|load mantissa longword into d4
 	moveql	#FSTRT,%d3	|counter to pick up digits
 	moveql	#FNIBS,%d2	|reset number of digits per a0 ptr
 md2b:
@@ -245,21 +245,21 @@
 |
 |  1. Branch on the sign of the adjusted exponent.
 |  2p.(positive exp)
-|   2. Check M16 and the digits in lwords 2 and 3 in decending order.
+|   2. Check M16 and the digits in lwords 2 and 3 in descending order.
 |   3. Add one for each zero encountered until a non-zero digit.
 |   4. Subtract the count from the exp.
 |   5. Check if the exp has crossed zero in #3 above; make the exp abs
 |	   and set SE.
 |	6. Multiply the mantissa by 10**count.
 |  2n.(negative exp)
-|   2. Check the digits in lwords 3 and 2 in decending order.
+|   2. Check the digits in lwords 3 and 2 in descending order.
 |   3. Add one for each zero encountered until a non-zero digit.
 |   4. Add the count to the exp.
 |   5. Check if the exp has crossed zero in #3 above; clear SE.
 |   6. Divide the mantissa by 10**count.
 |
 |  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
-|   any adjustment due to append/strip zeros will drive the resultane
+|   any adjustment due to append/strip zeros will drive the resultant
 |   exponent towards zero.  Since all pwrten constants with a power
 |   of 27 or less are exact, there is no need to use this routine to
 |   attempt to lessen the resultant exponent.
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/fpsp.h linux/arch/m68k/fpsp040/fpsp.h
--- v1.3.95/linux/arch/m68k/fpsp040/fpsp.h	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/fpsp.h	Fri Apr 26 12:12:35 1996
@@ -161,7 +161,7 @@
 	.set	guard_bit,1		| guard bit is bit number 1
 	.set	round_bit,0		| round bit is bit number 0
 	.set	stag_mask,0xE0		| upper 3 bits are source tag type
-	.set	denorm_bit,7		| bit determins if denorm or unnorm
+	.set	denorm_bit,7		| bit determines if denorm or unnorm
 	.set	etemp15_bit,4		| etemp exponent bit #15
 	.set	wbtemp66_bit,2		| wbtemp mantissa bit #66
 	.set	wbtemp1_bit,1		| wbtemp mantissa bit #1
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/gen_except.S linux/arch/m68k/fpsp040/gen_except.S
--- v1.3.95/linux/arch/m68k/fpsp040/gen_except.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/gen_except.S	Fri Apr 26 12:12:35 1996
@@ -296,7 +296,7 @@
 	moveb	#BUSY_SIZE-4,1(%a7)		|write busy fmt word.
 busy_fr:
 	movel	FP_SCR1(%a6),WBTEMP_EX(%a6)	|write
-	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a6)	|execptional op to
+	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a6)	|exceptional op to
 	movel	FP_SCR1+8(%a6),WBTEMP_LO(%a6)	|wbtemp
 	bsetb	#E3,E_BYTE(%a6)			|set E3 flag
 	bclrb	#E1,E_BYTE(%a6)			|make sure E1 is clear
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/get_op.S linux/arch/m68k/fpsp040/get_op.S
--- v1.3.95/linux/arch/m68k/fpsp040/get_op.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/get_op.S	Fri Apr 26 12:12:35 1996
@@ -14,7 +14,7 @@
 | UNIMPLEMENTED instructions (exception vector 11) the following
 | applies:
 |
-| - For unnormormalized numbers (opclass 0, 2, or 3) the
+| - For unnormalized numbers (opclass 0, 2, or 3) the
 | number(s) is normalized and the operand type tag is updated.
 |		
 | - For a packed number (opclass 2) the number is unpacked and the
@@ -48,7 +48,7 @@
 | detects this and tags the number as a denorm.  The routine
 | res_func sees the denorm tag and converts the denorm to a
 | norm.  The instruction is then restored back into the '040
-| which re_executess the instruction.
+| which re_executes the instruction.
 |
 |
 |		Copyright (C) Motorola, Inc. 1990
@@ -354,7 +354,7 @@
 
 |
 | Sets the DY_MO_FLG correctly. This is used only on if it is an
-| unuspported data type exception.  Set if dyadic.
+| unsupported data type exception.  Set if dyadic.
 |
 chk_dy_mo:
 	movew	CMDREG1B(%a6),%d0	
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/res_func.S linux/arch/m68k/fpsp040/res_func.S
--- v1.3.95/linux/arch/m68k/fpsp040/res_func.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/res_func.S	Fri Apr 26 12:12:35 1996
@@ -83,7 +83,7 @@
 	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
 	bne	opclass3			|it is a mv out
 |
-| At this point, only oplcass 0 and 2 possible
+| At this point, only opclass 0 and 2 possible
 |
 	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
 |				;inf=010 or nan=011
@@ -299,7 +299,7 @@
 	bnes	cu_nunzro
 |
 | The mantissa is zero from the denorm loop.  Check sign and rmode
-| to see if rounding should have occured which would leave the lsb.
+| to see if rounding should have occurred which would leave the lsb.
 |
 	movel	USER_FPCR(%a6),%d0
 	andil	#0x30,%d0		|isolate rmode
@@ -413,7 +413,7 @@
 
 |
 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
-| ftst) completly in software without an frestore to the 040. 
+| ftst) completely in software without an frestore to the 040. 
 |
 cu_dnrm:
 	st	CU_ONLY(%a6)
@@ -610,7 +610,7 @@
 |	DNRM_FLG contains $00 for neither op denormalized
 |	                  $0f for the destination op denormalized
 |	                  $f0 for the source op denormalized
-|	                  $ff for both ops denormalzed
+|	                  $ff for both ops denormalized
 |
 | The wrap-around condition occurs for add, sub, div, and cmp
 | when 
@@ -828,7 +828,7 @@
 | precision.  We can then call round with no sticky and the result
 | will be correct for the user's rounding mode and precision.  If
 | the signs are the same, we call round with the sticky bit set
-| and the result will be correctfor the user's rounding mode and
+| and the result will be correct for the user's rounding mode and
 | precision.
 |
 add_wrap:
@@ -1003,7 +1003,7 @@
 | precision.  We can then call round with no sticky and the result
 | will be correct for the user's rounding mode and precision.  If
 | the signs are unlike, we call round with the sticky bit set
-| and the result will be correctfor the user's rounding mode and
+| and the result will be correct for the user's rounding mode and
 | precision.
 |
 sub_wrap:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/round.S linux/arch/m68k/fpsp040/round.S
--- v1.3.95/linux/arch/m68k/fpsp040/round.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/round.S	Fri Apr 26 12:12:35 1996
@@ -212,7 +212,7 @@
 add_ext:
 	addql  #1,LOCAL_LO(%a0)		|add 1 to l-bit
 	bccs	xcc_clr			|test for carry out
-	addql  #1,LOCAL_HI(%a0)		|propogate carry
+	addql  #1,LOCAL_HI(%a0)		|propagate carry
 	bccs	xcc_clr
 	roxrw  LOCAL_HI(%a0)		|mant is 0 so restore v-bit
 	roxrw  LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
@@ -231,7 +231,7 @@
 add_dbl:
 	addl	#ad_1_dbl,LOCAL_LO(%a0)
 	bccs	dcc_clr
-	addql	#1,LOCAL_HI(%a0)		|propogate carry
+	addql	#1,LOCAL_HI(%a0)		|propagate carry
 	bccs	dcc_clr
 	roxrw	LOCAL_HI(%a0)		|mant is 0 so restore v-bit
 	roxrw	LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
@@ -483,7 +483,7 @@
 	rts
 
 |
-|	dnrm_lp --- normalize exponent/mantissa to specified threshhold
+|	dnrm_lp --- normalize exponent/mantissa to specified threshold
 |
 | Input:
 |	a0		points to the operand to be denormalized
@@ -506,7 +506,7 @@
 	beqs	not_E3			|not type E3 exception
 	bfextu	WBTEMP_GRS(%a6){#6:#3},%d2	|extract guard,round, sticky  bit
 	movel	#29,%d0
-	lsll	%d0,%d2			|shift g,r,s to their postions
+	lsll	%d0,%d2			|shift g,r,s to their positions
 	movel	%d2,%d0
 not_E3:
 	movel	(%sp)+,%d2		|restore d2
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/satan.S linux/arch/m68k/fpsp040/satan.S
--- v1.3.95/linux/arch/m68k/fpsp040/satan.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/satan.S	Fri Apr 26 12:12:35 1996
@@ -1,7 +1,7 @@
 |
 |	satan.sa 3.3 12/19/90
 |
-|	The entry point satan computes the arctagent of an
+|	The entry point satan computes the arctangent of an
 |	input value. satand does the same except the input value is a
 |	denormalized number.
 |
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/scale.S linux/arch/m68k/fpsp040/scale.S
--- v1.3.95/linux/arch/m68k/fpsp040/scale.S	Tue Apr 23 13:57:04 1996
+++ linux/arch/m68k/fpsp040/scale.S	Fri Apr 26 12:12:35 1996
@@ -2,7 +2,7 @@
 |	scale.sa 3.3 7/30/91
 |
 |	The entry point sSCALE computes the destination operand
-|	scaled by the source operand.  If the absoulute value of
+|	scaled by the source operand.  If the absolute value of
 |	the source operand is (>= 2^14) an overflow or underflow
 |	is returned.
 |
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/sint.S linux/arch/m68k/fpsp040/sint.S
--- v1.3.95/linux/arch/m68k/fpsp040/sint.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/sint.S	Fri Apr 26 12:12:35 1996
@@ -77,7 +77,7 @@
 	.global	sint
 sint:
 	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|use user's mode for rounding
-|					;implicity has extend precision
+|					;implicitly has extend precision
 |					;in upper word. 
 	movel	%d1,L_SCR1(%a6)		|save mode bits
 	bras	sintexc			
@@ -114,7 +114,7 @@
 	.global	sintrz
 sintrz:
 	movel	#1,L_SCR1(%a6)		|use rz mode for rounding
-|					;implicity has extend precision
+|					;implicitly has extend precision
 |					;in upper word. 
 	bras	sintexc			
 |
@@ -123,7 +123,7 @@
 |	Input:	a0 points to an IEEE extended format operand
 | 	Output:	fp0 has the result 
 |
-| Exeptions:
+| Exceptions:
 |
 | If the subroutine results in an inexact operation, the inx2 and
 | ainx bits in the USER_FPSR are set.
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
--- v1.3.95/linux/arch/m68k/fpsp040/skeleton.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/skeleton.S	Fri Apr 26 12:12:35 1996
@@ -107,7 +107,7 @@
 |	necessary for E1 exceptions.
 |
 | Code following the 'inex' label is to handle bug #1232.  In this
-| bug, if an E1 snan, ovfl, or unfl occured, and the process was
+| bug, if an E1 snan, ovfl, or unfl occurred, and the process was
 | swapped out before taking the exception, the exception taken on
 | return was inex, rather than the correct exception.  The snan, ovfl,
 | and unfl exception to be taken must not have been enabled.  The
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/slogn.S linux/arch/m68k/fpsp040/slogn.S
--- v1.3.95/linux/arch/m68k/fpsp040/slogn.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/slogn.S	Fri Apr 26 12:12:35 1996
@@ -383,7 +383,7 @@
 	fmulx	LOGOF2,%fp1	| ...GET K*LOG2 WHILE FP0 IS NOT READY
 	fmovex	%fp0,%fp2
 	fmulx	%fp2,%fp2		| ...FP2 IS V=U*U
-	fmovex	%fp1,KLOG2(%a6)	| ...PUT K*LOG2 IN MEMEORY, FREE FP1
+	fmovex	%fp1,KLOG2(%a6)	| ...PUT K*LOG2 IN MEMORY, FREE FP1
 
 |--LOG(1+U) IS APPROXIMATED BY
 |--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/ssin.S linux/arch/m68k/fpsp040/ssin.S
--- v1.3.95/linux/arch/m68k/fpsp040/ssin.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/ssin.S	Fri Apr 26 12:12:35 1996
@@ -9,7 +9,7 @@
 |	Input: Double-extended number X in location pointed to
 |		by address register a0.
 |
-|	Output: The funtion value sin(X) or cos(X) returned in Fp0 if SIN or
+|	Output: The function value sin(X) or cos(X) returned in Fp0 if SIN or
 |		COS is requested. Otherwise, for SINCOS, sin(X) is returned
 |		in Fp0, and cos(X) is returned in Fp1.
 |
@@ -32,7 +32,7 @@
 |	2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.
 |
 |	3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let
-|		k = N mod 4, so in particular, k = 0,1,2,or 3. Overwirte
+|		k = N mod 4, so in particular, k = 0,1,2,or 3. Overwrite
 |		k by k := k + AdjN.
 |
 |	4. If k is even, go to 6.
@@ -409,7 +409,7 @@
 
 |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
 |--integer quotient will be stored in N
-|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1)
 
 LOOP:
 	fmovex		%fp0,INARG(%a6)	| ...+-2**K * F, 1 <= F < 2
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/stan.S linux/arch/m68k/fpsp040/stan.S
--- v1.3.95/linux/arch/m68k/fpsp040/stan.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/stan.S	Fri Apr 26 12:12:35 1996
@@ -299,7 +299,7 @@
 
 	fmovex		%fp0,-(%sp)
 	fmovel		%d1,%fpcr		 |restore users exceptions
-	fmovex		(%sp)+,%fp0	|last inst - posibble exception set
+	fmovex		(%sp)+,%fp0	|last inst - possible exception set
 
 	bra		t_frcinx
 
@@ -340,7 +340,7 @@
 
 |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
 |--integer quotient will be stored in N
-|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1)
 
 LOOP:
 	fmovex		%fp0,INARG(%a6)	| ...+-2**K * F, 1 <= F < 2
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/tbldo.S linux/arch/m68k/fpsp040/tbldo.S
--- v1.3.95/linux/arch/m68k/fpsp040/tbldo.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/tbldo.S	Fri Apr 26 12:12:35 1996
@@ -3,7 +3,7 @@
 |
 | Modified:
 |	8/16/90	chinds	The table was constructed to use only one level
-|			of indirection in do_func for monoadic
+|			of indirection in do_func for monadic
 |			functions.  Dyadic functions require two
 |			levels, and the tables are still contained
 |			in do_func.  The table is arranged for 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/util.S linux/arch/m68k/fpsp040/util.S
--- v1.3.95/linux/arch/m68k/fpsp040/util.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/util.S	Fri Apr 26 12:12:35 1996
@@ -256,7 +256,7 @@
 	bsetb	#inf_bit,FPSR_CC(%a6)
 	bras	set_sign
 SGL_RZ:
-	leal	SGL_PLRG,%a1	|anwer is +/- large number
+	leal	SGL_PLRG,%a1	|answer is +/- large number
 	bras	set_sign
 SGL_RM:
 	tstb	LOCAL_SGN(%a0)	|if negative overflow
@@ -276,7 +276,7 @@
 	bsetb	#neg_bit,FPSR_CC(%a6)
 	bras	end_ovfr
 s_rp_pos:
-	leal	EXT_PINF,%a1	|answer is postive infinity
+	leal	EXT_PINF,%a1	|answer is positive infinity
 	bsetb	#inf_bit,FPSR_CC(%a6)
 	bras	end_ovfr
 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_bsun.S linux/arch/m68k/fpsp040/x_bsun.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_bsun.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_bsun.S	Fri Apr 26 12:12:35 1996
@@ -3,7 +3,7 @@
 |
 |	fpsp_bsun --- FPSP handler for branch/set on unordered exception
 |
-|	Copy the PC to FPIAR to maintain 881/882 compatability
+|	Copy the PC to FPIAR to maintain 881/882 compatibility
 |
 |	The real_bsun handler will need to perform further corrective
 |	measures as outlined in the 040 User's Manual on pages
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_operr.S linux/arch/m68k/fpsp040/x_operr.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_operr.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_operr.S	Fri Apr 26 12:12:35 1996
@@ -25,7 +25,7 @@
 |
 |			where exp = (true exp) - 1
 |
-|  So, wbtemp and fptemp will contain the following on erroneoulsy
+|  So, wbtemp and fptemp will contain the following on erroneously
 |	  signalled operr:
 |			fpts = 1
 |			fpte = $4000  (15 bit externally)
@@ -321,7 +321,7 @@
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | operr.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_ovfl.S linux/arch/m68k/fpsp040/x_ovfl.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_ovfl.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_ovfl.S	Fri Apr 26 12:12:35 1996
@@ -92,7 +92,7 @@
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | ovfl.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_snan.S linux/arch/m68k/fpsp040/x_snan.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_snan.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_snan.S	Fri Apr 26 12:12:35 1996
@@ -57,7 +57,7 @@
 |
 | It is possible to have an inex1 exception with the
 | snan.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_store.S linux/arch/m68k/fpsp040/x_store.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_store.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_store.S	Fri Apr 26 12:12:35 1996
@@ -138,7 +138,7 @@
 	swap	%d0		|d0 now in upper word
 	lsll	#4,%d0		|d0 now in proper place for dbl prec exp
 	tstb	LOCAL_SGN(%a1)	
-	beqs	get_mant	|if postive, go process mantissa
+	beqs	get_mant	|if positive, go process mantissa
 	bsetl	#31,%d0		|if negative, put in sign information
 |				; before continuing
 	bras	get_mant	|go process mantissa
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/fpsp040/x_unfl.S linux/arch/m68k/fpsp040/x_unfl.S
--- v1.3.95/linux/arch/m68k/fpsp040/x_unfl.S	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/fpsp040/x_unfl.S	Fri Apr 26 12:12:35 1996
@@ -9,7 +9,7 @@
 | by taking the intermediate result (which is always normalized) and 
 | shifting the mantissa right while incrementing the exponent until 
 | it is equal to the denormalized exponent for the destination 
-| format.  After denormalizatoin, the result is rounded to the 
+| format.  After denormalization, the result is rounded to the 
 | destination format.
 |		
 | Trap enabled results
@@ -80,7 +80,7 @@
 |
 | It is possible to have either inex2 or inex1 exceptions with the
 | unfl.  If the inex enable bit is set in the FPCR, and either
-| inex2 or inex1 occured, we must clean up and branch to the
+| inex2 or inex1 occurred, we must clean up and branch to the
 | real inex handler.
 |
 ck_inex:
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/ifpsp060/TEST.DOC linux/arch/m68k/ifpsp060/TEST.DOC
--- v1.3.95/linux/arch/m68k/ifpsp060/TEST.DOC	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/ifpsp060/TEST.DOC	Fri Apr 26 12:12:35 1996
@@ -45,7 +45,7 @@
 with a global search and replace function.
 
 To assist in assembling and linking these modules with other modules,
-the instaler should add symbolic labels to the top of the files.
+the installer should add symbolic labels to the top of the files.
 This will allow the calling routines to access the entry points
 of these packages.
 
@@ -159,7 +159,7 @@
 FP enabled: tests enabled snan/operr/ovfl/unfl/dz/inex.
 	    basically, it enables each of these exceptions and forces
 	    each using an implemented FP instruction. this process
-	    exercizes _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and
+	    exercises _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and
 	    _real_{snan,operr,ovfl,unfl,dz,inex}(). the test expects
 	    _real_XXXX() to do nothing except clear the exception
 	    and "rte". if a system's _real_XXXX() handler creates an
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/ifpsp060/fpsp.doc linux/arch/m68k/ifpsp060/fpsp.doc
--- v1.3.95/linux/arch/m68k/ifpsp060/fpsp.doc	Tue Apr 23 13:57:06 1996
+++ linux/arch/m68k/ifpsp060/fpsp.doc	Fri Apr 26 12:12:35 1996
@@ -254,7 +254,7 @@
             |
             |----> may exit through _060_real_trap
             |
-            |----> may exit thorugh _060_real_bsun
+            |----> may exit through _060_real_bsun
             |
             |----> may exit through _060_fpsp_done
 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v1.3.95/linux/arch/m68k/ifpsp060/iskeleton.S	Tue Apr 23 13:57:07 1996
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Fri Apr 26 12:12:35 1996
@@ -71,7 +71,7 @@
 | This is an alternate exit point for the Unimplemented Integer
 | Instruction exception handler. If the instruction was a "chk2"
 | and the operand was out of bounds, then _isp_unimp() creates
-| a CHK exception stack frame from the Unimplemented Integer Instrcution
+| a CHK exception stack frame from the Unimplemented Integer Instruction
 | stack frame and branches to this routine.
 |
 	.global		_060_real_chk
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- v1.3.95/linux/arch/m68k/kernel/console.c	Tue Apr 23 13:57:07 1996
+++ linux/arch/m68k/kernel/console.c	Fri Apr 26 10:30:50 1996
@@ -1561,7 +1561,7 @@
                            where we really draw the chars */
 
                         if (count > 2 &&
-			    !decim && currcons == fg_console) { 
+			    !decim && !utf && currcons == fg_console) { 
 				static char putcs_buf[256];
 				char   *p     = putcs_buf;
 				int putcs_count  = 1;
@@ -1582,14 +1582,25 @@
 				
 				while (count)
 				{
+					enable_bh(CONSOLE_BH);
 					c = from_user ? get_user(buf) : *buf;
+					disable_bh(CONSOLE_BH);
 					tc = translate[toggle_meta ? (c|0x80) : c];
 					if (!tc ||
 					    !(c >= 32
-					      || (disp_ctrl && c != 0x1b)
-					      || !((CTRL_ACTION >> c) & 1)))
+					      || !(((disp_ctrl ? CTRL_ALWAYS
+						   : CTRL_ACTION) >> c) & 1)))
 					  break;
+					tc = conv_uni_to_pc(tc);
+					if (tc == -4)
+					  tc = conv_uni_to_pc(0xfffd);
+					else if (tc == -3)
+					  tc = c;
+
 					buf++; n++; count--;
+					if (tc & ~console_charmask)
+					  continue; /* Conversion failed */
+
 					*p++ = tc;
 					*pos++ = tc | (attr << 8);
 					++putcs_count;
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v1.3.95/linux/arch/m68k/kernel/entry.S	Tue Apr 23 13:57:07 1996
+++ linux/arch/m68k/kernel/entry.S	Fri Apr 26 10:30:50 1996
@@ -234,7 +234,6 @@
 	cmpl	%a0@(LTASK_COUNTER),%d0   | counter
 	jeq	SYMBOL_NAME(reschedule)
 
-	.word	0xf4f8
 	movel	%a0@(LTASK_BLOCKED),%d0
 	movel	%d0,%d1			| save blocked in d1 for sig handling
 	notl	%d0
@@ -356,9 +355,6 @@
 
 	/* offset of tss struct (processor state) from beginning
 	   of task struct */
-/*
-	movel	%sp@(8),%a1
-*/
 	addl	%a1,%a0
 
 	/* save sr */
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v1.3.95/linux/arch/m68k/kernel/head.S	Tue Apr 23 13:57:07 1996
+++ linux/arch/m68k/kernel/head.S	Fri Apr 26 12:12:36 1996
@@ -313,7 +313,7 @@
 	 * on the 68040, pages used to hold mmu tables should
 	 * be initialized as noncachable; the '060 allows write-through.
 	 * Do this for the root table page (which also contains
-	 * all pointer tables utilitized thus far) and the
+	 * all pointer tables utilized thus far) and the
 	 * kernel page table.
 	 */
 	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
@@ -469,9 +469,9 @@
    is done by writing to the byte at phys. 0x0. This should result
    in a bus error on all other machines.
 
-   ...should, but doesn't. The Atferburner040 for the Falcon has the
+   ...should, but doesn't. The Afterburner040 for the Falcon has the
    same behaviour (0x0..0x7 are no ROM shadow). So we have to do
-   another test to distinuish Medusa and AB040. This is a
+   another test to distinguish Medusa and AB040. This is a
    read attempt for 0x00ff82fe phys. that should bus error on a Falcon
    (+AB040), but is in the range where the Medusa always asserts DTACK.
 */
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v1.3.95/linux/arch/m68k/kernel/sys_m68k.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/kernel/sys_m68k.c	Fri Apr 26 12:12:36 1996
@@ -20,7 +20,7 @@
 
 /*
  * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix tranditionally does this, though.
+ * a pipe. It's not the way unix traditionally does this, though.
  */
 asmlinkage int sys_pipe(unsigned long * fildes)
 {
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v1.3.95/linux/arch/m68k/kernel/traps.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/kernel/traps.c	Fri Apr 26 12:12:36 1996
@@ -261,7 +261,7 @@
 	/*
 	 * No special handling for the second writeback anymore.
 	 * It misinterpreted the misaligned status sometimes.
-	 * This way an extra pgae-fault may be caused (Martin Apel).
+	 * This way an extra page-fault may be caused (Martin Apel).
 	 */
 
 	mmusr = probe040 (1, wbs & WBTM_040,  wba);
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v1.3.95/linux/arch/m68k/mm/init.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/mm/init.c	Fri Apr 26 10:30:50 1996
@@ -448,7 +448,6 @@
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
 	int codepages = 0;
-	int reservedpages = 0;
 	int datapages = 0;
 	unsigned long tmp;
 	extern int _etext;
@@ -514,11 +513,10 @@
 			free_page(tmp);
 	}
 	tmp = nr_free_pages << PAGE_SHIFT;
-	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+	printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
 	       tmp >> 10,
 	       high_memory >> 10,
 	       codepages << (PAGE_SHIFT-10),
-	       reservedpages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10));
 }
 
diff -u --recursive --new-file v1.3.95/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v1.3.95/linux/arch/m68k/mm/memory.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/mm/memory.c	Fri Apr 26 12:12:36 1996
@@ -378,7 +378,7 @@
 {
     if (m68k_is040or060) {
 	/* ++roman: There have been too many problems with the CINV, it seems
-	 * to break the cache maintainance of DMAing drivers. I don't expect
+	 * to break the cache maintenance of DMAing drivers. I don't expect
 	 * too much overhead by using CPUSH instead.
 	 */
 	while (len > PAGE_SIZE) {
@@ -461,7 +461,7 @@
 		      "movec %/d0,%/cacr"
 		      : : "i" (FLUSH_I)
 		      : "d0");
-    }
+}
 
 void cache_push_v (unsigned long vaddr, int len)
 {
@@ -489,15 +489,44 @@
 	    pushv060(vaddr);
 	    len -= PAGE_SIZE;
 	    vaddr += PAGE_SIZE;
-	    }
+	}
 	if (len > 0) {
 	    pushv060(vaddr);
 	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
 		/* a page boundary gets crossed at the end */
 		pushv060(vaddr + len - 1);
-		}
 	    }
 	}
+    }
+    /* 68030/68020 have no writeback cache; still need to clear icache. */
+    else /* 68030 or 68020 */
+	asm volatile ("movec %/cacr,%/d0\n\t"
+		      "oriw %0,%/d0\n\t"
+		      "movec %/d0,%/cacr"
+		      : : "i" (FLUSH_I)
+		      : "d0");
+}
+
+void flush_cache_all(void)
+{
+    if (m68k_is040or060 >= 4)
+        __asm__ __volatile__ (".word 0xf478\n" ::);
+    else /* 68030 or 68020 */
+	asm volatile ("movec %/cacr,%/d0\n\t"
+		      "oriw %0,%/d0\n\t"
+		      "movec %/d0,%/cacr"
+		      : : "i" (FLUSH_I)
+		      : "d0");
+}
+
+void flush_page_to_ram (unsigned long addr)
+{
+    if (m68k_is040or060 == 4)
+        pushv040(addr);
+
+    else if (m68k_is040or060 == 6)
+        push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */
+
     /* 68030/68020 have no writeback cache; still need to clear icache. */
     else /* 68030 or 68020 */
 	asm volatile ("movec %/cacr,%/d0\n\t"
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/boot/bare.S linux/arch/sparc/boot/bare.S
--- v1.3.95/linux/arch/sparc/boot/bare.S	Fri Apr 12 15:51:48 1996
+++ linux/arch/sparc/boot/bare.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: bare.S,v 1.3 1995/11/27 02:42:50 davem Exp $
+/* $Id: bare.S,v 1.4 1996/04/23 01:53:40 davem Exp $
  * base.S:      Ugly low-level boot program entry code.  The job of this
  *              module is to parse the boot flags, try to mount the remote
  *              root filesystem and load the kernel into virtual memory.
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/boot/empirical.h linux/arch/sparc/boot/empirical.h
--- v1.3.95/linux/arch/sparc/boot/empirical.h	Sun Apr 21 19:21:59 1996
+++ linux/arch/sparc/boot/empirical.h	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: empirical.h,v 1.1 1996/04/21 10:17:46 davem Exp $
+/* $Id: empirical.h,v 1.2 1996/04/23 01:53:42 davem Exp $
  * empirical.h:  Nasty hacks....
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v1.3.95/linux/arch/sparc/config.in	Sun Apr 21 19:21:59 1996
+++ linux/arch/sparc/config.in	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1996/04/04 16:30:03 tridge Exp $
+# $Id: config.in,v 1.12 1996/04/24 03:15:38 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -12,6 +12,7 @@
 if [ "$CONFIG_AP1000" = "n" ]; then
 	# Global things across all Sun machines.
 	define_bool CONFIG_SBUS y
+	define_bool CONFIG_SBUSCHAR y
 	define_bool CONFIG_SUN_MOUSE y
 	define_bool CONFIG_SERIAL y
 	define_bool CONFIG_SUN_SERIAL y
@@ -30,7 +31,23 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 endmenu
 
-source drivers/block/Config.in
+mainmenu_option next_comment
+comment 'Floppy, IDE, and other block devices'
+
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
+
+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
+
+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
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 
 if [ "$CONFIG_NET" = "y" ]; then
 	source net/Config.in
@@ -42,7 +59,23 @@
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-	source drivers/scsi/Config.in
+	comment 'SCSI support type (disk, tape, CDrom)'
+
+	dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+	dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+	dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+	dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+	comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+	bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+
+	bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+
+	mainmenu_option next_comment
+	comment 'SCSI low-level drivers'
+
+	dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
 fi
 endmenu
 
@@ -52,7 +85,17 @@
 
 	bool 'Network device support' CONFIG_NETDEVICES
 	if [ "$CONFIG_NETDEVICES" = "y" ]; then
-		source drivers/net/Config.in
+		tristate 'Dummy net driver support' CONFIG_DUMMY
+		tristate 'SLIP (serial line) support' CONFIG_SLIP
+		if [ "$CONFIG_SLIP" != "n" ]; then
+		  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+		  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+		fi
+		tristate 'PPP (point-to-point) support' CONFIG_PPP
+		if [ ! "$CONFIG_PPP" = "n" ]; then
+		  comment 'CCP compressors for PPP are only built as modules.'
+		fi
+		bool 'Sun LANCE support' CONFIG_SUNLANCE
 	fi
 	endmenu
 fi
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v1.3.95/linux/arch/sparc/defconfig	Sun Apr 21 19:21:59 1996
+++ linux/arch/sparc/defconfig	Thu Apr 25 13:22:05 1996
@@ -7,6 +7,7 @@
 #
 # CONFIG_AP1000 is not set
 CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
 CONFIG_SUN_MOUSE=y
 CONFIG_SERIAL=y
 CONFIG_SUN_SERIAL=y
@@ -23,7 +24,8 @@
 #
 # Floppy, IDE, and other block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_LOOP is not set
@@ -32,6 +34,7 @@
 # Networking options
 #
 # CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
 # CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
@@ -74,7 +77,6 @@
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_AUTO_BIOSP is not set
 
 #
 # SCSI low-level drivers
@@ -111,6 +113,8 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_UFS_FS=y
 
 #
 # Kernel hacking
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v1.3.95/linux/arch/sparc/kernel/Makefile	Sun Apr 21 19:21:59 1996
+++ linux/arch/sparc/kernel/Makefile	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.29 1996/04/04 16:30:17 tridge Exp $
+# $Id: Makefile,v 1.30 1996/04/22 10:37:53 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -35,7 +35,7 @@
 	    process.o signal.o ioport.o setup.o idprom.o \
 	    sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
 	    sunos_ioctl.o time.o windows.o cpu.o devices.o ksyms.o \
-	    sclow.o solaris.o tadpole.o tick14.o
+	    sclow.o solaris.o tadpole.o tick14.o ptrace.o
 
 ifdef SMP
 O_OBJS += trampoline.o smp.o rirq.o
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v1.3.95/linux/arch/sparc/kernel/entry.S	Wed Apr 24 17:00:34 1996
+++ linux/arch/sparc/kernel/entry.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.90 1996/04/18 01:00:37 davem Exp $
+/* $Id: entry.S,v 1.93 1996/04/25 06:08:32 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -990,15 +990,27 @@
 	jmp	%l5 + 0x8		/* so stupid... */
 	 nop
 
-#if 0 /* work in progress */
+	/* Note how we really return to ret_syscall because we share the
+	 * register window with our caller.
+	 */
+
 	.align 4
 	.globl	C_LABEL(sys_ptrace)
 C_LABEL(sys_ptrace):
 	call	C_LABEL(do_ptrace)
 	 add	%sp, REGWIN_SZ, %o0
 
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	1f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
+1:
 	RESTORE_ALL
-#endif
 
 	.align	4
 	.globl	C_LABEL(sys_execve)
@@ -1028,6 +1040,16 @@
 	call	C_LABEL(do_sigpause)
 	 add	%sp, REGWIN_SZ, %o1
 
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	1f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
+1:
 	/* We are returning to a signal handler. */
 	RESTORE_ALL
 
@@ -1037,6 +1059,16 @@
 	call	C_LABEL(do_sigsuspend)
 	 add	%sp, REGWIN_SZ, %o0
 
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	1f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
+1:
 	/* We are returning to a signal handler. */
 	RESTORE_ALL
 
@@ -1046,6 +1078,16 @@
 	call	C_LABEL(do_sigreturn)
 	 add	%sp, REGWIN_SZ, %o0
 
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	1f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
+1:
 	/* We don't want to muck with user registers like a
 	 * normal syscall, just return.
 	 */
@@ -1153,6 +1195,15 @@
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	2f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
 2:
 	ldd	[%sp + REGWIN_SZ + PT_I0], %o0
 	st	%o0, [%sp + REGWIN_SZ + PT_G0]	! for restarting syscalls
@@ -1184,8 +1235,18 @@
 	or	%l5, %l6, %l5
 	st	%l5, [%sp + REGWIN_SZ + PT_PSR]
 
-	/* Advance the pc and npc over the trap instruction. */
 2:
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 0x14], %l5
+	andcc	%l5, 0x20, %g0
+	be	3f
+	 nop
+
+	call	C_LABEL(syscall_trace)
+	 nop
+
+	/* Advance the pc and npc over the trap instruction. */
+3:
 	ld	[%sp + REGWIN_SZ + PT_NPC], %l1	/* pc  = npc   */
 	add	%l1, 0x4, %l2			/* npc = npc+4 */
 	st	%l1, [%sp + REGWIN_SZ + PT_PC]
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S
--- v1.3.95/linux/arch/sparc/kernel/etrap.S	Wed Apr 24 17:00:34 1996
+++ linux/arch/sparc/kernel/etrap.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.17 1996/03/07 06:26:43 davem Exp $
+/* $Id: etrap.S,v 1.18 1996/04/25 06:08:35 davem Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v1.3.95/linux/arch/sparc/kernel/head.S	Wed Apr 24 17:00:34 1996
+++ linux/arch/sparc/kernel/head.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.56 1996/04/04 16:30:22 tridge Exp $
+/* $Id: head.S,v 1.57 1996/04/25 06:08:38 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c
--- v1.3.95/linux/arch/sparc/kernel/idprom.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/idprom.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: idprom.c,v 1.18 1995/11/25 00:58:05 davem Exp $
+/* $Id: idprom.c,v 1.19 1996/04/25 06:08:41 davem Exp $
  * idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.3.95/linux/arch/sparc/kernel/ioport.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/ioport.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.17 1996/03/23 02:39:13 davem Exp $
+/* $Id: ioport.c,v 1.18 1996/04/25 06:08:44 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v1.3.95/linux/arch/sparc/kernel/irq.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/irq.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.43 1996/04/17 12:37:45 zaitcev Exp $
+/*  $Id: irq.c,v 1.44 1996/04/25 06:08:46 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v1.3.95/linux/arch/sparc/kernel/process.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/process.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.49 1996/04/20 07:37:20 davem Exp $
+/*  $Id: process.c,v 1.51 1996/04/25 06:08:49 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -78,12 +78,9 @@
 	volatile int *spap = &smp_process_available;
 	volatile int cval;
 
-	current->priority = -50;
 	while(1) {
                 if(0==read_smp_counter(spap))
                 	continue;
-		while(*spap == -1)
-			;
 		cli();
 		/* Acquire exclusive access. */
 		while((cval = smp_swap(spap, -1)) == -1)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v1.3.95/linux/arch/sparc/kernel/ptrace.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/ptrace.c	Thu Apr 25 13:22:05 1996
@@ -0,0 +1,801 @@
+/* ptrace.c: Sparc process tracing support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ *
+ * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
+ * and David Mosberger.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/* change a pid into a task struct. */
+static inline struct task_struct * get_task(int pid)
+{
+	int i;
+
+	for (i = 1; i < NR_TASKS; i++) {
+		if (task[i] != NULL && (task[i]->pid == pid))
+			return task[i];
+	}
+	return NULL;
+}
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ */
+static unsigned long get_long(struct task_struct * tsk,
+	struct vm_area_struct * vma, unsigned long addr)
+{
+	pgd_t * pgdir;
+	pmd_t * pgmiddle;
+	pte_t * pgtable;
+	unsigned long page, retval;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (pgd_none(*pgdir)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return 0;
+	}
+	pgmiddle = pmd_offset(pgdir, addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return 0;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (page >= high_memory)
+		return 0;
+	page += addr & ~PAGE_MASK;
+	retval = *(unsigned long *) page;
+	flush_page_to_ram(page);
+	return retval;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it.  -M.U-
+ */
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+	unsigned long addr, unsigned long data)
+{
+	pgd_t *pgdir;
+	pmd_t *pgmiddle;
+	pte_t *pgtable;
+	unsigned long page;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (!pgd_present(*pgdir)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return;
+	}
+	pgmiddle = pmd_offset(pgdir, addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+	if (!pte_write(*pgtable)) {
+		do_wp_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	flush_cache_page(vma, page);
+	if (page < high_memory) {
+		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+		flush_page_to_ram(page);
+	}
+/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
+/* this should also re-instate whatever read-only mode there was before */
+	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+	flush_tlb_page(vma, page);
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
+					       unsigned long addr)
+{
+	struct vm_area_struct * vma;
+
+	addr &= PAGE_MASK;
+	vma = find_vma(tsk,addr);
+	if (!vma)
+		return NULL;
+	if (vma->vm_start <= addr)
+		return vma;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return NULL;
+	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+		return NULL;
+	vma->vm_offset -= vma->vm_start - addr;
+	vma->vm_start = addr;
+	return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+		     unsigned long * result)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	*result = get_long(tsk, vma, addr);
+	return 0;
+}
+
+static int read_byte(struct task_struct *tsk, unsigned long addr,
+		     unsigned char *result)
+{
+	struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
+	unsigned long tmp;
+
+	if(!vma)
+		return -EIO;
+	tmp = get_long(tsk, vma, (addr & ~3));
+	switch(addr & 3) {
+	case 0:
+		*result = (tmp & 0xff000000)>>24;
+		break;
+	case 1:
+		*result = (tmp & 0x00ff0000)>>16;
+		break;
+	case 2:
+		*result = (tmp & 0x0000ff00)>>8;
+		break;
+	case 3:
+		*result = (tmp & 0x000000ff);
+		break;
+	}
+	return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+		      unsigned long data)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	put_long(tsk, vma, addr, data);
+	return 0;
+}
+
+static int write_byte(struct task_struct * tsk, unsigned long addr,
+		      unsigned char data)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
+	unsigned long tmp;
+
+	if (!vma)
+		return -EIO;
+	tmp = get_long(tsk, vma, (addr & ~3));
+	switch(addr & 3) {
+	case 0:
+		tmp &= 0x00ffffff;
+		tmp |= (data << 24);
+		break;
+	case 1:
+		tmp &= 0xff00ffff;
+		tmp |= ((data << 16) & 0x00ff0000);
+		break;
+	case 2:
+		tmp &= 0xffff00ff;
+		tmp |= ((data << 8) & 0x0000ff00);
+		break;
+	case 3:
+		tmp &= 0xffffff00;
+		tmp |= (data & 0x000000ff);
+		break;
+	}
+	put_long(tsk, vma, (addr & ~3), tmp);
+	return 0;
+}
+
+/* Returning from ptrace is a bit tricky because the syscall return
+ * low level code assumes any value returned which is negative and
+ * is a valid errno will mean setting the condition codes to indicate
+ * an error return.  This doesn't work, so we have this hook.
+ */
+static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
+{
+	regs->u_regs[UREG_I0] = error;
+	regs->psr |= PSR_C;
+	regs->pc = regs->npc;
+	regs->npc += 4;
+}
+
+static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
+{
+	regs->u_regs[UREG_I0] = value;
+	regs->psr &= ~PSR_C;
+	regs->pc = regs->npc;
+	regs->npc += 4;
+}
+
+/* Fuck me gently with a chainsaw... */
+static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
+				   struct task_struct *tsk)
+{
+	struct pt_regs *cregs = tsk->tss.kregs;
+	struct thread_struct *t = &tsk->tss;
+
+	if(offset >= 1024)
+		offset -= 1024; /* whee... */
+	if(offset & ((sizeof(unsigned long) - 1))) {
+		pt_error_return(regs, EIO);
+		return;
+	}
+	if(offset >= 16 && offset < 784) {
+		offset -= 16; offset >>= 2;
+		pt_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset));	
+		return;
+	}
+	if(offset >= 784 && offset < 832) {
+		offset -= 784; offset >>= 2;
+		pt_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset));
+		return;
+	}
+	switch(offset) {
+	case 0:
+		regs->u_regs[UREG_I0] = t->ksp;
+		break;
+	case 4:
+		regs->u_regs[UREG_I0] = t->kpc;
+		break;
+	case 8:
+		regs->u_regs[UREG_I0] = t->kpsr;
+		break;
+	case 12:
+		regs->u_regs[UREG_I0] = t->uwinmask;
+		break;
+	case 832:
+		regs->u_regs[UREG_I0] = t->w_saved;
+		break;
+	case 896:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
+		break;
+	case 900:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
+		break;
+	case 904:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I2];
+		break;
+	case 908:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I3];
+		break;
+	case 912:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I4];
+		break;
+	case 916:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I5];
+		break;
+	case 920:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I6];
+		break;
+	case 924:
+		if(tsk->tss.flags & 0x80000000)
+			regs->u_regs[UREG_I0] = cregs->u_regs[UREG_G1];
+		else
+			regs->u_regs[UREG_I0] = 0;
+		break;
+	case 940:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
+		break;
+	case 944:
+		regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
+		break;
+
+	case 948:
+		/* Isn't binary compatability _fun_??? */
+		if(cregs->psr & PSR_C)
+			regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24;
+		else
+			regs->u_regs[UREG_I0] = 0;
+		break;
+
+		/* Rest of them are completely unsupported. */
+	default:
+		printk("%s [%d]: Wants to read user offset %d\n",
+		       current->comm, current->pid, offset);
+		pt_error_return(regs, EIO);
+		return;
+	}
+	regs->psr &= ~PSR_C;
+	regs->pc = regs->npc;
+	regs->npc += 4;
+	return;
+}
+
+static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
+				    struct task_struct *tsk)
+{
+	struct pt_regs *cregs = tsk->tss.kregs;
+	struct thread_struct *t = &tsk->tss;
+	unsigned long value = regs->u_regs[UREG_I3];
+
+	if(offset >= 1024)
+		offset -= 1024; /* whee... */
+	if(offset & ((sizeof(unsigned long) - 1)))
+		goto failure;
+	if(offset >= 16 && offset < 784) {
+		offset -= 16; offset >>= 2;
+		*(((unsigned long *)(&t->reg_window[0]))+offset) = value;
+		goto success;
+	}
+	if(offset >= 784 && offset < 832) {
+		offset -= 784; offset >>= 2;
+		*(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
+		goto success;
+	}
+	switch(offset) {
+	case 896:
+		cregs->u_regs[UREG_I0] = value;
+		break;
+	case 900:
+		cregs->u_regs[UREG_I1] = value;
+		break;
+	case 904:
+		cregs->u_regs[UREG_I2] = value;
+		break;
+	case 908:
+		cregs->u_regs[UREG_I3] = value;
+		break;
+	case 912:
+		cregs->u_regs[UREG_I4] = value;
+		break;
+	case 916:
+		cregs->u_regs[UREG_I5] = value;
+		break;
+	case 920:
+		cregs->u_regs[UREG_I6] = value;
+		break;
+	case 924:
+		cregs->u_regs[UREG_I7] = value;
+		break;
+	case 940:
+		cregs->u_regs[UREG_I0] = value;
+		break;
+	case 944:
+		cregs->u_regs[UREG_I1] = value;
+		break;
+
+		/* Rest of them are completely unsupported or "no-touch". */
+	default:
+		printk("%s [%d]: Wants to write user offset %d\n",
+		       current->comm, current->pid, offset);
+		goto failure;
+	}
+success:
+	pt_succ_return(regs, 0);
+	return;
+failure:
+	pt_error_return(regs, EIO);
+	return;
+}
+
+/* #define ALLOW_INIT_TRACING */
+/* #define DEBUG_PTRACE */
+
+asmlinkage void do_ptrace(struct pt_regs *regs)
+{
+	unsigned long request = regs->u_regs[UREG_I0];
+	unsigned long pid = regs->u_regs[UREG_I1];
+	unsigned long addr = regs->u_regs[UREG_I2];
+	unsigned long data = regs->u_regs[UREG_I3];
+	unsigned long addr2 = regs->u_regs[UREG_I4];
+	struct task_struct *child;
+
+#ifdef DEBUG_PTRACE
+	printk("do_ptrace: rq=%d pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
+	       (int) request, (int) pid, addr, data, addr2);
+#endif
+	if(request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->flags & PF_PTRACED) {
+			pt_error_return(regs, EPERM);
+			return;
+		}
+		/* set the ptrace bit in the process flags. */
+		current->flags |= PF_PTRACED;
+		pt_succ_return(regs, 0);
+		return;
+	}
+#ifndef ALLOW_INIT_TRACING
+	if(pid == 1) {
+		/* Can't dork with init. */
+		pt_error_return(regs, EPERM);
+		return;
+	}
+#endif
+	if(!(child = get_task(pid))) {
+		pt_error_return(regs, ESRCH);
+		return;
+	}
+
+	if(request == PTRACE_SUNATTACH) {
+		if(child == current) {
+			/* Try this under SunOS/Solaris, bwa haha
+			 * You'll never be able to kill the process. ;-)
+			 */
+			pt_error_return(regs, EPERM);
+			return;
+		}
+		if((!child->dumpable ||
+		    (current->uid != child->euid) ||
+		    (current->uid != child->uid) ||
+		    (current->gid != child->egid) ||
+		    (current->gid != child->gid)) && !suser()) {
+			pt_error_return(regs, EPERM);
+			return;
+		}
+		/* the same process cannot be attached many times */
+		if (child->flags & PF_PTRACED) {
+			pt_error_return(regs, EPERM);
+			return;
+		}
+		child->flags |= PF_PTRACED;
+		if(child->p_pptr != current) {
+			REMOVE_LINKS(child);
+			child->p_pptr = current;
+			SET_LINKS(child);
+		}
+		send_sig(SIGSTOP, child, 1);
+		pt_succ_return(regs, 0);
+		return;
+	}
+	if(!(child->flags & PF_PTRACED)) {
+		pt_error_return(regs, ESRCH);
+		return;
+	}
+	if(child->state != TASK_STOPPED) {
+		if(request != PTRACE_KILL) {
+			pt_error_return(regs, ESRCH);
+			return;
+		}
+	}
+	if(child->p_pptr != current) {
+		pt_error_return(regs, ESRCH);
+		return;
+	}
+	switch(request) {
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int res;
+
+		/* Non-word alignment _not_ allowed on Sparc. */
+		if(addr & (sizeof(unsigned long) - 1)) {
+			pt_error_return(regs, EINVAL);
+			return;
+		}
+		res = read_long(child, addr, &tmp);
+		if (res < 0) {
+			pt_error_return(regs, -res);
+			return;
+		}
+		pt_succ_return(regs, tmp);
+		return;
+	}
+
+	case PTRACE_PEEKUSR:
+		read_sunos_user(regs, addr, child);
+		return;
+
+	case PTRACE_POKEUSR:
+		write_sunos_user(regs, addr, child);
+		return;
+
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA: {
+		struct vm_area_struct *vma;
+		int res;
+
+		/* Non-word alignment _not_ allowed on Sparc. */
+		if(addr & (sizeof(unsigned long) - 1)) {
+			pt_error_return(regs, EINVAL);
+			return;
+		}
+		vma = find_extend_vma(child, addr);
+		if(vma && request == PTRACE_POKEDATA && (vma->vm_flags & VM_EXEC)) {
+			pt_error_return(regs, EIO);
+			return;
+		}
+		res = write_long(child, addr, data);
+		if(res < 0)
+			pt_error_return(regs, -res);
+		else
+			pt_succ_return(regs, res);
+		return;
+	}
+
+	case PTRACE_GETREGS: {
+		struct pt_regs *pregs = (struct pt_regs *) addr;
+		struct pt_regs *cregs = child->tss.kregs;
+		int rval;
+
+		rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs) - 4);
+		if(rval) {
+			pt_error_return(regs, rval);
+			return;
+		}
+		pregs->psr = cregs->psr;
+		pregs->pc = cregs->pc;
+		pregs->npc = cregs->npc;
+		pregs->y = cregs->y;
+		for(rval = 1; rval < 16; rval++)
+			pregs->u_regs[rval - 1] = cregs->u_regs[rval];
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_SETREGS: {
+		struct pt_regs *pregs = (struct pt_regs *) addr;
+		struct pt_regs *cregs = child->tss.kregs;
+		unsigned long psr;
+		int rval, i;
+
+		rval = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs) - 4);
+		if(rval) {
+			pt_error_return(regs, rval);
+			return;
+		}
+		/* Must be careful, tracing process can only set certain
+		 * bits in the psr.
+		 */
+		psr = (pregs->psr) & PSR_ICC;
+		cregs->psr &= ~PSR_ICC;
+		cregs->psr |= psr;
+		if(!((pregs->pc | pregs->npc) & 3)) {
+			cregs->pc = pregs->pc;
+			cregs->npc = pregs->npc;
+		}
+		cregs->y = pregs->y;
+		for(i = 1; i < 16; i++)
+			cregs->u_regs[i] = pregs->u_regs[i-1];
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_GETFPREGS: {
+		struct fps {
+			unsigned long regs[32];
+			unsigned long fsr;
+			unsigned long flags;
+			unsigned long extra;
+			unsigned long fpqd;
+			struct fq {
+				unsigned long *insnaddr;
+				unsigned long insn;
+			} fpq[16];
+		} *fps = (struct fps *) addr;
+		int rval, i;
+
+		rval = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
+		if(rval) { pt_error_return(regs, rval); return; }
+		for(i = 0; i < 32; i++)
+			fps->regs[i] = child->tss.float_regs[i];
+		fps->fsr = child->tss.fsr;
+		fps->fpqd = child->tss.fpqdepth;
+		fps->flags = fps->extra = 0;
+		for(i = 0; i < 16; i++) {
+			fps->fpq[i].insnaddr = child->tss.fpqueue[i].insn_addr;
+			fps->fpq[i].insn = child->tss.fpqueue[i].insn;
+		}
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_SETFPREGS: {
+		struct fps {
+			unsigned long regs[32];
+			unsigned long fsr;
+			unsigned long flags;
+			unsigned long extra;
+			unsigned long fpqd;
+			struct fq {
+				unsigned long *insnaddr;
+				unsigned long insn;
+			} fpq[16];
+		} *fps = (struct fps *) addr;
+		int rval, i;
+
+		rval = verify_area(VERIFY_READ, fps, sizeof(struct fps));
+		if(rval) { pt_error_return(regs, rval); return; }
+		for(i = 0; i < 32; i++)
+			child->tss.float_regs[i] = fps->regs[i];
+		child->tss.fsr = fps->fsr;
+		child->tss.fpqdepth = fps->fpqd;
+		for(i = 0; i < 16; i++) {
+			child->tss.fpqueue[i].insn_addr = fps->fpq[i].insnaddr;
+			child->tss.fpqueue[i].insn = fps->fpq[i].insn;
+		}
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_READTEXT:
+	case PTRACE_READDATA: {
+		unsigned char *dest = (unsigned char *) addr2;
+		unsigned long src = addr;
+		unsigned char tmp;
+		int res, len = data;
+
+		res = verify_area(VERIFY_WRITE, (void *) dest, len);
+		if(res) {
+			pt_error_return(regs, -res);
+			return;
+		}
+		while(len) {
+			res = read_byte(child, src, &tmp);
+			if(res < 0) {
+				pt_error_return(regs, -res);
+				return;
+			}
+			*dest = tmp;
+			src++; dest++; len--;
+		}
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_WRITETEXT:
+	case PTRACE_WRITEDATA: {
+		unsigned char *src = (unsigned char *) addr2;
+		unsigned long dest = addr;
+		int res, len = data;
+
+		res = verify_area(VERIFY_READ, (void *) src, len);
+		if(res) {
+			pt_error_return(regs, -res);
+			return;
+		}
+		while(len) {
+			res = write_byte(child, dest, *src);
+			if(res < 0) {
+				pt_error_return(regs, -res);
+				return;
+			}
+			src++; dest++; len--;
+		}
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
+		data = 0;
+		addr = 1;
+
+	case PTRACE_CONT: { /* restart after signal. */
+		if ((unsigned long) data > NSIG) {
+			pt_error_return(regs, EIO);
+			return;
+		}
+		if (request == PTRACE_SYSCALL)
+			child->flags |= PF_TRACESYS;
+		else
+			child->flags &= ~PF_TRACESYS;
+		child->exit_code = data;
+		if((addr != 1) & !(addr & 3)) {
+			child->tss.kregs->pc = addr;
+			child->tss.kregs->npc = addr + 4;
+		}
+		wake_up_process(child);
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		if (child->state == TASK_ZOMBIE) {	/* already dead */
+			pt_succ_return(regs, 0);
+			return;
+		}
+		wake_up_process(child);
+		child->exit_code = SIGKILL;
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+		if ((unsigned long) data > NSIG) {
+			pt_error_return(regs, EIO);
+			return;
+		}
+		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+		wake_up_process(child);
+		child->exit_code = data;
+		REMOVE_LINKS(child);
+		child->p_pptr = child->p_opptr;
+		SET_LINKS(child);
+		pt_succ_return(regs, 0);
+		return;
+	}
+
+	/* PTRACE_DUMPCORE unsupported... */
+
+	default:
+		pt_error_return(regs, EIO);
+		return;
+	}
+}
+
+asmlinkage void syscall_trace(void)
+{
+#ifdef DEBUG_PTRACE
+	printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
+#endif
+	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+			!= (PF_PTRACED|PF_TRACESYS))
+		return;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	current->tss.flags ^= 0x80000000;
+	notify_parent(current);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code)
+		current->signal |= (1 << (current->exit_code - 1));
+	current->exit_code = 0;
+}
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v1.3.95/linux/arch/sparc/kernel/setup.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/setup.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.60 1996/04/04 16:30:28 tridge Exp $
+/*  $Id: setup.c,v 1.62 1996/04/25 09:11:33 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -212,20 +212,11 @@
 void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-	int total, i, panic_stuff[2], packed;
+	int total, i, packed;
 
 #if CONFIG_AP1000
         register_console(prom_printf);
 	((char *)(&cputypval))[4] = 'm'; /* ugly :-( */
-#endif
-
-#if 0
-	/* Always reboot on panic, but give 5 seconds to hit L1-A
-	 * and look at debugging info if desired.
-	 */
-	panic_stuff[0] = 1;
-	panic_stuff[1] = 5;
-	panic_setup(0, panic_stuff);
 #endif
 
 	sparc_ttable = (struct tt_entry *) &start;
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v1.3.95/linux/arch/sparc/kernel/signal.c	Sun Apr 21 19:22:00 1996
+++ linux/arch/sparc/kernel/signal.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.31 1996/04/18 01:00:41 davem Exp $
+/*  $Id: signal.c,v 1.32 1996/04/22 19:37:48 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -232,6 +232,22 @@
 		clear_bit(signr, &current->signal);
 		sa = current->sig->action + signr;
 		signr++;
+		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current);
+			schedule();
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+			if (signr == SIGSTOP)
+				continue;
+			if (_S(signr) & current->blocked) {
+				current->signal |= _S(signr);
+				continue;
+			}
+			sa = current->sig->action + signr - 1;
+		}
 		if(sa->sa_handler == SIG_IGN) {
 			if(signr != SIGCHLD)
 				continue;
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v1.3.95/linux/arch/sparc/kernel/smp.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/smp.c	Thu Apr 25 13:22:05 1996
@@ -93,7 +93,7 @@
 	sprintf(smp_buf,
 "\n        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
 "State: %s\t\t%s\t\t%s\t\t%s\n"
-"Lock:  %08lx\t\t%08lx\t%08lx\t\t%08lx\n"
+"Lock:  %08lx\t\t%08lx\t%08lx\t%08lx\n"
 "\n"
 "klock: %x\n",
 		(cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline",
@@ -236,7 +236,6 @@
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			printk("Starting CPU %d at %p\n", i, entry);
 			mid_xlate[i] = (linux_cpus[i].mid & ~8);
-			current_set[i] = &init_task;
 			local_flush_cache_all();
 			prom_startcpu(linux_cpus[i].prom_node,
 				      &penguin_ctable, 0, (char *)entry);
@@ -255,7 +254,6 @@
 			} else {
 				printk("Penguin %d is stuck in the bottle.\n", i);
 			}
-			current_set[i] = 0;
 		}
 		if(!(cpu_callin_map[i])) {
 			cpu_present_map &= ~(1 << i);
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c
--- v1.3.95/linux/arch/sparc/kernel/sparc-stub.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/sparc-stub.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.15 1996/04/04 12:41:35 davem Exp $
+/* $Id: sparc-stub.c,v 1.16 1996/04/25 06:09:01 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v1.3.95/linux/arch/sparc/kernel/sunos_ioctl.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.18 1996/04/04 12:41:38 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.20 1996/04/25 06:09:08 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -139,8 +139,43 @@
 		 */
 		return 0;
 	/* Non posix grp */
-	case _IOR('t', 119, int):
-		return -EIO;
+	case _IOW('t', 118, int): {
+		int oldval, *ptr;
+
+		cmd = TIOCSPGRP;
+		ptr = (int *) arg;
+		oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int));
+		if(oldval)
+			return oldval;
+		oldval = *ptr;
+		foo = sys_ioctl(fd, cmd, arg);
+		if(*ptr == -1) {
+			*ptr = oldval;
+			foo = -EIO;
+		}
+		if(foo == -ENOTTY)
+			foo = -EIO;
+		return foo;
+	}
+
+	case _IOR('t', 119, int): {
+		int oldval, *ptr;
+
+		cmd = TIOCGPGRP;
+		ptr = (int *) arg;
+		oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int));
+		if(oldval)
+			return oldval;
+		oldval = *ptr;
+		foo = sys_ioctl(fd, cmd, arg);
+		if(*ptr == -1) {
+			*ptr = oldval;
+			foo = -EIO;
+		}
+		if(foo == -ENOTTY)
+			foo = -EIO;
+		return foo;
+	}
 	}
 
 #if 0
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v1.3.95/linux/arch/sparc/kernel/sys_sparc.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/sys_sparc.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.10 1996/04/20 08:33:55 davem Exp $
+/* $Id: sys_sparc.c,v 1.11 1996/04/25 06:09:10 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v1.3.95/linux/arch/sparc/kernel/sys_sunos.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/sys_sunos.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.37 1996/04/19 16:52:38 miguel Exp $
+/* $Id: sys_sunos.c,v 1.40 1996/04/25 09:11:36 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -35,6 +35,8 @@
 #include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/resource.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
@@ -565,7 +567,7 @@
 	case _PCONF_NOTRUNC:
 		return 0; /* XXX Investigate XXX */
 	case _PCONF_VDISABLE:
-		return 30; /* XXX Investigate XXX */
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -1011,3 +1013,34 @@
 	return fdcount;
 }
 
+extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
+extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
+extern asmlinkage int sys_shmdt (char *shmaddr);
+extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
+
+asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2,
+			    unsigned long arg3)
+{
+	unsigned long raddr;
+	int rval;
+
+	switch(op) {
+	case 0:
+		/* sys_shmat(): attach a shared memory area */
+		rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr);
+		if(rval != 0)
+			return rval;
+		return (int) raddr;
+	case 1:
+		/* sys_shmctl(): modify shared memory area attr. */
+		return sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3);
+	case 2:
+		/* sys_shmdt(): detach a shared memory area */
+		return sys_shmdt((char *)arg1);
+	case 3:
+		/* sys_shmget(): get a shared memory area */
+		return sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
+	default:
+		return -EINVAL;
+	}
+}
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v1.3.95/linux/arch/sparc/kernel/systbls.S	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/systbls.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.38 1996/04/20 08:43:26 davem Exp $
+/* $Id: systbls.S,v 1.41 1996/04/25 09:11:39 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -147,7 +147,7 @@
 	.long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
 	.long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
@@ -197,7 +197,7 @@
 	.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
 	.long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_audit)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
 	.long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v1.3.95/linux/arch/sparc/kernel/traps.c	Sun Apr 21 19:22:01 1996
+++ linux/arch/sparc/kernel/traps.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.42 1996/04/16 08:24:44 davem Exp $
+/* $Id: traps.c,v 1.43 1996/04/24 09:09:42 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 #include <asm/unistd.h>
+#include <asm/traps.h>
 #include <asm/smp.h>
 
 /* #define TRAP_DEBUG */
@@ -95,6 +96,10 @@
 		printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
 		die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs);
 	}	
+	if(type == SP_TRAP_SBPT) {
+		send_sig(SIGTRAP, current, 1);
+		return;
+	}
 	current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
 	current->tss.sig_address = pc;
 	send_sig(SIGILL, current, 1);
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v1.3.95/linux/arch/sparc/kernel/wuf.S	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/kernel/wuf.S	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.22 1996/04/03 02:15:13 davem Exp $
+/* $Id: wuf.S,v 1.23 1996/04/25 06:09:18 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v1.3.95/linux/arch/sparc/mm/fault.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/mm/fault.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.61 1996/04/12 06:52:35 davem Exp $
+/* $Id: fault.c,v 1.62 1996/04/25 06:09:26 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c
--- v1.3.95/linux/arch/sparc/mm/generic.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/mm/generic.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,5 @@
-/* generic.c: Generic Sparc mm routines that are not dependent upon
+/* $Id: generic.c,v 1.2 1996/04/25 06:09:30 davem Exp $
+ * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.3.95/linux/arch/sparc/mm/init.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/mm/init.c	Thu Apr 25 13:22:05 1996
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.36 1996/04/16 08:02:54 davem Exp $
+/*  $Id: init.c,v 1.37 1996/04/25 06:09:33 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v1.3.95/linux/arch/sparc/mm/srmmu.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/mm/srmmu.c	Thu Apr 25 13:22:06 1996
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.59 1996/04/21 10:32:21 davem Exp $
+/* $Id: srmmu.c,v 1.62 1996/04/25 09:11:47 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -604,11 +604,14 @@
 /* Tsunami does not have a Copy-back style virtual cache. */
 static void tsunami_flush_page_to_ram(unsigned long page)
 {
+	tsunami_flush_icache();
+	tsunami_flush_dcache();
 }
 
 /* However, Tsunami is not IO coherent. */
 static void tsunami_flush_page_for_dma(unsigned long page)
 {
+	tsunami_flush_icache();
 	tsunami_flush_dcache();
 }
 
@@ -805,7 +808,6 @@
 
 static void viking_flush_cache_all(void)
 {
-	viking_flush_icache();
 }
 
 static void viking_flush_cache_mm(struct mm_struct *mm)
@@ -814,7 +816,6 @@
 	if(mm->context != NO_CONTEXT) {
 #endif
 		flush_user_windows();
-		viking_flush_icache();
 #ifndef __SMP__
 	}
 #endif
@@ -826,7 +827,6 @@
 	if(mm->context != NO_CONTEXT) {
 #endif
 		flush_user_windows();
-		viking_flush_icache();
 #ifndef __SMP__
 	}
 #endif
@@ -839,8 +839,6 @@
 	if(mm->context != NO_CONTEXT) {
 #endif
 		flush_user_windows();
-		if(vma->vm_flags & VM_EXEC)
-			viking_flush_icache();
 #ifndef __SMP__
 	}
 #endif
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c
--- v1.3.95/linux/arch/sparc/prom/memory.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/prom/memory.c	Thu Apr 25 13:22:06 1996
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.6 1996/04/08 09:02:27 davem Exp $
+/* $Id: memory.c,v 1.7 1996/04/25 06:09:46 davem Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
diff -u --recursive --new-file v1.3.95/linux/arch/sparc/prom/palloc.c linux/arch/sparc/prom/palloc.c
--- v1.3.95/linux/arch/sparc/prom/palloc.c	Wed Apr 24 17:00:35 1996
+++ linux/arch/sparc/prom/palloc.c	Thu Apr 25 13:22:06 1996
@@ -1,4 +1,4 @@
-/* $Id: palloc.c,v 1.3 1995/11/25 01:00:08 davem Exp $
+/* $Id: palloc.c,v 1.4 1996/04/25 06:09:48 davem Exp $
  * palloc.c:  Memory allocation from the Sun PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v1.3.95/linux/drivers/block/amiflop.c	Tue Apr 23 13:57:08 1996
+++ linux/drivers/block/amiflop.c	Fri Apr 26 12:12:25 1996
@@ -677,7 +677,7 @@
                            but this compiler solves it  by adding silently 
                            adding a pad byte so data wont fit
                            and this cost about 3h to discover.... */
-unsigned char gap1[22];     /* for longword-aligndness (0x4e) */
+unsigned char gap1[22];     /* for longword-alignedness (0x4e) */
 };
 
 /* crc routines are borrowed from the messydos-handler  */
@@ -702,7 +702,7 @@
 ; How CRCs "really" work:
 ;
 ; First, you should regard a bitstring as a series of coefficients of
-; polymomials. We calculate with these polynomials in modulo-2
+; polynomials. We calculate with these polynomials in modulo-2
 ; arithmetic, in which both add and subtract are done the same as
 ; exclusive-or. Now, we modify our data (a very long polynomial) in
 ; such a way that it becomes divisible by the CCITT-standard 16-bit
@@ -1637,7 +1637,7 @@
   unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
         unit[drive].sects;
 
-printk("fd%d: accesing %s-disk with %s-layout\n",drive,unit[drive].type->name,
+printk("fd%d: accessing %s-disk with %s-layout\n",drive,unit[drive].type->name,
   data_types[system].name);
 
   return 0;
diff -u --recursive --new-file v1.3.95/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v1.3.95/linux/drivers/block/ataflop.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/block/ataflop.c	Fri Apr 26 12:12:25 1996
@@ -38,7 +38,7 @@
  *  - for medusa, the step rate is always 3ms
  *  - on medusa, use only cache_push()
  * Roman:
- *  - Make disk format numbering independant from minors
+ *  - Make disk format numbering independent from minors
  *  - Let user set max. supported drive type (speeds up format
  *    detection, saves buffer space)
  *
@@ -244,7 +244,7 @@
 /* Buffering variables:
  * First, there is a DMA buffer in ST-RAM that is used for floppy DMA
  * operations. Second, a track buffer is used to cache a whole track
- * of the disk to save read operations. These are two seperate buffers
+ * of the disk to save read operations. These are two separate buffers
  * because that allows write operations without clearing the track buffer.
  */
 
@@ -299,7 +299,7 @@
 #define	FD_MOTOR_OFF_MAXTRY	(10*20)
 
 #define FLOPPY_TIMEOUT		(6*HZ)
-#define RECALIBRATE_ERRORS	4	/* Atfer this many errors the drive
+#define RECALIBRATE_ERRORS	4	/* After this many errors the drive
 					 * will be recalibrated. */
 #define MAX_ERRORS		8	/* After this many errors the driver
 					 * will give up. */
@@ -338,7 +338,7 @@
  */
 static int Probing = 0;
 
-/* This flag is set when a dummy seek is necesary to make the WP
+/* This flag is set when a dummy seek is necessary to make the WP
  * status bit accessible.
  */
 static int NeedSeek = 0;
@@ -550,7 +550,7 @@
 
  
 /* Handling of the Head Settling Flag: This flag should be set after each
- * seek operation, because we dont't use seeks with verify.
+ * seek operation, because we don't use seeks with verify.
  */
 
 static __inline__ void set_head_settle_flag( void )
@@ -880,7 +880,7 @@
 			copy_buffer( ReqData, DMABuffer );
 			paddr = PhysDMABuffer;
 		}
-		dma_cache_maintainance( paddr, 512, 1 );
+		dma_cache_maintenance( paddr, 512, 1 );
 		rwflag = 0x100;
 	}
 	else {
@@ -949,7 +949,7 @@
 	if (read_track) {
 		/* If reading a whole track, wait about one disk rotation and
 		 * then check if all sectors are read. The FDC will even
-		 * search for the first non-existant sector and need 1 sec to
+		 * search for the first non-existent sector and need 1 sec to
 		 * recognise that it isn't present :-(
 		 */
 		readtrack_timer.expires =
@@ -1061,7 +1061,7 @@
 	}	
 	if ((status & FDCSTAT_RECNF) &&
 	    /* RECNF is no error after a multiple read when the FDC
-	       searched for a non-existant sector! */
+	       searched for a non-existent sector! */
 	    !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
 		if (Probing) {
 			if (SUDT > disk_type) {
@@ -1115,11 +1115,11 @@
 		if (!read_track) {
 			void *addr;
 			addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
-			dma_cache_maintainance( VTOP(addr), 512, 0 );
+			dma_cache_maintenance( VTOP(addr), 512, 0 );
 			if (!ATARIHW_PRESENT( EXTD_DMA ))
 				copy_buffer (addr, ReqData);
 		} else {
-			dma_cache_maintainance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
+			dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
 			BufferDrive = SelectedDrive;
 			BufferSide  = ReqSide;
 			BufferTrack = ReqTrack;
@@ -1155,7 +1155,7 @@
 	DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide ));
 
 	paddr = PhysTrackBuffer;
-	dma_cache_maintainance( paddr, BUFFER_SIZE, 1 );
+	dma_cache_maintenance( paddr, BUFFER_SIZE, 1 );
 
 	fd_select_side( ReqSide );
   
@@ -1233,11 +1233,11 @@
 static void fd_times_out( unsigned long dummy )
 {
 	atari_disable_irq( IRQ_MFP_FDC );
-	if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but
+	if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but
 					  * before we came here... */
 
 	SET_IRQ_HANDLER( NULL );
-	/* If the timeout occured while the readtrack_check timer was
+	/* If the timeout occurred while the readtrack_check timer was
 	 * active, we need to cancel it, else bad things will happen */
 	if (UseTrackbuffer)
 		del_timer( &readtrack_timer );
@@ -1271,7 +1271,7 @@
 		MotorOn = 1;
 		START_TIMEOUT();
 		/* we must wait for the IRQ here, because the ST-DMA
-		   is released immediatly afterwards and the interrupt
+		   is released immediately afterwards and the interrupt
 		   may be delivered to the wrong driver. */
 	  }
 }
@@ -1333,7 +1333,7 @@
  * looking at the serial number in block 0. This isn't possible for
  * Linux, since the floppy driver can't make assumptions about the
  * filesystem used on the disk and thus the contents of block 0. I've
- * choosen the method to always say "The disk was changed" if it is
+ * chosen the method to always say "The disk was changed" if it is
  * unsure whether it was. This implies that every open or mount
  * invalidates the disk buffers if you work with write protected
  * disks. But at least this is better than working with incorrect data
diff -u --recursive --new-file v1.3.95/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.95/linux/drivers/block/floppy.c	Sun Apr 21 19:22:02 1996
+++ linux/drivers/block/floppy.c	Thu Apr 25 13:13:18 1996
@@ -294,7 +294,7 @@
 /*
  * globals used by 'result()'
  */
-#define MAX_REPLIES 17
+#define MAX_REPLIES 16
 static unsigned char reply_buffer[MAX_REPLIES];
 static int inr; /* size of reply buffer, when called from interrupt */
 #define ST0 (reply_buffer[0])
diff -u --recursive --new-file v1.3.95/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.95/linux/drivers/block/genhd.c	Sat Mar  9 13:31:43 1996
+++ linux/drivers/block/genhd.c	Thu Apr 25 12:29:39 1996
@@ -208,6 +208,43 @@
 	brelse(bh);
 }
 
+#ifdef CONFIG_BSD_DISKLABEL
+/* 
+ * Create devices for BSD partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void bsd_disklabel_partition(struct gendisk *hd, int dev)
+{
+	struct buffer_head *bh;
+	struct bsd_disklabel *l;
+	struct bsd_partition *p;
+	int mask = (1 << hd->minor_shift) - 1;
+
+	if (!(bh = bread(dev,0,1024)))
+		return;
+	bh->b_state = 0;
+	l = (struct bsd_disklabel *) (bh->b_data+512);
+	if (l->d_magic != BSD_DISKMAGIC) {
+		brelse(bh);
+		return;
+	}
+
+	p = &l->d_partitions[0];
+	while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) {
+		if ((current_minor & mask) >= (4 + hd->max_p))
+			break;
+
+		if (p->p_fstype != BSD_FS_UNUSED) {
+			add_partition(hd, current_minor, p->p_offset, p->p_size);
+			current_minor++;
+		}
+		p++;
+	}
+	brelse(bh);
+
+}
+#endif
+
 static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
 	int i, minor = current_minor;
@@ -329,6 +366,13 @@
 			if (hd->part[minor].nr_sects > 2)
 				hd->part[minor].nr_sects = 2;
 		}
+#ifdef CONFIG_BSD_DISKLABEL
+		if (p->sys_ind == BSD_PARTITION) {
+			printk(" <");
+			bsd_disklabel_partition(hd, MKDEV(hd->major, minor));
+			printk(" >");
+		}
+#endif
 	}
 	/*
 	 *  Check for old-style Disk Manager partition table
@@ -445,15 +489,27 @@
 		unsigned short nsect;      /* Sectors per track */
 		unsigned char spare3[4];   /* Even more magic... */
 		struct sun_partition {
-			unsigned long start_cylinder;
-			unsigned long num_sectors;
+			__u32 start_cylinder;
+			__u32 num_sectors;
 		} partitions[8];
 		unsigned short magic;      /* Magic number */
 		unsigned short csum;       /* Label xor'd checksum */
 	} * label;		
 	struct sun_partition *p;
+	int other_endian;
 	unsigned long spc;
-#define SUN_LABEL_MAGIC  0xDABE
+#define SUN_LABEL_MAGIC          0xDABE
+#define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
+/* No need to optimize these macros since they are called only when reading
+ * the partition table. This occurs only at each disk change. */
+#define SWAP16(x)  (other_endian ? (((__u16)(x) & 0xFF) << 8) \
+				 | (((__u16)(x) & 0xFF00) >> 8) \
+				 : (__u16)(x))
+#define SWAP32(x)  (other_endian ? (((__u32)(x) & 0xFF) << 24) \
+				 | (((__u32)(x) & 0xFF00) << 8) \
+				 | (((__u32)(x) & 0xFF0000) >> 8) \
+				 | (((__u32)(x) & 0xFF000000) >> 24) \
+				 : (__u32)(x))
 
 	if(!(bh = bread(dev, 0, 1024))) {
 		printk("Dev %d: unable to read partition table\n", dev);
@@ -461,11 +517,12 @@
 	}
 	label = (struct sun_disklabel *) bh->b_data;
 	p = label->partitions;
-	if(label->magic != SUN_LABEL_MAGIC) {
-		printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic);
+	if (label->magic != SUN_LABEL_MAGIC && label->magic != SUN_LABEL_MAGIC_SWAPPED) {
+		printk("Dev %d Sun disklabel: bad magic %04x\n", dev, label->magic);
 		brelse(bh);
 		return 0;
 	}
+	other_endian = (label->magic == SUN_LABEL_MAGIC_SWAPPED);
 	/* Look at the checksum */
 	ush = ((unsigned short *) (label+1)) - 1;
 	for(csum = 0; ush >= ((unsigned short *) label);)
@@ -476,20 +533,22 @@
 		return 0;
 	}
 	/* All Sun disks have 8 partition entries */
-	spc = (label->ntrks * label->nsect);
+	spc = SWAP16(label->ntrks) * SWAP16(label->nsect);
 	for(i=0; i < 8; i++, p++) {
 		unsigned long st_sector;
 
 		/* We register all partitions, even if zero size, so that
 		 * the minor numbers end up ok as per SunOS interpretation.
 		 */
-		st_sector = first_sector + (p->start_cylinder * spc);
-		add_partition(hd, current_minor, st_sector, p->num_sectors);
+		st_sector = first_sector + SWAP32(p->start_cylinder) * spc;
+		add_partition(hd, current_minor, st_sector, SWAP32(p->num_sectors));
 		current_minor++;
 	}
 	printk("\n");
 	brelse(bh);
 	return 1;
+#undef SWAP16
+#undef SWAP32
 }
 
 #endif /* CONFIG_SUN_PARTITION */
diff -u --recursive --new-file v1.3.95/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v1.3.95/linux/drivers/block/rd.c	Sat Mar  9 13:31:43 1996
+++ linux/drivers/block/rd.c	Sat Apr 27 11:07:18 1996
@@ -32,6 +32,9 @@
  * 	Default ramdisk size changed to 2.88MB
  *
  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
+ *
+ * 4/25/96 : Made ramdisk size a parameter (default is now 4MB) 
+ *		- Chad Page
  */
 
 #include <linux/config.h>
@@ -60,9 +63,8 @@
 #define MAJOR_NR RAMDISK_MAJOR
 #include <linux/blk.h>
 
-/* These *should* be defined as parameters */
-#define NUM_RAMDISKS 8
-#define RD_DEFAULTSIZE	2880	/* 2.88 MB */
+/* The ramdisk size is now a parameter */
+#define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */ 
 
 #ifndef MODULE
 /* We don't have to load ramdisks or gunzip them in a module... */
@@ -92,6 +94,7 @@
 int rd_doload = 0;		/* 1 = load ramdisk, 0 = don't load */
 int rd_prompt = 1;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 int rd_image_start = 0;		/* starting block # of image */
+int rd_size = 4096;		/* Size of the ramdisks */
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned long initrd_start,initrd_end;
 int mount_initrd = 1;		/* zero if initrd should not be mounted */
@@ -272,11 +275,14 @@
 	blk_dev[MAJOR_NR].request_fn = &rd_request;
 
 	for (i = 0; i < NUM_RAMDISKS; i++) {
-		rd_length[i] = (RD_DEFAULTSIZE * 1024);
+		rd_length[i] = (rd_size * 1024);
 		rd_blocksizes[i] = 1024;
 	}
 
 	blksize_size[MAJOR_NR] = rd_blocksizes;
+
+	printk("Ramdisk driver initialized : %d ramdisks of %dK size\n",
+							NUM_RAMDISKS, rd_size);
 
 	return 0;
 }
diff -u --recursive --new-file v1.3.95/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.95/linux/drivers/char/Makefile	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/Makefile	Thu Apr 25 13:27:42 1996
@@ -20,18 +20,24 @@
 
 L_TARGET := char.a
 M_OBJS   :=
-L_OBJS   := tty_io.o n_tty.o console.o keyboard.o \
+L_OBJS   := tty_io.o n_tty.o console.o \
 	tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
-	defkeymap.o consolemap.o selection.o
- 
+	consolemap.o selection.o
+
 ifeq ($(CONFIG_SERIAL),y)
-LX_OBJS += serial.o
+  ifndef CONFIG_SUN_SERIAL
+  LX_OBJS += serial.o
+  endif
 else
   ifeq ($(CONFIG_SERIAL),m)
   MX_OBJS += serial.o
   endif
 endif
 
+ifndef CONFIG_SUN_KEYBOARD
+L_OBJS += keyboard.o defkeymap.o
+endif
+
 ifeq ($(CONFIG_DIGI),y)
 L_OBJS += pcxx.o
 endif
@@ -127,6 +133,10 @@
 # This is not modularized, so if configured then "misc.c" will be resident
 endif
 
+ifdef CONFIG_SUN_MOUSE
+M = y
+endif
+
 ifeq ($(CONFIG_WDT),y)
 M = y
 L_OBJS += wdt.o
@@ -167,7 +177,7 @@
   MX_OBJS += misc.o
   endif
 endif
-
+  
 ifeq ($(CONFIG_SCC),y)
 L_OBJS += scc.o
 else
@@ -179,7 +189,9 @@
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
 else
-L_OBJS += vga.o vesa_blank.o
+ ifndef CONFIG_SUN_CONSOLE
+ L_OBJS += vga.o vesa_blank.o
+ endif
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.95/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v1.3.95/linux/drivers/char/amigamouse.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/amigamouse.c	Fri Apr 26 12:12:25 1996
@@ -25,7 +25,7 @@
  *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
  *   renamed this file mouse.c => busmouse.c
  *
- * Modfied for use in the 1.3 kernels by Jes Sorensen.
+ * Modified for use in the 1.3 kernels by Jes Sorensen.
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v1.3.95/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v1.3.95/linux/drivers/char/lp_intern.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/lp_intern.c	Fri Apr 26 12:12:25 1996
@@ -1,6 +1,6 @@
 
 /*
- * split into mid and low-level for better support of diffent hardware
+ * split into mid and low-level for better support of different hardware
  * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
  *
  * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
diff -u --recursive --new-file v1.3.95/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v1.3.95/linux/drivers/char/lp_m68k.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/lp_m68k.c	Fri Apr 26 12:12:25 1996
@@ -29,7 +29,7 @@
  *  with a certain priority is executed, all requests with lower or same
  *  priority get locked out. executing the sti()-macro allows ANY interrupt
  *  to be served. this really causes BIG trouble!
- *  to protect an interrupt driven routine against beeing interrupted 
+ *  to protect an interrupt driven routine against being interrupted 
  *  (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
  *
  */
@@ -231,7 +231,7 @@
       }
       if (lp_error) {
 
-	/* an error has occured, maybe in lp_interrupt().
+	/* an error has occurred, maybe in lp_interrupt().
 	   figure out the type of error, exit on request or if nothing has 
 	   been printed at all. */
 	
diff -u --recursive --new-file v1.3.95/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v1.3.95/linux/drivers/char/mem.c	Mon Apr 15 12:20:17 1996
+++ linux/drivers/char/mem.c	Thu Apr 25 13:27:42 1996
@@ -53,7 +53,7 @@
 	if (count > high_memory - p)
 		count = high_memory - p;
 	read = 0;
-#if defined(__i386__)		/* we don't have page 0 mapped on x86.. */
+#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
 	while (p < PAGE_OFFSET + PAGE_SIZE && count > 0) {
 		put_user(0,buf);
 		buf++;
@@ -81,7 +81,7 @@
 	if (count > high_memory - p)
 		count = high_memory - p;
 	written = 0;
-#if defined(__i386__)		/* we don't have page 0 mapped on x86.. */
+#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
 	while (PAGE_OFFSET + p < PAGE_SIZE && count > 0) {
 		/* Hmm. Do something? */
 		buf++;
@@ -390,7 +390,7 @@
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_APM) || defined (CONFIG_RTC)
+    defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
 	misc_init();
 #endif
 #ifdef CONFIG_SOUND
diff -u --recursive --new-file v1.3.95/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v1.3.95/linux/drivers/char/misc.c	Wed Apr 24 17:00:38 1996
+++ linux/drivers/char/misc.c	Fri Apr 26 10:30:50 1996
@@ -65,6 +65,7 @@
 extern int psaux_init(void);
 extern int ms_bus_mouse_init(void);
 extern int atixl_busmouse_init(void);
+extern int sun_mouse_init(void);
 extern void watchdog_init(void);
 extern int rtc_init(void);
 
@@ -204,6 +205,15 @@
 #endif
 #ifdef CONFIG_ATIXL_BUSMOUSE
  	atixl_busmouse_init();
+#endif
+#ifdef CONFIG_AMIGAMOUSE
+	amiga_mouse_init();
+#endif
+#ifdef CONFIG_ATARIMOUSE
+	atari_mouse_init();
+#endif
+#ifdef CONFIG_SUN_MOUSE
+	sun_mouse_init();
 #endif
 #ifdef CONFIG_SOFT_WATCHDOG
 	watchdog_init();
diff -u --recursive --new-file v1.3.95/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v1.3.95/linux/drivers/char/pty.c	Wed Apr 24 17:00:38 1996
+++ linux/drivers/char/pty.c	Fri Apr 26 09:23:24 1996
@@ -216,8 +216,9 @@
 	 */
 	if (tty->driver.subtype == PTY_TYPE_MASTER)
 		return 0;
-	add_wait_queue(&pty->open_wait, &wait);
 	retval = 0;
+#if PTY_SLAVE_WAITS_ON_OPEN
+	add_wait_queue(&pty->open_wait, &wait);
 	while (1) {
 		if (current->signal & ~current->blocked) {
 			retval = -ERESTARTSYS;
@@ -226,6 +227,7 @@
 		/*
 		 * Block until the master is open...
 		 */
+		current->state = TASK_INTERRUPTIBLE;
 		if (tty->link->count &&
 		    !test_bit(TTY_OTHER_CLOSED, &tty->flags))
 			break;
@@ -233,6 +235,10 @@
 	}
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&pty->open_wait, &wait);
+#else
+	if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags))
+		retval = -EPERM;
+#endif
 	return retval;
 }
 
diff -u --recursive --new-file v1.3.95/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v1.3.95/linux/drivers/char/riscom8.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/riscom8.c	Fri Apr 26 12:12:25 1996
@@ -7,7 +7,7 @@
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
  *      programming info was obtained from various drivers for other OSes 
  *	(FreeBSD, ISC, etc), but no source code from those drivers were 
- *	directly included in this drvier.
+ *	directly included in this driver.
  *
  *
  *      This program is free software; you can redistribute it and/or modify
@@ -173,7 +173,7 @@
 	outb(val, bp->base + RC_TO_ISA(reg));
 }
 
-/* Wait for Chanel Command Register ready */
+/* Wait for Channel Command Register ready */
 extern inline void rc_wait_CCR(struct riscom_board const * bp)
 {
 	unsigned long delay;
@@ -196,7 +196,7 @@
 	
 	for (i = 0; i < RC_NIOPORT; i++)  
 		if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1))  {
-			printk("rc%d: Skipping probe at 0x%03x. I/O adress in use.\n",
+			printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n",
 			       board_No(bp), bp->base);
 			return 1;
 		}
@@ -319,7 +319,7 @@
 
 /* 
  * 
- *  Inerrupt processing routines.
+ *  Interrupt processing routines.
  * 
  */
 
@@ -328,7 +328,7 @@
 	/* 
          * I'm not quite happy with current scheme all serial
 	 * drivers use their own BH routine.
-         * It seem's this easily can be done with one BH routine
+         * It seems this easily can be done with one BH routine
 	 * serving for all serial drivers.
 	 * For now I must introduce another one - RISCOM8_BH.
 	 * Still hope this will be changed in near future.
@@ -673,7 +673,7 @@
 
 /*
  * Setting up port characteristics. 
- * Must be called with disabled interupts
+ * Must be called with disabled interrupts
  */
 static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
 {
@@ -785,7 +785,7 @@
 			/* Real raw mode. Ignore all */
 			port->mark_mask &= ~RCSR_OE;
 	}
-	/* Enable Hardware FLow Control */
+	/* Enable Hardware Flow Control */
 	if (C_CRTSCTS(tty))  {
 #ifdef RISCOM_BRAIN_DAMAGED_CTS
 		port->IER |= IER_DSR | IER_CTS;
@@ -831,12 +831,12 @@
 	/* Setting up modem option registers */
 	rc_out(bp, CD180_MCOR1, mcor1);
 	rc_out(bp, CD180_MCOR2, mcor2);
-	/* Enable CD180 trasmitter & receiver */
+	/* Enable CD180 transmitter & receiver */
 	rc_wait_CCR(bp);
 	rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
 	/* Enable interrupts */
 	rc_out(bp, CD180_IER, port->IER);
-	/* And finaly set RTS on */
+	/* And finally set RTS on */
 	rc_out(bp, CD180_MSVR, port->MSVR);
 }
 
@@ -927,7 +927,7 @@
 	port->flags &= ~ASYNC_INITIALIZED;
 	
 	if (--bp->count < 0)  {
-		printk("rc%d: rc_shutdow_port: bad board count: %d\n",
+		printk("rc%d: rc_shutdown_port: bad board count: %d\n",
 		       board_No(bp), bp->count);
 		bp->count = 0;
 	}
@@ -1812,7 +1812,7 @@
  * 
  * You can specify IO base for up to RC_NBOARD cards,
  * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there wiil be no probing at default
+ * Note that there will be no probing at default
  * addresses in this case.
  *
  */ 
@@ -1862,7 +1862,7 @@
 
 /*
  * You can setup up to 4 boards (current value of RC_NBOARD)
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as isnmod parametr.
+ * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
  *
  */
 int init_module(void) 
diff -u --recursive --new-file v1.3.95/linux/drivers/char/riscom8.h linux/drivers/char/riscom8.h
--- v1.3.95/linux/drivers/char/riscom8.h	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/riscom8.h	Fri Apr 26 12:12:25 1996
@@ -7,7 +7,7 @@
  *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
  *      programming info was obtained from various drivers for other OSes 
  *	(FreeBSD, ISC, etc), but no source code from those drivers were 
- *	directly included in this drvier.
+ *	directly included in this driver.
  *
  *
  *      This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v1.3.95/linux/drivers/char/riscom8_reg.h linux/drivers/char/riscom8_reg.h
--- v1.3.95/linux/drivers/char/riscom8_reg.h	Tue Apr 23 13:57:09 1996
+++ linux/drivers/char/riscom8_reg.h	Fri Apr 26 12:12:25 1996
@@ -109,7 +109,7 @@
 /* Channel Address Register (R/W) */
 
 #define CAR_CHAN        0x07    /* Channel Number Mask                     */
-#define CAR_A7          0x08    /* A7 Address Extention (unused)           */
+#define CAR_A7          0x08    /* A7 Address Extension (unused)           */
 
 
 /* Receive Character Status Register (R/O) */
diff -u --recursive --new-file v1.3.95/linux/drivers/char/suncons.c linux/drivers/char/suncons.c
--- v1.3.95/linux/drivers/char/suncons.c	Wed Apr 24 17:00:38 1996
+++ linux/drivers/char/suncons.c	Thu Jan  1 02:00:00 1970
@@ -1,1874 +0,0 @@
-/* suncons.c: Sun SparcStation console support.
- *
- * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *
- * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Added render_screen and faster scrolling Nov/27, miguel
- * Added console palette code for cg6 Dec/13/95, miguel
- * Added generic frame buffer support Dec/14/95, miguel
- * Added cgsix and bwtwo drivers Jan/96, miguel
- * Added 4m, and cg3 driver Feb/96, miguel
- * Fixed the cursor on color displays Feb/96, miguel.
- *
- * Cleaned up the detection code, generic 8bit depth display 
- * code, Mar/96 miguel
- * 
- * This file contains the frame buffer device drivers.
- * Each driver is kept together in case we would like to
- * split this file.
- *
- * Much of this driver is derived from the DEC TGA driver by
- * Jay Estabrook who has done a nice job with the console
- * driver abstraction btw.
- *
- * We try to make everything a power of two if possible to
- * speed up the bit blit.  Doing multiplies, divides, and
- * remainder routines end up calling software library routines
- * since not all Sparcs have the hardware to do it.
- *
- * TODO:
- * do not use minor to index into instances of the frame buffer,
- * since the numbers assigned to us are not consecutive.
- *
- * do not blank the screen when frame buffer is mapped.
- *
- * Change the detection loop to use more than one video card.
- */
-
-
-/* Define this one if you are debugging something in X, it will not disable the console output */
-/* #define DEBUGGING_X */
-/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
-
-#define GRAPHDEV_MAJOR 29
-
-#define FRAME_BUFFERS 1
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/types.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/oplib.h>
-#include <asm/sbus.h>
-#include <asm/fbio.h>
-#include <asm/io.h>
-#include <asm/pgtsun4c.h>	/* for the sun4c_nocache */
-
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
-
-#define cmapsz 8192
-
-extern void register_console(void (*proc)(const char *));
-extern void console_print(const char *);
-extern unsigned char vga_font[];
-extern int graphics_on;
-extern int serial_console;
-
-/* Based upon what the PROM tells us, we can figure out where
- * the console is currently located.  The situation can be either
- * of the following two scenarios:
- *
- * 1) Console i/o is done over the serial line, ttya or ttyb
- * 2) Console output on frame buffer (video card) and input
- *    coming from the keyboard/mouse which each use a zilog8530
- *    serial channel a piece.
- */
-
-/* The following variables describe a Sparc console. */
-
-/* From the PROM */
-static char con_name[40];
-
-/* Screen dimensions and color depth. */
-static int con_depth, con_width, con_height, con_type;
-
-static int con_linebytes;
-
-/* Base address of first line. */
-static unsigned char *con_fb_base;
-
-/* Screen parameters: we compute those at startup to make the code faster */
-static int chars_per_line;	/* number of bytes per line */
-static int ints_per_line;	/* number of ints per  line */
-static int skip_bytes;		/* number of bytes we skip for the y margin */
-static int x_margin, y_margin;	/* the x and y margins */
-static int bytes_per_row;	/* bytes used by one screen line (of 16 scan lines)  */
-
-/* Functions used by the SPARC dependent console code
- * to perform the restore_palette function.
- */
-static void (*restore_palette)(void);
-void set_palette (void);
-
-
- /* Our screen looks like at 1152 X 900:
- *
- *  0,0
- *      ------------------------------------------------------------------
- *      |                          ^^^^^^^^^^^                           |
- *      |                          18 y-pixels                           |
- *      |                          ^^^^^^^^^^^                           |
- *   13 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
- *    ....
- *                         54 chars from top to bottom
- *    ....
- *  888 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
- *      |                          ^^^^^^^^^^^                           |
- *      |                          18 y-pixels                           |
- *      |                          ^^^^^^^^^^^                           |
- *      ------------------------------------------------------------------
- */
-/* First for MONO displays. */
-#define SCREEN_WIDTH     1152     /* Screen width in pixels  */
-#define SCREEN_HEIGHT    900      /* Screen height in pixels */
-#define CHARS_PER_LINE   144      /* Make this empirical for speed */
-#define NICE_Y_MARGIN    18       /* We skip 18 y-pixels at top/bottom */
-#define NICE_X_MARGIN    8        /* We skip 64 x-pixels at left/right */
-#define FBUF_TOP_SKIP    2592     /* Empirical, (CHARS_PER_LINE * NICE_Y_MARGIN) */
-#define CHAR_HEIGHT      16
-#define ONE_ROW          2304     /* CHARS_PER_LINE * CHAR_HEIGHT */
-
-/* Now we have this, to compute the base frame buffer position
- * for a new character to be rendered. 1 and 8 bit depth.
- */
-#define FBUF_OFFSET(cindex) \
-        (((FBUF_TOP_SKIP) + (((cindex)>>7) * ONE_ROW)) + \
-	 ((NICE_X_MARGIN) + (((cindex)&127))))
-
-
-#define COLOR_FBUF_OFFSET(cindex) \
-        (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
-	 ((x_margin) + (((cindex)&127) << 3)))
-
-void
-__set_origin(unsigned short offset)
-{
-	/*
-	 * should not be called, but if so, do nothing...
-	 */
-}
-
-/* For the cursor, we just invert the 8x16 block at the cursor
- * location.  Easy enough...
- *
- * Hide the cursor from view, during blanking, usually...
- */
-static int cursor_pos = -1;
-void
-hide_cursor(void)
-{
-	unsigned long flags;
-	int j;
-
-	save_flags(flags); cli();
-
-	if(cursor_pos == -1) {
-		restore_flags (flags);
-		return;
-	}
-	/* We just zero out the area for now.  Certain graphics
-	 * cards like the cg6 have a hardware cursor that we could
-	 * use, but this is an optimization for some time later.
-	 */
-	switch (con_depth){
-	case 1: {
-		unsigned char *dst;
-		dst = (unsigned char *)((unsigned long)con_fb_base +
-					FBUF_OFFSET(cursor_pos));
-		for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
-			*dst = ~(0);
-		break;
-	}
-	case 8: {
-		unsigned long *dst;
-		const    int ipl = ints_per_line;
-		
-		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
-		for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
-			*dst = ~(0UL);
-			*(dst + 1) = ~(0UL);
-		}
-		break;
-	}
-	default:
-		break;
-	}
-	restore_flags(flags);
-}
-
-/* The idea is the following:
- * we only use the colors in the range 0..15, and we only
- * setup the palette on that range, so we better keep the
- * pixel inversion using those colors, that's why we have
- * those constants below.
- */
-inline static void
-cursor_reverse (long *dst, int height, const int ints_on_line)
-{
-    int j;
-
-    for (j = 0; j < height; j++){
-	*dst     = ~(*dst)     & 0x0f0f0f0f;
-	*(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
-	dst += ints_on_line;
-    }
-}
-
-void
-set_cursor(int currcons)
-{
-	int j, idx, oldpos;
-	unsigned long flags;
-
-	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
-		return;
-
-	if (__real_origin != __origin)
-		__set_origin(__real_origin);
-
-	save_flags(flags); cli();
-
-	idx = (pos - video_mem_base) >> 1;
-	oldpos = cursor_pos;
-	cursor_pos = idx;
-	if (!deccm) {
-		hide_cursor ();
-		restore_flags (flags);
-		return;
-	}
-	switch (con_depth){
-	case 1: {
-		unsigned char *dst, *opos;
-		
-		dst = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(idx));
-		opos = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(oldpos));
-		if(oldpos != -1) {
-			/* Restore what was at the old position */
-			for(j=0; j < CHAR_HEIGHT; j++, opos += CHARS_PER_LINE) {
-				*opos = ~*opos;
-			}
-		}
-		for(j=0; j < 16; j++, dst+=CHARS_PER_LINE) {
-			*dst = ~*dst;
-		}
-		break;
-	}
-	case 8: {
-		unsigned long *dst, *opos;
-		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
-		opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
-			
-		if(oldpos != -1) 
-			cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
-		cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
-		break;
-	}
-	default:
-	}
-	restore_flags(flags);
-}
-
-/*
- * Render the current screen
- * Only used at startup to avoid the caching that is being done in selection.h
- */
-static void
-render_screen(void)
-{
-    int count;
-    unsigned short *contents;
-
-    count = video_num_columns * video_num_lines;
-    contents = (unsigned short *) video_mem_base;
-    
-    for (;count--; contents++)
-	sun_blitc (*contents, (unsigned long) contents);
-}
-
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
-{
-        can_do_color = (con_type != FBTYPE_SUN2BW);
-
-        video_type = VIDEO_TYPE_SUN;
-        *display_desc = "SUN";
-
-	if (!serial_console) {
-		/* If we fall back to PROM than our output have to remain readable. */
-		prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
-
-		/*
-		 * fake the screen memory with some CPU memory
-		 */
-		video_mem_base = kmem_start;
-		kmem_start += video_screen_size;
-		video_mem_term = kmem_start;
-
-		render_screen();
-	}
-	return kmem_start;
-}
-
-/*
- * NOTE: get_scrmem() and set_scrmem() are here only because
- * the VGA version of set_scrmem() has some direct VGA references.
- */
-void
-get_scrmem(int currcons)
-{
-	memcpyw((unsigned short *)vc_scrbuf[currcons],
-		(unsigned short *)origin, video_screen_size);
-	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
-	scr_end = video_mem_end = video_mem_start + video_screen_size;
-	pos = origin + y*video_size_row + (x<<1);
-}
-
-void
-set_scrmem(int currcons, long offset)
-{
-	if (video_mem_term - video_mem_base < offset + video_screen_size)
-		offset = 0;
-	memcpyw((unsigned short *)(video_mem_base + offset),
-		(unsigned short *) origin, video_screen_size);
-	video_mem_start = video_mem_base;
-	video_mem_end = video_mem_term;
-	origin = video_mem_base + offset;
-	scr_end = origin + video_screen_size;
-	pos = origin + y*video_size_row + (x<<1);
-}
-
-/*
- * PIO_FONT support.
- */
-int
-set_get_font(char * arg, int set, int ch512)
-{
-	int error, i, line;
-
-	if (!arg)
-		return -EINVAL;
-	error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
-			     ch512 ? 2* cmapsz : cmapsz);
-	if (error)
-		return error;
-
-	/* download the current font */
-	if (!set){
-		memset (arg, 0, cmapsz);
-		for (i = 0; i < 256; i++)
-		    for (line = 0; line < CHAR_HEIGHT; line++)
-			put_user (vga_font [i], arg+(i*32+line));
-		return 0;
-	}
-	
-        /* set the font */
-	for (i = 0; i < 256; i++)
-		for (line = 0; line < CHAR_HEIGHT; line++){
-			vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
-			if (con_depth == 1)
-				vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
-		}
-	return 0;
-}
-
-/*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- *
- * for now, we only support the built-in font...
- */
-int
-con_adjust_height(unsigned long fontheight)
-{
-	return -EINVAL;
-}
-
-int
-set_get_cmap(unsigned char * arg, int set)
-{
-	int i;
-
-	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
-	if (i)
-		return i;
-
-	for (i=0; i<16; i++) {
-		if (set) {
-			default_red[i] = get_user(arg++) ;
-			default_grn[i] = get_user(arg++) ;
-			default_blu[i] = get_user(arg++) ;
-		} else {
-			put_user (default_red[i], arg++) ;
-			put_user (default_grn[i], arg++) ;
-			put_user (default_blu[i], arg++) ;
-		}
-	}
-	if (set) {
-		for (i=0; i<MAX_NR_CONSOLES; i++)
-			if (vc_cons_allocated(i)) {
-				int j, k ;
-				for (j=k=0; j<16; j++) {
-					vc_cons[i].d->vc_palette[k++] = default_red[j];
-					vc_cons[i].d->vc_palette[k++] = default_grn[j];
-					vc_cons[i].d->vc_palette[k++] = default_blu[j];
-				}
-			}
-		set_palette();
-	}
-
-	return 0;
-}
-
-
-void
-sun_clear_screen(void)
-{
-	memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
-		(con_depth * con_height * con_width) / 8);
-	/* also clear out the "shadow" screen memory */
-	memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
-}
-
-/*
- * dummy routines for the VESA blanking code, which is VGA only,
- * so we don't have to carry that stuff around for the Sparc...
- */
-void vesa_blank(void)
-{
-}
-void vesa_unblank(void)
-{
-}
-void set_vesa_blanking(const unsigned long arg)
-{
-}
-
-void vesa_powerdown(void)
-{
-}
-
-#undef color
-/* cg6 cursor status, kernel tracked copy */
-struct cg6_cursor {
-        short   enable;	        /* cursor is enabled */
-        struct  fbcurpos cpos;	/* position */
-        struct  fbcurpos chot;	/* hot-spot */
-        struct  fbcurpos size;	/* size of mask & image fields */
-        int     bits[2][32];	/* space for mask & image bits */
-	char    color [6];	/* cursor colors */
-};
-
-struct cg6_info {
-	struct bt_regs *bt;	/* color control */
-	void *fbc;
-	struct cg6_fhc *fhc;
-	struct cg6_tec *tec;
-	struct cg6_thc *thc;
-	struct cg6_cursor cursor; /* cursor control */
-	void *dhc;
-};
-
-struct bwtwo_info {
-        struct bwtwo_regs *regs;
-};
-
-struct cg3_info {
-	struct bt_regs *bt;	/* brooktree (color) registers */
-};
-
-/* Array holding the information for the frame buffers */
-typedef struct {
-	union {
-		struct bwtwo_info bwtwo;
-		struct cg3_info   cg3;
-		struct cg6_info   cg6;
-	} info;		        /* per frame information */
-	int    space;           /* I/O space this card resides in */
-	int    blanked;		/* true if video blanked */
-	int    open;		/* is this fb open? */
-	int    mmaped;		/* has this fb been mmapped? */
-	int    vtconsole;	/* virtual console where it is opened */
-	long   base;		/* frame buffer base    */
-	struct fbtype type;	/* frame buffer type    */
-	int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
-	void   (*loadcmap)(void *this, int index, int count);
-	void   (*blank)(void *this);
-	void   (*unblank)(void *this);
-	int    (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
-} fbinfo_t;
-
-static fbinfo_t fbinfo [FRAME_BUFFERS];
-
-/* We need to keep a copy of the color map to answer ioctl requests */
-static union {
-	unsigned char   map[256][3];    /* reasonable way to access */
-        unsigned int    raw[256*3/4];   /* hardware wants it like this */
-} color_map;
-
-#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
-
-static int
-fb_open (struct inode * inode, struct file * file)
-{
-	int minor = MINOR (inode->i_rdev);
-
-	if (minor >= FRAME_BUFFERS)
-		return -EBADF;
-	if (fbinfo [minor].open)
-		return -EBUSY;
-	fbinfo [minor].open = 1;
-	fbinfo [minor].mmaped = 0;
-	return 0;
-}
-
-static int
-fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int minor = MINOR (inode->i_rdev);
-	fbinfo_t *fb;
-	struct fbcmap *cmap;
-	int i;
-	
-	if (minor >= FRAME_BUFFERS)
-		return -EBADF;
-	fb = &fbinfo [minor];
-	
-	switch (cmd){
-	case FBIOGTYPE:		/* return frame buffer type */
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
-		if (i) return i;
-		*(struct fbtype *)arg = (fb->type);
-		break;
-	case FBIOGATTR:{
-		struct fbgattr *fba = (struct fbgattr *) arg;
-		
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
-		if (i) return i;
-		fba->real_type = fb->type.fb_type;
-		fba->owner = 0;
-		fba->fbtype = fb->type;
-		fba->sattr.flags = 0;
-		fba->sattr.emu_type = fb->type.fb_type;
-		fba->sattr.dev_specific [0] = -1;
-		fba->emu_types [0] = fb->type.fb_type;
-		fba->emu_types [1] = -1;
-		break;
-	}
-	case FBIOSVIDEO:
-		i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
-		if (i) return i;
-		
-		if (*(int *)arg){
-			if (!fb->blanked || !fb->unblank)
-				break;
-			(*fb->unblank)(fb);
-			fb->blanked = 0;
-		} else {
-			if (fb->blanked || !fb->blank)
-				break;
-			(*fb->blank)(fb);
-			fb->blanked = 1;
-		}
-		break;
-	case FBIOGVIDEO:
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
-		if (i) return i;
-		*(int *) arg = fb->blanked;
-		break;
-	case FBIOPUTCMAP: {	/* load color map entries */
-		char *rp, *gp, *bp;
-		int end, count;;
-		
-		if (!fb->loadcmap)
-			return -EINVAL;
-		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
-		if (i) return i;
-		cmap = (struct fbcmap *) arg;
-		count = cmap->count;
-		if ((cmap->index < 0) || (cmap->index > 255))
-			return -EINVAL;
-		if (cmap->index + count > 256)
-			count = 256 - cmap->index;
-		i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
-		if (i) return i;
-
-		end = cmap->index + count;
-		for (i = cmap->index; i < end; i++){
-			color_map.map [i][0] = *rp++;
-			color_map.map [i][1] = *gp++;
-			color_map.map [i][2] = *bp++;
-		}
-		(*fb->loadcmap)(fb, cmap->index, count);
-                break;			
-	}
-
-	default:
-		if (fb->ioctl){
-			i = fb->ioctl (inode, file, cmd, arg, fb);
-			if (i == -EINVAL)
-				printk ("[[FBIO: %8.8x]]\n", cmd);
-			return i;
-		}
-		printk ("[[FBIO: %8.8x]]\n", cmd);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void
-fb_close (struct inode * inode, struct file *filp)
-{
-	int minor = MINOR(inode->i_rdev);
-	struct fbcursor cursor;
-	
-	if (minor >= FRAME_BUFFERS)
-		return;
-	if (fbinfo [minor].open)
-		fbinfo [minor].open = 0;
-	vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
-
-	/* Leaving graphics mode, turn off the cursor */
-	graphics_on = 0;
-	if (fbinfo [minor].mmaped)
-		sun_clear_screen ();
-	cursor.set    = FB_CUR_SETCUR;
-	cursor.enable = 0;
-	fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
-	set_palette ();
-	render_screen ();
-	return;
-}
-
-static int
-fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
-{
-	int minor = MINOR (inode->i_rdev);
-	fbinfo_t *fb;
-
-	if (minor >= FRAME_BUFFERS)
-		return -ENXIO;
-	/* FIXME: the fg_console below should actually be the
-	 * console on which the invoking process is running
-	 */
-	if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
-		return -ENXIO;
-	fbinfo [minor].vtconsole = fg_console;
-	fb = &fbinfo [minor];
-
-	if (fb->mmap){
-		int v;
-		
-		v = (*fb->mmap)(inode, file, vma, fb->base, fb);
-		if (v) return v;
-		fbinfo [minor].mmaped = 1;
-		vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
-		graphics_on = 1;
-		return 0;
-	} else
-		return -ENXIO;
-}
-
-static struct file_operations graphdev_fops =
-{
-	NULL,			/* lseek */
-	NULL,			/* read */
-	NULL,			/* write */
-	NULL,			/* readdir */
-	NULL,			/* select */
-	fb_ioctl,
-	fb_mmap,
-	fb_open,		/* open */
-	fb_close,		/* close */
-};
-
-/* Call the frame buffer routine for setting the palette */
-void
-set_palette (void)
-{
-	if (console_blanked || vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
-		return;
-
-	if (fbinfo [0].loadcmap){
-		int i, j;
-	
-		/* First keep color_map with the palette colors */
-		for (i = 0; i < 16; i++){
-			j = color_table [i];
-			color_map.map [i][0] = default_red [j];
-			color_map.map [i][1] = default_grn [j];
-			color_map.map [i][2] = default_blu [j];
-		}
-		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
-	}
-}
-
-/* Called when returning to prom */
-void
-console_restore_palette (void)
-{
-        if (restore_palette)
-	        (*restore_palette) ();
-}
-
-/* This routine should be moved to srmmu.c */
-static __inline__ unsigned int
-srmmu_get_pte (unsigned long addr)
-{
-	register unsigned long entry;
-
-	__asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
-			     "=r" (entry):
-			     "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
-	return entry;
-}
-
-unsigned int
-get_phys (unsigned int addr)
-{
-	switch (sparc_cpu_model){
-	case sun4c:
-		return sun4c_get_pte (addr) << PAGE_SHIFT;
-	case sun4m:
-		return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
-	default:
-		panic ("get_phys called for unsupported cpu model\n");
-		return 0;
-	}
-}
-
-/* CG6 support code */
-
-/* Offset of interesting structures in the OBIO space */
-/*
- * Brooktree is the video dac and is funny to program on the cg6.
- * (it's even funnier on the cg3)
- * The FBC could be the the frame buffer control
- * The FHC could be the frame buffer hardware control.
- */
-#define CG6_ROM_OFFSET       0x0
-#define CG6_BROOKTREE_OFFSET 0x200000
-#define CG6_DHC_OFFSET       0x240000
-#define CG6_ALT_OFFSET       0x280000
-#define CG6_FHC_OFFSET       0x300000
-#define CG6_THC_OFFSET       0x301000
-#define CG6_FBC_OFFSET       0x700000
-#define CG6_TEC_OFFSET       0x701000
-#define CG6_RAM_OFFSET       0x800000
-
-struct bt_regs {
-	unsigned int  addr;	/* address register */
-	unsigned int  color_map; /* color map */
-	unsigned int  control;	/* control register */
-	unsigned int  cursor;	/* cursor map register */
-};
-
-/* The contents are unknown */
-struct cg6_tec {
-	int tec_matrix;
-	int tec_clip;
-	int tec_vdc;
-};
-
-struct cg6_thc {
-        unsigned int thc_xxx0[512];  /* ??? */
-        unsigned int thc_hsync1;     /* hsync timing */
-        unsigned int thc_hsync2;
-        unsigned int thc_hsync3;
-        unsigned int thc_vsync1;     /* vsync timing */
-        unsigned int thc_vsync2;
-        unsigned int thc_refresh;
-        unsigned int thc_misc;
-        unsigned int thc_xxx1[56];
-        unsigned int thc_cursxy;             /* cursor x,y position (16 bits each) */
-        unsigned int thc_cursmask[32];       /* cursor mask bits */
-        unsigned int thc_cursbits[32];       /* what to show where mask enabled */
-};
-
-static void
-cg6_restore_palette (void)
-{
-	volatile struct bt_regs *bt;
-
-	bt = fbinfo [0].info.cg6.bt;
-	bt->addr = 0;
-	bt->color_map = 0xffffffff;
-	bt->color_map = 0xffffffff;
-	bt->color_map = 0xffffffff;
-}
-
-/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
-/* So, we just mmap the things that are being asked for */
-static int
-cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-	unsigned int size, page, r, map_size;
-	unsigned int map_offset = 0;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	
-	size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS;
-	
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ){
-		switch (vma->vm_offset+page){
-		case CG6_TEC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.tec);
-			break;
-		case CG6_FBC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fbc);
-			break;
-		case CG6_FHC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fhc);
-			break;
-		case CG6_THC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.thc);
-			break;
-		case CG6_BTREGS:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.bt);
-			break;
-			
-		case CG6_DHC:
-			map_size = PAGE_SIZE * 40;
-			map_offset = get_phys ((uint)fb->info.cg6.dhc);
-			break;
-			
-		case CG6_ROM:
-			map_size = 0;
-			break;
-
-		case CG6_RAM:
-			map_size = size-page;
-			map_offset = get_phys ((uint) con_fb_base);
-			if (map_size < fb->type.fb_size)
-				map_size = fb->type.fb_size;
-			break;
-		default:
-			map_size = 0;
-			break;
-		}
-		if (!map_size){
-			page += PAGE_SIZE;
-			continue;
-		}
-		r = io_remap_page_range (vma->vm_start+page,
-					 map_offset,
-					 map_size, vma->vm_page_prot,
-					 fb->space);
-		if (r) return -EAGAIN;
-		page += map_size;
-	}
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
-}
-
-#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
-#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
-
-static void
-cg6_loadcmap (void *fbinfo, int index, int count)
-{
-	fbinfo_t *fb = (fbinfo_t *) fbinfo;
-	struct bt_regs *bt = fb->info.cg6.bt;
-	int i;
-	
-	bt->addr = index << 24;
-	for (i = index; count--; i++){
-		bt->color_map = color_map.map [i][0] << 24;
-		bt->color_map = color_map.map [i][1] << 24;
-		bt->color_map = color_map.map [i][2] << 24;
-	}
-}
-
-/* Load cursor information */
-static void
-cg6_setcursor (struct cg6_info *info)
-{
-	unsigned int v;
-	struct cg6_cursor *c = &info->cursor;
-	
-	if (c->enable){
-		v = ((c->cpos.fbx - c->chot.fbx) << 16)
-		   |((c->cpos.fby - c->chot.fby) & 0xffff);
-	} else {
-		/* Magic constant to turn off the cursor */
-		v = ((65536-32) << 16) | (65536-32);
-	}
-	info->thc->thc_cursxy = v;
-}
-
-#undef pos
-static int
-cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
-{
-	int op = cursor->set;
-	volatile struct cg6_thc *thc = fb->info.cg6.thc;
-	struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
-	int i, bytes = 0;
-	
-	if (op & FB_CUR_SETSHAPE){
-		if ((unsigned int) cursor->size.fbx > 32)
-			return -EINVAL;
-		if ((unsigned int) cursor->size.fby > 32)
-			return -EINVAL;
-		bytes = (cursor->size.fby * 32)/8;
-		i = verify_area (VERIFY_READ, cursor->image, bytes);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, cursor->mask, bytes);
-		if (i) return i;
-	}
-	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
-		if (op & FB_CUR_SETCUR)
-			cursor_info->enable = cursor->enable;
-		if (op & FB_CUR_SETPOS)
-			cursor_info->cpos = cursor->pos;
-		if (op & FB_CUR_SETHOT)
-			cursor_info->chot = cursor->hot;
-		cg6_setcursor (&fb->info.cg6);
-	}
-	if (op & FB_CUR_SETSHAPE){
-		unsigned int u;
-		
-		cursor_info->size = cursor->size;
-		memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
-		memcpy (cursor_info->bits [0], cursor->mask, bytes);
-		memcpy (cursor_info->bits [1], cursor->image, bytes);
-		u = ~0;
-		if (cursor_info->size.fbx < 32)
-			u = ~(u  >> cursor_info->size.fbx);
-		for (i = 0; i < 32; i++){
-			int m = cursor_info->bits [0][i] & u;
-			thc->thc_cursmask [i] = m;
-			thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
-		}
-	}
-	return 0;
-}
-
-/* Handle cg6-specific ioctls */
-static int
-cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
-{
-	int i;
-
-	switch (cmd){
-	case FBIOGCURMAX:
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
-		if (i) return i;
-		((struct fbcurpos *) arg)->fbx = 32;
-		((struct fbcurpos *) arg)->fby = 32;
-		break;
-
-	case FBIOSVIDEO:
-		/* vesa_blank and vesa_unblank could do the job on fb [0] */
-		break;
-
-	case FBIOSCURSOR:
-		return cg6_scursor ((struct fbcursor *) arg, fb);
-
-	case FBIOSCURPOS:
-		/*
-		i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
-		if (i) return i;
-		*/
-		fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
-		cg6_setcursor (&fb->info.cg6);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void
-cg6_setup (int slot, unsigned int cg6, int cg6_io)
-{
-	struct cg6_info *cg6info;
-
-	printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
-	
-	/* Fill in parameters we left out */
-	fbinfo [slot].type.fb_cmsize = 256;
-	fbinfo [slot].mmap = cg6_mmap;
-	fbinfo [slot].loadcmap = cg6_loadcmap;
-	fbinfo [slot].ioctl = (void *) cg6_ioctl;
-	fbinfo [slot].blank = 0;
-	fbinfo [slot].unblank = 0;
-	
-	cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
-
-	/* Map the hardware registers */
-	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
-		 sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
-	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
-		 sizeof (int), "cgsix_fhc", cg6_io, 0);
-	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
-		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
-	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
-		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
-	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
-		 0x40000, "cgsix_dhc", cg6_io, 0);
-	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
-		 0x1000, "cgsix_fbc", cg6_io, 0);
-	if (!con_fb_base){
-		con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
-                    fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
-	}
-	if (!slot)
-		restore_palette = cg6_restore_palette;
-}
-
-/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
-#define CG3_REGS 0x400000
-#define CG3_RAM  0x800000
-#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
-#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
-
-/* The cg3 palette is loaded with 4 color values at each time  */
-/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
-static void
-cg3_loadcmap (void *fbinfo, int index, int count)
-{
-	fbinfo_t *fb = (fbinfo_t *) fbinfo;
-	struct bt_regs *bt = fb->info.cg3.bt;
-	int *i, steps;
-
-	i = &color_map.raw [D4M3(index)];
-	steps = D4M3(index+count-1) - D4M3(index)+3;
-	bt->addr = D4M4(index);
-	while (steps--)
-		bt->color_map = *i++;
-}
-
-/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
-/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation          */
-static int
-cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-	unsigned int size, page, r, map_size;
-	unsigned int map_offset = 0;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	
-	size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
-	
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ){
-		switch (vma->vm_offset+page){
-		case CG3_MMAP_OFFSET:
-			map_size = size-page;
-			map_offset = get_phys ((uint) con_fb_base);
-			if (map_size > fb->type.fb_size)
-				map_size = fb->type.fb_size;
-			break;
-		default:
-			map_size = 0;
-			break;
-		}
-		if (!map_size){
-			page += PAGE_SIZE;
-			continue;
-		}
-		r = io_remap_page_range (vma->vm_start+page,
-					 map_offset,
-					 map_size, vma->vm_page_prot,
-					 fb->space);
-		if (r) return -EAGAIN;
-		page += map_size;
-	}
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
-}
-
-static void
-cg3_setup (int slot, unsigned int cg3, int cg3_io)
-{
-	struct cg3_info *cg3info;
-
-	printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
-	
-	/* Fill in parameters we left out */
-	fbinfo [slot].type.fb_cmsize = 256;
-	fbinfo [slot].mmap = cg3_mmap;
-	fbinfo [slot].loadcmap = cg3_loadcmap;
-	fbinfo [slot].ioctl = 0; /* no special ioctls */
-
-	cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
-
-	/* Map the card registers */
-	cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
-		 sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
-	
-	if (!con_fb_base){
-		con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
-                    fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
-	}
-}
-
-/* OBio addresses for the bwtwo registers */
-#define BWTWO_REGISTER_OFFSET 0x400000
-
-struct bwtwo_regs {
-	char          unknown [16];
-#define BWTWO_ENABLE_VIDEO 0x40
-	unsigned char control;
-	char          unknown2 [15];
-};
-
-static int
-bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-	unsigned int size, map_offset, r;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	int map_size;
-	
-	map_size = size = vma->vm_end - vma->vm_start;
-	
-	if (vma->vm_offset & ~PAGE_MASK)
-		return -ENXIO;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS;
-	printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
-		(unsigned int) base,
-		(unsigned int) vma->vm_start, size,
-		(unsigned int) vma->vm_offset);
-
-	/* This routine should also map the register if asked for, but we don't do that yet */
-	map_offset = get_phys ((uint) con_fb_base);
-	r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
-				 fb->space);
-	if (r) return -EAGAIN;
-	vma->vm_inode = inode;
-	inode->i_count++;
-	return 0;
-}
-
-static void
-bwtwo_blank (void *xx)
-{
-	fbinfo_t *fb = (fbinfo_t *) xx;
-
-	fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_unblank (void *xx)
-{
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
-{
-	printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
-	fbinfo [slot].type.fb_cmsize = 2;
-	fbinfo [slot].mmap = bwtwo_mmap;
-	fbinfo [slot].loadcmap = 0;
-	fbinfo [slot].ioctl = 0;
-	fbinfo [slot].blank = bwtwo_blank;
-	fbinfo [slot].unblank = bwtwo_unblank;
-	fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
-		0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
-}
-
-static char *known_cards [] = {
-	"cgsix", "cgthree", "bwtwo", "SUNW,tcx", 0
-};
-
-static int
-known_card (char *name)
-{
-	int i;
-
-	for (i = 0; known_cards [i]; i++)
-		if (strcmp (name, known_cards [i]) == 0)
-			return 1;
-	return 0;
-}
-
-static struct {
-	int depth;
-	int resx, resy;
-	int x_margin, y_margin;
-} scr_def [] = {
-	{ 1, 1152, 900,  8,  18 },
-	{ 8, 1152, 900,  64, 18 },
-	{ 8, 1280, 1024, 96, 80 },
-	{ 8, 1024, 768,  0,  0 },
-	{ 0 },
-};
-
-static int
-sparc_console_probe(void)
-{
-	int propl, con_node, i;
-	struct linux_sbus_device *sbdp;
-	unsigned int fbbase = 0xb001b001;
-	int fbiospace = 0;
-
-	/* XXX The detection code needs to support multiple video cards in one system */
-	con_node = 0;
-	switch(prom_vers) {
-	case PROM_V0:
-		/* V0 proms are at sun4c only. Can skip many checks. */
-		con_type = FBTYPE_NOTYPE;
-		if(SBus_chain == 0) {
-			prom_printf("SBUS chain is NULL, bailing out...\n");
-			prom_halt();
-		}
-		for_each_sbusdev(sbdp, SBus_chain) {
-			con_node = sbdp->prom_node;
-
-			/* If no "address" than it is not the PROM console. */
-			if(sbdp->num_vaddrs) {
-				if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
-					con_type = FBTYPE_SUNFAST_COLOR;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
-					break;
-				} else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
-					con_type = FBTYPE_SUN3COLOR;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
-					break;
-				} else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
-					con_type = FBTYPE_SUN2BW;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
-					break;
-				}
-			}
-		}
-		if(con_type == FBTYPE_NOTYPE) return -1;
-		con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
-		strncpy(con_name, sbdp->prom_name, sizeof (con_name));
-		break;
-	case PROM_V2:
-	case PROM_V3:
-	case PROM_P1275:
-		for_each_sbusdev(sbdp, SBus_chain) {
-			if (known_card (sbdp->prom_name))
-				break;
-		}
-		if (!sbdp){
-			prom_printf ("Could not find a know video card on this machine\n");
-			prom_halt ();
-		}
-		prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
-		fbbase = (long) sbdp->reg_addrs [0].phys_addr;
-		fbiospace = sbdp->reg_addrs[0].which_io;
-		con_node = (*romvec->pv_v2devops.v2_inst2pkg)
-			(*romvec->pv_v2bootargs.fd_stdout);
-		/*
-		 * Determine the type of hardware accelerator.
-		 */
-		propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
-		if (propl < 0 || propl >= sizeof (con_name)) {
-			/* Early cg3s had no "emulation". */
-			propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
-			if (propl < 0) {
-				prom_printf("console: no device name!!\n");
-				return -1;
-			}
-		}
-		if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
-			con_type = FBTYPE_SUNFAST_COLOR;
-		} else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
-			con_type = FBTYPE_SUN3COLOR;
-		} else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
-			con_type = FBTYPE_MDICOLOR;
-		} else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
-			con_type = FBTYPE_SUN2BW;
-		} else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
-			con_type = FBTYPE_SUN3COLOR;
-		} else {
-			prom_printf("console: \"%s\" is unsupported\n", con_name);
-			return -1;
-		}
-		propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
-		if (propl != 4) {
-		    con_fb_base = 0;
-		}
-		break;
-	default:
-		return -1;
-	};
-
-	/* Get the device geometry */
-	con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
-	con_width = prom_getintdefault(con_node, "width", 1152);
-	con_height = prom_getintdefault(con_node, "height", 900);
-
-	/* Currently we just support 1-bit and 8-bit depth displays */
-	if (con_type == FBTYPE_SUN2BW) {
-		con_depth = 1;
-	} else {
-		con_depth = 8;
-	}
-	for (i = 0; scr_def [i].depth; i++){
-		if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
-			continue;
-		if (scr_def [i].depth != con_depth)
-		        continue;
-		x_margin = scr_def [i].x_margin;
-		y_margin = scr_def [i].y_margin;
-		chars_per_line = (con_width * con_depth) / 8;
-		skip_bytes = chars_per_line * y_margin;
-		ints_per_line = chars_per_line / 4;
-		bytes_per_row = CHAR_HEIGHT * chars_per_line;
-		break;
-	}
-	if (!scr_def [i].depth){
-		x_margin = y_margin = 0;
-		prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
-		prom_halt ();
-	}
-	/* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
-	if ((con_linebytes*8) / con_depth != con_width) {
-		prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
-			con_linebytes, con_width, con_depth);
-		return -1;
-	}
-
-	/* Negate the font table on 1 bit depth cards so we have white on black */
-	if (con_depth == 1)
-		for(i=0; i<(16 * 256); i++)
-			vga_font[i] = ~vga_font[i];
-
-	/* Fill in common fb information */
-	fbinfo [0].type.fb_type   = con_type;
-	fbinfo [0].type.fb_height = con_height;
-	fbinfo [0].type.fb_width  = con_width;
-	fbinfo [0].type.fb_depth  = con_depth;
-	fbinfo [0].type.fb_size   = PAGE_ALIGN((con_linebytes) * (con_height));
-	fbinfo [0].space = fbiospace;
-	fbinfo [0].blanked = 0;
-
-	/* Should be filled in for supported video cards */
-	fbinfo [0].mmap = 0; 
-	fbinfo [0].loadcmap = 0;
-	fbinfo [0].ioctl = 0;
-	fbinfo [0].blank = 0;
-	fbinfo [0].unblank = 0;
-
-	if (fbbase == 0xb001b001){
-		printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
-	}
-
-	/* Per card setup */
-	switch (con_type){
-	case FBTYPE_SUN3COLOR:
-		cg3_setup (0, fbbase, fbiospace);
-		break;
-	case FBTYPE_SUNFAST_COLOR:
-		cg6_setup (0, fbbase, fbiospace);
-		break;
-	case FBTYPE_SUN2BW:
-		bwtwo_setup (0, fbbase, fbiospace);
-		break;
-	default:
-		break;
-	}
-	if (!con_fb_base){
-		prom_printf ("PROM does not have an 'address' property for this\n"
-			     "frame buffer and the Linux drivers do not know how\n"
-			     "to map the video of this device\n");
-		prom_halt ();
-	}
-	fbinfo [0].base = (long) con_fb_base;
-	
-	/* Register the frame buffer device */
-	if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
-		printk ("Could not register graphics device\n");
-		return -EIO;
-	}
-	return 0; /* success */
-}
-
-/* video init code, called from within the SBUS bus scanner at
- * boot time.
- */
-void
-sun_console_init(void)
-{
-	if(serial_console)
-		return;
-
-	if(sparc_console_probe()) {
-		prom_printf("Could not probe console, bailing out...\n");
-		prom_halt();
-	}
-	sun_clear_screen();
-}
-
-/*
- * sun_blitc
- *
- * Displays an ASCII character at a specified character cell
- *  position.
- *
- * Called from scr_writew() when the destination is
- *  the "shadow" screen
- */
-static unsigned int
-fontmask_bits[16] = {
-    0x00000000,
-    0x000000ff,
-    0x0000ff00,
-    0x0000ffff,
-    0x00ff0000,
-    0x00ff00ff,
-    0x00ffff00,
-    0x00ffffff,
-    0xff000000,
-    0xff0000ff,
-    0xff00ff00,
-    0xff00ffff,
-    0xffff0000,
-    0xffff00ff,
-    0xffffff00,
-    0xffffffff
-};
-
-int
-sun_blitc(unsigned int charattr, unsigned long addr)
-{
-	int j, idx;
-	unsigned char *font_row;
-
-#ifndef DEBUGGING_X
-	if (graphics_on)
-		return 0;
-#endif
-	idx = (addr - video_mem_base) >> 1;
-
-	/* Invalidate the cursor position if necessary. */
-	if(idx == cursor_pos)
-		cursor_pos = -1;
-	font_row = &vga_font[(charattr & 0xff) << 4];
-
-	switch (con_depth){
-	case 1: {
-		register unsigned char *dst;
-		
-		dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
-		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
-			*dst = *font_row;
-		break;
-	}
-	case 8: {
-		register unsigned long *dst;
-		unsigned long fgmask, bgmask, data, rowbits, attrib;
-		const int ipl = ints_per_line;
-		
-		dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
-		attrib = (charattr >> 8) & 0x0ff;
-		fgmask = attrib & 0x0f;
-		bgmask = (attrib >> 4) & 0x0f;
-		fgmask = fgmask << 8 | fgmask;
-		fgmask |= fgmask << 16;
-		bgmask = bgmask << 8 | bgmask;
-		bgmask |= bgmask << 16;
-		
-		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
-			rowbits = *font_row;
-			data = fontmask_bits[(rowbits>>4)&0xf];
-			data = (data & fgmask) | (~data & bgmask);
-			*dst = data;
-			data = fontmask_bits[rowbits&0xf];
-			data = (data & fgmask) | (~data & bgmask);
-			*(dst+1) = data;
-		}
-		break;
-	} /* case */
-	} /* switch */
-	return (0);
-}
-
-unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-};
diff -u --recursive --new-file v1.3.95/linux/drivers/char/sunmouse.c linux/drivers/char/sunmouse.c
--- v1.3.95/linux/drivers/char/sunmouse.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/char/sunmouse.c	Thu Jan  1 02:00:00 1970
@@ -1,420 +0,0 @@
-/* sunmouse.c: Sun mouse driver for the Sparc
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *
- * Parts based on the psaux.c driver written by:
- * Johan Myreen.
- *
- * Dec/19/95 Added SunOS mouse ioctls - miguel.
- * Jan/5/96  Added VUID support, sigio support - miguel.
- * Mar/5/96  Added proper mouse stream support - miguel.
- */
-
-/* The mouse is run off of one of the Zilog serial ports.  On
- * that port is the mouse and the keyboard, each gets a zs channel.
- * The mouse itself is mouse-systems in nature.  So the protocol is:
- *
- * Byte 1) Button state which is bit-encoded as
- *            0x4 == left-button down, else up
- *            0x2 == middle-button down, else up
- *            0x1 == right-button down, else up
- *
- * Byte 2) Delta-x
- * Byte 3) Delta-y
- * Byte 4) Delta-x again
- * Byte 5) Delta-y again
- *
- * One day this driver will have to support more than one mouse in the system.
- *
- * This driver has two modes of operation: the default VUID_NATIVE is
- * set when the device is opened and allows the application to see the
- * mouse character stream as we get it from the serial (for gpm for
- * example).  The second method, VUID_FIRM_EVENT will provide cooked
- * events in Firm_event records.
- * */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fcntl.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/vuid_event.h>
-#include <linux/random.h>
-/* The following keeps track of software state for the Sun
- * mouse.
- */
-#define STREAM_SIZE   2048
-#define EV_SIZE       (STREAM_SIZE/sizeof (Firm_event))
-#define BUTTON_LEFT   4
-#define BUTTON_MIDDLE 2
-#define BUTTON_RIGHT  1
-
-struct sun_mouse {
-	unsigned char transaction[5];  /* Each protocol transaction */
-	unsigned char byte;            /* Counter, starts at 0 */
-	unsigned char button_state;    /* Current button state */
-	unsigned char prev_state;      /* Previous button state */
-	int delta_x;                   /* Current delta-x */
-	int delta_y;                   /* Current delta-y */
-	int present;
-	int ready;		       /* set if there if data is available */
-	int active;		       /* set if device is open */
-        int vuid_mode;	               /* VUID_NATIVE or VUID_FIRM_EVENT */
-	struct wait_queue *proc_list;
-	struct fasync_struct *fasync;
-	
-	/* The event/stream queue */
-	unsigned int head;
-	unsigned int tail;
-	union {
-		char stream [STREAM_SIZE];
-		Firm_event ev [0];
-	} queue;
-};
-
-static struct sun_mouse sunmouse;
-#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
-#define bstate sunmouse.button_state
-#define pstate sunmouse.prev_state
-
-extern void mouse_put_char(char ch);
-
-/* #define SMOUSE_DEBUG */
-
-static void
-push_event (Firm_event *ev)
-{
-	int next = (sunmouse.head + 1) % EV_SIZE;
-	
-	if (next != sunmouse.tail){
-		sunmouse.queue.ev [sunmouse.head] = *ev;
-		sunmouse.head = next;
-	}
-}
-
-static int
-queue_empty (void)
-{
-	return sunmouse.head == sunmouse.tail;
-}
-
-static Firm_event *
-get_from_queue (void)
-{
-	Firm_event *result;
-	
-	result = &sunmouse.queue.ev [sunmouse.tail];
-	sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
-	return result;
-}
-
-static void
-push_char (char c)
-{
-	int next = (sunmouse.head + 1) % STREAM_SIZE;
-
-	if (next != sunmouse.tail){
-		sunmouse.queue.stream [sunmouse.head] = c;
-		sunmouse.head = next;
-	}
-	sunmouse.ready = 1;
-	if (sunmouse.fasync)
-		kill_fasync (sunmouse.fasync, SIGIO);
-	wake_up_interruptible (&sunmouse.proc_list);
-}
-
-/* The following is called from the zs driver when bytes are received on
- * the Mouse zs8530 channel.
- */
-void
-sun_mouse_inbyte(unsigned char byte, unsigned char status)
-{
-	signed char mvalue;
-	int d;
-	Firm_event ev;
-
-	add_mouse_randomness (byte);
-	if(!sunmouse.active)
-		return;
-
-	if (!gen_events){
-		push_char (byte);
-		return;
-	}
-	/* Check for framing errors and parity errors */
-	/* XXX TODO XXX */
-
-	/* If the mouse sends us a byte from 0x80 to 0x87
-	 * we are starting at byte zero in the transaction
-	 * protocol.
-	 */
-	if(byte >= 0x80 && byte <= 0x87)
-		sunmouse.byte = 0;
-
-	mvalue = (signed char) byte;
-	switch(sunmouse.byte) {
-	case 0:
-		/* Button state */
-		sunmouse.button_state = (~byte) & 0x7;
-#ifdef SMOUSE_DEBUG
-		printk("B<Left %s, Middle %s, Right %s>",
-		       ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
-		       ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
-		       ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
-#endif
-		sunmouse.byte++;
-		return;
-	case 1:
-		/* Delta-x 1 */
-#ifdef SMOUSE_DEBUG
-		printk("DX1<%d>", mvalue);
-#endif
-		sunmouse.delta_x = mvalue;
-		sunmouse.byte++;
-		return;
-	case 2:
-		/* Delta-y 1 */
-#ifdef SMOUSE_DEBUG
-		printk("DY1<%d>", mvalue);
-#endif
-		sunmouse.delta_y = mvalue;
-		sunmouse.byte++;
-		return;
-	case 3:
-		/* Delta-x 2 */
-#ifdef SMOUSE_DEBUG
-		printk("DX2<%d>", mvalue);
-#endif
-		sunmouse.delta_x += mvalue;
-		sunmouse.byte++;
-		return;
-	case 4:
-		/* Last byte, Delta-y 2 */
-#ifdef SMOUSE_DEBUG
-		printk("DY2<%d>", mvalue);
-#endif
-		sunmouse.delta_y += mvalue;
-		sunmouse.byte = 69;  /* Some ridiculous value */
-		break;
-	case 69:
-		/* Until we get the (0x80 -> 0x87) value we aren't
-		 * in the middle of a real transaction, so just
-		 * return.
-		 */
-		return;
-	default:
-		printk("sunmouse: bogon transaction state\n");
-		sunmouse.byte = 69;  /* What could cause this? */
-		return;
-	};
-	d = bstate ^ pstate;
-	pstate = bstate;
-	if (d){
-		if (d & BUTTON_LEFT){
-			ev.id = MS_LEFT;
-			ev.value = bstate & BUTTON_LEFT;
-		}
-		if (d & BUTTON_RIGHT){
-			ev.id = MS_RIGHT;
-			ev.value = bstate & BUTTON_RIGHT;
-		}
-		if (d & BUTTON_MIDDLE){
-			ev.id = MS_MIDDLE;
-			ev.value = bstate & BUTTON_MIDDLE;
-		}
-		ev.time = xtime;
-		ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
-		push_event (&ev);
-	}
-	if (sunmouse.delta_x){
-		ev.id = LOC_X_DELTA;
-		ev.time = xtime;
-		ev.value = sunmouse.delta_x;
-		push_event (&ev);
-		sunmouse.delta_x = 0;
-	}
-	if (sunmouse.delta_y){
-		ev.id = LOC_Y_DELTA;
-		ev.time = xtime;
-		ev.value = sunmouse.delta_y;
-		push_event (&ev);
-	}
-	
-        /* We just completed a transaction, wake up whoever is awaiting
-	 * this event.
-	 */
-	sunmouse.ready = 1;
-	if (sunmouse.fasync)
-		kill_fasync (sunmouse.fasync, SIGIO);
-	wake_up_interruptible(&sunmouse.proc_list);
-	return;
-}
-
-static int
-sun_mouse_open(struct inode * inode, struct file * file)
-{
-	if(!sunmouse.present)
-		return -EINVAL;
-	if(sunmouse.active)
-		return -EBUSY;
-	sunmouse.active = 1;
-	sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
-	sunmouse.button_state = 0x80;
-	sunmouse.vuid_mode = VUID_NATIVE;
-	return 0;
-}
-
-static int
-sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-static void
-sun_mouse_close(struct inode *inode, struct file *file)
-{
-	sunmouse.active = sunmouse.ready = 0;
-	sun_mouse_fasync (inode, file, 0);
-}
-
-static int
-sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
-		int count)
-{
-	return -EINVAL;  /* foo on you */
-}
-
-static int
-sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
-	       int count)
-{
-	struct wait_queue wait = { current, NULL };
-
-	if (queue_empty ()){
-		if (file->f_flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
-		add_wait_queue (&sunmouse.proc_list, &wait);
-		while (queue_empty () && !(current->signal & ~current->blocked)){
-			current->state = TASK_INTERRUPTIBLE;
-			schedule ();
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue (&sunmouse.proc_list, &wait);
-	}
-	if (gen_events){
-		char *p = buffer, *end = buffer+count;
-		
-		while (p < end && !queue_empty ()){
-			*(Firm_event *)p = *get_from_queue ();
-			p += sizeof (Firm_event);
-		}
-		sunmouse.ready = !queue_empty ();
-		inode->i_atime = CURRENT_TIME;
-		return p-buffer;
-	} else {
-		int c;
-		
-		for (c = count; !queue_empty () && c; c--){
-			*buffer++ = sunmouse.queue.stream [sunmouse.tail];
-			sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
-		}
-		sunmouse.ready = !queue_empty ();
-		inode->i_atime = CURRENT_TIME;
-		return count-c;
-	}
-	/* Only called if nothing was sent */
-	if (current->signal & ~current->blocked)
-		return -ERESTARTSYS;
-	return 0;
-}
-
-static int
-sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
-			    select_table *wait)
-{
-	if(sel_type != SEL_IN)
-		return 0;
-	if(sunmouse.ready)
-		return 1;
-	select_wait(&sunmouse.proc_list, wait);
-	return 0;
-}
-int
-sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int i;
-	
-	switch (cmd){
-		/* VUIDGFORMAT - Get input device byte stream format */
-	case _IOR('v', 2, int):
-		i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
-		if (i) return i;
-		*(int *)arg = sunmouse.vuid_mode;
-		break;
-
-		/* VUIDSFORMAT - Set input device byte stream format*/
-	case _IOW('v', 1, int):
-		i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
-	        if (i) return i;
-		i = *(int *) arg;
-		if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
-			sunmouse.vuid_mode = *(int *)arg;
-			sunmouse.head = sunmouse.tail = 0;
-		} else
-			return -EINVAL;
-		break;
-		
-	default:
-		printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
-		return -1;
-	}
-	return 0;
-}
-
-struct file_operations sun_mouse_fops = {
-	NULL,
-	sun_mouse_read,
-	sun_mouse_write,
-	NULL,
-	sun_mouse_select,
-	sun_mouse_ioctl,
-	NULL,
-	sun_mouse_open,
-	sun_mouse_close,
-	NULL,
-	sun_mouse_fasync,
-};
-
-static struct miscdevice sun_mouse_mouse = {
-	SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
-};
-
-int
-sun_mouse_init(void)
-{
-	printk("Sun Mouse-Systems mouse driver version 1.00\n");
-	sunmouse.present = 1;
-	sunmouse.ready = sunmouse.active = 0;
-	misc_register (&sun_mouse_mouse);
-	sunmouse.delta_x = sunmouse.delta_y = 0;
-	sunmouse.button_state = 0x80;
-	sunmouse.proc_list = NULL;
-	return 0;
-}
-
-void
-sun_mouse_zsinit(void)
-{
-	sunmouse.ready = 1;
-}
diff -u --recursive --new-file v1.3.95/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v1.3.95/linux/drivers/net/3c509.c	Sun Apr 21 19:22:08 1996
+++ linux/drivers/net/3c509.c	Fri Apr 26 14:48:48 1996
@@ -221,7 +221,6 @@
 		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
 	}
 
-	current_tag = dev->name[3]-'0';
 	/* For the first probe, clear all board's tag registers. */
 	if (current_tag == 0)
 		outb(0xd0, id_port);
@@ -266,10 +265,6 @@
 
 	/* Free the interrupt so that some other card can use it. */
 	outw(0x0f00, ioaddr + WN0_IRQ);
-
-	if( check_region(ioaddr, EL3_IO_EXTENT) )
-		return -ENODEV;
-
  found:
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
diff -u --recursive --new-file v1.3.95/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v1.3.95/linux/drivers/net/Config.in	Sun Apr 21 12:39:01 1996
+++ linux/drivers/net/Config.in	Fri Apr 26 18:05:24 1996
@@ -51,12 +51,12 @@
   tristate 'Cabletron E21xx support' CONFIG_E2100
   tristate 'DEPCA support' CONFIG_DEPCA
   tristate 'EtherWorks 3 support' CONFIG_EWRK3
+  tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
   if [ "$CONFIG_NET_ALPHA" = "y" ]; then
     bool 'SEEQ8005 support' CONFIG_SEEQ8005
     tristate 'AT1700 support' CONFIG_AT1700
     tristate 'FMV-181/182 support' CONFIG_FMV18X
     tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-    tristate 'EtherExpress support' CONFIG_EEXPRESS
     tristate 'NI5210 support' CONFIG_NI52
     bool 'NI6510 support' CONFIG_NI65
     tristate 'WaveLAN support' CONFIG_WAVELAN
diff -u --recursive --new-file v1.3.95/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.95/linux/drivers/net/Makefile	Sun Apr 21 19:22:08 1996
+++ linux/drivers/net/Makefile	Fri Apr 26 10:30:51 1996
@@ -450,6 +450,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_ATARILANCE),y)
+L_OBJS += atarilance.o
+else
+  ifeq ($(CONFIG_ATARILANCE),m)
+  M_OBJS += atarilance.o
+  endif
+endif
+
+ifeq ($(CONFIG_A2065),y)
+L_OBJS += a2065.o
+else
+  ifeq ($(CONFIG_A2065),m)
+  M_OBJS += a2065.o
+  endif
+endif
+
 ifeq ($(CONFIG_SDLA),y)
 L_OBJS += sdla.o
 else
@@ -463,6 +479,14 @@
 else
   ifeq ($(CONFIG_DLCI),m)
   M_OBJS += dlci.o
+  endif
+endif
+
+ifeq ($(CONFIG_ARIADNE),y)
+L_OBJS += ariadne.o
+else
+  ifeq ($(CONFIG_ARIADNE),m)
+  M_OBJS += ariadne.o
   endif
 endif
 
diff -u --recursive --new-file v1.3.95/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.95/linux/drivers/net/Space.c	Sun Apr 21 19:22:08 1996
+++ linux/drivers/net/Space.c	Fri Apr 26 10:30:51 1996
@@ -74,6 +74,9 @@
 extern int dgrs_probe(struct device *);
 extern int smc_init( struct device * );
 extern int sparc_lance_probe(struct device *);
+extern int atarilance_probe(struct device *);
+extern int a2065_probe(struct device *);
+extern int ariadne_probe(struct device *);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -190,6 +193,15 @@
 #endif
 #ifdef CONFIG_NI52
 	&& ni52_probe(dev)
+#endif
+#ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
+	&& atarilance_probe(dev)
+#endif
+#ifdef CONFIG_A2065		/* Commodore/Ameristar A2065 Ethernet Board */
+	&& a2065_probe(dev)
+#endif
+#ifdef CONFIG_ARIADNE		/* Village Tronic Ariadne Ethernet Board */
+	&& ariadne_probe(dev)
 #endif
 #ifdef CONFIG_SUNLANCE
 	&& sparc_lance_probe(dev)
diff -u --recursive --new-file v1.3.95/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v1.3.95/linux/drivers/net/a2065.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/net/a2065.c	Fri Apr 26 12:12:24 1996
@@ -346,7 +346,7 @@
 
 	board->Lance.RAP = CSR0;	/* LANCE Controller Status */
 
-	if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has
+	if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has
 					   been generated by the board. */
 		return;
 
diff -u --recursive --new-file v1.3.95/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v1.3.95/linux/drivers/net/ariadne.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/net/ariadne.c	Fri Apr 26 12:12:24 1996
@@ -394,7 +394,7 @@
 
     board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
 
-    if (!(board->Lance.RDP & INTR))	/* Check if any interrrupt has been
+    if (!(board->Lance.RDP & INTR))	/* Check if any interrupt has been
 	return;				   generated by the board. */
 
     if (dev->interrupt)
diff -u --recursive --new-file v1.3.95/linux/drivers/net/ariadne.h linux/drivers/net/ariadne.h
--- v1.3.95/linux/drivers/net/ariadne.h	Tue Apr 23 13:57:09 1996
+++ linux/drivers/net/ariadne.h	Fri Apr 26 12:12:24 1996
@@ -122,8 +122,8 @@
 #define CSR61		0x3d00	/*   Previous Transmit Descriptor Address */
 #define CSR62		0x3e00	/*   Previous Transmit Status and Byte Count */
 #define CSR63		0x3f00	/*   Previous Transmit Status and Byte Count */
-#define CSR64		0x4000	/*   Next Transmit Buffer Addres */
-#define CSR65		0x4100	/*   Next Transmit Buffer Addres */
+#define CSR64		0x4000	/*   Next Transmit Buffer Address */
+#define CSR65		0x4100	/*   Next Transmit Buffer Address */
 #define CSR66		0x4200	/*   Next Transmit Status and Byte Count */
 #define CSR67		0x4300	/*   Next Transmit Status and Byte Count */
 #define CSR68		0x4400	/*   Transmit Status Temporary Storage */
diff -u --recursive --new-file v1.3.95/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v1.3.95/linux/drivers/net/atarilance.c	Tue Apr 23 13:57:09 1996
+++ linux/drivers/net/atarilance.c	Fri Apr 26 12:12:25 1996
@@ -219,7 +219,7 @@
 	struct lance_ioreg	*iobase;
 	struct lance_memory	*mem;
 	int					cur_rx, cur_tx;	/* The next free ring entry */
-	int					dirty_tx;		/* Ring entries to be freeed. */
+	int					dirty_tx;		/* Ring entries to be freed. */
 						/* copy function */
 	void				*(*memcpy_f)( void *, const void *, size_t );
 	struct enet_statistics stats;
@@ -303,7 +303,7 @@
 #define CSR2	2		/* init block addr (high) */
 #define CSR3	3		/* misc */
 #define CSR8	8	  	/* address filter */
-#define CSR15	15		/* promiscous mode */
+#define CSR15	15		/* promiscuous mode */
 
 /* CSR0 */
 /* (R=readable, W=writeable, S=set on write, C=clear on write) */
diff -u --recursive --new-file v1.3.95/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v1.3.95/linux/drivers/net/de4x5.c	Fri Apr 12 15:51:55 1996
+++ linux/drivers/net/de4x5.c	Sat Apr 27 11:14:49 1996
@@ -121,6 +121,11 @@
     patched this  driver to detect it  because the SROM format used complies
     to a previous DEC-STD format.
 
+    I have removed the buffer copies needed for receive on Intels.  I cannot
+    remove them for   Alphas since  the  Tulip hardware   only does longword
+    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
+    longword aligned data copies (which makes them really slow). No comment.
+
     TO DO:
     ------
 
@@ -182,11 +187,19 @@
 			  Duh, put the SA_SHIRQ flag into request_interrupt().
 			  Fix SMC ethernet address in enet_det[].
 			  Print chip name instead of "UNKNOWN" during boot.
+      0.42    26-Apr-96   Fix MII write TA bit error.
+                          Fix bug in dc21040 and dc21041 autosense code.
+			  Remove buffer copies on receive for Intels.
+			  Change sk_buff handling during media disconnects to
+			  eliminate DUP packets.
+			  Add dynamic TX thresholding.
+			  Change all chips to use perfect multicast filtering.
+			  Fix alloc_device() bug <jari@markkus2.fimr.fi>
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.41 96/3/21 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n";
 
 #include <linux/module.h>
 
@@ -298,6 +311,7 @@
 ** Ethernet Info
 */
 #define PKT_BUF_SZ	1536            /* Buffer size for each Tx/Rx buffer */
+#define IEEE802_3_SZ    1518            /* Packet + CRC */
 #define MAX_PKT_SZ   	1514            /* Maximum ethernet packet length */
 #define MAX_DAT_SZ   	1500            /* Maximum ethernet data length */
 #define MIN_DAT_SZ   	1               /* Minimum ethernet data length */
@@ -418,6 +432,7 @@
     char info[100];
     short chksum;
 };
+#define SUB_VENDOR_ID 0x500a
 
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
@@ -451,7 +466,8 @@
     char adapter_name[80];                  /* Adapter name                 */
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
-    struct sk_buff *skb[NUM_TX_DESC];       /* TX skb for freeing when sent */
+    struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
+    struct sk_buff *rx_skb[NUM_RX_DESC];    /* RX skb's                     */
     int rx_new, rx_old;                     /* RX descriptor ring pointers  */
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
@@ -531,6 +547,8 @@
 			lp->tx_old+lp->txRingSize-lp->tx_new-1:\
 			lp->tx_old               -lp->tx_new-1)
 
+#define TX_PKT_PENDING (lp->tx_old != lp->tx_new)
+
 /*
 ** Public Functions
 */
@@ -551,6 +569,7 @@
 static int     de4x5_rx(struct device *dev);
 static int     de4x5_tx(struct device *dev);
 static int     de4x5_ast(struct device *dev);
+static int     de4x5_txur(struct device *dev);
 
 static int     autoconf_media(struct device *dev);
 static void    create_packet(struct device *dev, char *frame, int len);
@@ -563,13 +582,16 @@
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-/*static int     test_sym_link(struct device *dev, u32 msec);*/
+static int     test_sym_link(struct device *dev, int msec);
 static int     test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
 static int     is_spd_100(struct device *dev);
 static int     is_100_up(struct device *dev);
 static int     is_10_up(struct device *dev);
 static int     is_anc_capable(struct device *dev);
 static int     ping_media(struct device *dev, int msec);
+static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len);
+static void    de4x5_free_rx_buffs(struct device *dev);
+static void    de4x5_free_tx_buffs(struct device *dev);
 static void    de4x5_save_skbs(struct device *dev);
 static void    de4x5_restore_skbs(struct device *dev);
 static void    de4x5_cache_state(struct device *dev, int flag);
@@ -621,6 +643,7 @@
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
 static void    de4x5_dbg_srom(struct de4x5_srom *p);
+static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
 static int     de4x5_strncmp(char *a, char *b, int n);
 
 #ifdef MODULE
@@ -655,7 +678,8 @@
 ** more info. Until I fix (un)register_netdevice() we won't be able to use it
 ** though.
 */
-int de4x5_probe(struct device *dev)
+int
+de4x5_probe(struct device *dev)
 {
     int tmp = num_de4x5s, status = -ENODEV;
     u_long iobase = dev->base_addr;
@@ -793,62 +817,66 @@
 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
 	
 	/*
-	** Allocate contiguous receive buffers, long word aligned. 
+	** Set up the RX descriptor ring (Intels)
+	** Allocate contiguous receive buffers, long word aligned (Alphas) 
 	*/
+#ifndef __alpha__
+	for (i=0; i<NUM_RX_DESC; i++) {
+	    lp->rx_ring[i].status = 0;
+	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
+	    lp->rx_ring[i].buf = 0;
+	    lp->rx_ring[i].next = 0;
+	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+	}
+
+#else
 	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
-				   GFP_KERNEL)) != NULL) {
-	    lp->cache.buf = tmp;
-	    tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
-	    for (i=0; i<NUM_RX_DESC; i++) {
-		lp->rx_ring[i].status = 0;
-		lp->rx_ring[i].des1 = RX_BUFF_SZ;
-		lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
-		lp->rx_ring[i].next = (u32)NULL;
-	    }
-	    barrier();
+				   GFP_KERNEL)) == NULL) {
+	    kfree(lp->cache.priv);
+	    return -ENOMEM;
+	}
+
+	lp->cache.buf = tmp;
+	tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
+	for (i=0; i<NUM_RX_DESC; i++) {
+	    lp->rx_ring[i].status = 0;
+	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
+	    lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+	    lp->rx_ring[i].next = 0;
+	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+	}
+#endif
+
+	barrier();
 	    
-	    request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-				    DE4X5_EISA_TOTAL_SIZE), 
-			   lp->adapter_name);
+	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+				DE4X5_EISA_TOTAL_SIZE), 
+		       lp->adapter_name);
 	    
-	    lp->rxRingSize = NUM_RX_DESC;
-	    lp->txRingSize = NUM_TX_DESC;
+	lp->rxRingSize = NUM_RX_DESC;
+	lp->txRingSize = NUM_TX_DESC;
 	    
-	    /* Write the end of list marker to the descriptor lists */
-	    lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
-	    lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
+	/* Write the end of list marker to the descriptor lists */
+	lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
+	lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
 	    
-	    /* Tell the adapter where the TX/RX rings are located. */
-	    outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
-	    outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+	/* Tell the adapter where the TX/RX rings are located. */
+	outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+	outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
 	    
-	    /* Initialise the IRQ mask and Enable/Disable */
-	    lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
-	    lp->irq_en   = IMR_NIM | IMR_AIM;
+	/* Initialise the IRQ mask and Enable/Disable */
+	lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
+	lp->irq_en   = IMR_NIM | IMR_AIM;
 
-	    /* Create a loopback packet frame for later media probing */
-	    create_packet(dev, lp->frame, sizeof(lp->frame));
+	/* Create a loopback packet frame for later media probing */
+	create_packet(dev, lp->frame, sizeof(lp->frame));
 
-	    /* Initialise the adapter state */
-	    lp->state = CLOSED;
+	/* Initialise the adapter state */
+	lp->state = CLOSED;
+
+	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
+	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
 
-	    printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
-		   ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-	} else {
-	    printk("%s: Kernel could not allocate RX buffer memory.\n", dev->name);
-	}
-	if (status) {
-	    release_region(iobase, (lp->bus == PCI ? 
-				    DE4X5_PCI_TOTAL_SIZE :
-				    DE4X5_EISA_TOTAL_SIZE));
-	    if (lp->rx_ring[0].buf) {
-		kfree(bus_to_virt(lp->rx_ring[0].buf));
-	    }
-	    kfree(dev->priv);
-	    dev->priv = NULL;
-	    
-	    return -ENXIO;
-	}
     }
     
     if (de4x5_debug > 0) {
@@ -883,9 +911,17 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int status = 0;
+    int i, status = 0;
     s32 omr;
     
+    /* Allocate the RX buffers */
+    for (i=0; i<lp->rxRingSize; i++) {
+	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
+	    de4x5_free_rx_buffs(dev);
+	    return -EAGAIN;
+	}
+    }
+
     /*
     ** Wake up the adapter
     */
@@ -893,14 +929,13 @@
 	outl(0, PCI_CFDA);
 	de4x5_ms_delay(10);
     }
-    
-    lp->state = OPEN;
-    
+
     /* 
     ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
     
+    lp->state = OPEN;
     de4x5_dbg_open(dev);
     
     if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
@@ -937,7 +972,7 @@
 /*
 ** Initialize the DE4X5 operating conditions. NB: a chip problem with the
 ** DC21140 requires using perfect filtering mode for that chip. Since I can't
-** see why I'd want > 14 multicast addresses, I may change all chips to use
+** see why I'd want > 14 multicast addresses, I have changed all chips to use
 ** the perfect filtering mode. Keep the DMA burst length at 8: there seems
 ** to be data corruption problems if it is larger (UDP errors seen from a
 ** ttcp source).
@@ -956,7 +991,8 @@
     return 0;
 }
 
-static int de4x5_sw_reset(struct device *dev)
+static int
+de4x5_sw_reset(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -978,14 +1014,11 @@
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
     outl(bmr, DE4X5_BMR);
     
-    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn of promiscuous mode */
-    if (lp->chipset != DC21140) {
-	omr |= TR_96;
-	lp->setup_f = HASH_PERF;
-    } else {
-	omr |= OMR_SDP | OMR_SB | (!lp->phy[lp->active].id ? OMR_SF : 0);
-	lp->setup_f = PERFECT;
+    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
+    if (lp->chipset == DC21140) {
+	omr |= (OMR_SDP | OMR_SB);
     }
+    lp->setup_f = PERFECT;
     outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
     outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
     
@@ -1005,11 +1038,7 @@
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
     
-    if (lp->chipset != DC21140) {
-	load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    } else {
-	load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    }
+    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
     
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
@@ -1041,15 +1070,14 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int status = 0;
-    
+
     if (skb == NULL) {
 	dev_tint(dev);
 	return 0;
     }
 
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
-	de4x5_put_cache(dev, skb);               /* Queue the buffer locally */
-	return 0;                                
+	return -1;                                
     }
     
     /*
@@ -1063,14 +1091,14 @@
     sti();
     
     /* Transmit descriptor ring full or stale skb */
-    if (dev->tbusy || lp->skb[lp->tx_new]) {
+    if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
 	if (dev->interrupt) {
 	    de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
 	} else {
 	    de4x5_put_cache(dev, skb);
 	}
 	if (de4x5_debug > 1) {
-	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->skb[lp->tx_new] ? "YES" : "NO"));
+	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
 	}
     } else if (skb->len > 0) {
 	/* If we already have stuff queued locally, use that first */
@@ -1079,7 +1107,7 @@
 	    skb = de4x5_get_cache(dev);
 	}
 
-	while (skb && !dev->tbusy && !lp->skb[lp->tx_new]) {
+	while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
 	    set_bit(0, (void*)&dev->tbusy);
 	    cli();
 	    if (TX_BUFFS_AVAIL) {           /* Fill in a Tx ring entry */
@@ -1097,7 +1125,7 @@
 	    }
 	    sti();
 	}
-	if (skb && (dev->tbusy || lp->skb[lp->tx_new])) {
+	if (skb && (dev->tbusy || lp->tx_skb[lp->tx_new])) {
 	    de4x5_putb_cache(dev, skb);
 	}
     }
@@ -1121,7 +1149,7 @@
 {
     struct device *dev = (struct device *)dev_id;
     struct de4x5_private *lp;
-    s32 imr, omr, sts;
+    s32 imr, omr, sts, limit;
     u_long iobase;
     
     if (dev == NULL) {
@@ -1137,7 +1165,7 @@
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
     dev->interrupt = MASK_INTERRUPTS;
 	
-    for (;;) {
+    for (limit=0; limit<8; limit++) {
 	sts = inl(DE4X5_STS);            /* Read IRQ status */
 	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
 	    
@@ -1154,6 +1182,10 @@
 	    lp->irq_mask &= ~IMR_LFM;
 	}
 	    
+	if (sts & STS_UNF) {             /* Transmit underrun */
+	    de4x5_txur(dev);
+	}
+	    
 	if (sts & STS_SE) {              /* Bus Error */
 	    STOP_DE4X5;
 	    printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1204,24 +1236,15 @@
 		struct sk_buff *skb;
 		short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4;
 		
-		if ((skb = dev_alloc_skb(pkt_len+2)) == NULL) {
+		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
 		    printk("%s: Insufficient memory; nuking packet.\n", 
 			                                            dev->name);
 		    lp->stats.rx_dropped++;   /* Really, deferred. */
 		    break;
 		}
+		de4x5_dbg_rx(skb, pkt_len);
 
-		skb->dev = dev;
-		skb_reserve(skb,2);	      /* Align */
-		if (entry < lp->rx_old) {     /* Wrapped buffer */
-		    short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-		    memcpy(skb_put(skb,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
-		    memcpy(skb_put(skb,pkt_len-len), bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
-		} else {                      /* Linear buffer */
-		    memcpy(skb_put(skb,pkt_len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
-		}
-		    
-		/* Push up the protocol stack */
+	/* Push up the protocol stack */
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
 		    
@@ -1284,29 +1307,32 @@
 	status = lp->tx_ring[entry].status;
 	if (status < 0) {                     /* Buffer not sent yet */
 	    break;
-	} else if (status & TD_ES) {          /* An error happened */
-	    lp->stats.tx_errors++; 
-	    if (status & TD_NC)  lp->stats.tx_carrier_errors++;
-	    if (status & TD_LC)  lp->stats.tx_window_errors++;
-	    if (status & TD_UF)  lp->stats.tx_fifo_errors++;
-	    if (status & TD_LC)  lp->stats.collisions++;
-	    if (status & TD_EC)  lp->pktStats.excessive_collisions++;
-	    if (status & TD_DE)  lp->stats.tx_aborted_errors++;
-	    
-	    if ((status != 0x7fffffff) &&     /* Not setup frame */
-		(status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
-		lp->lostMedia++;
-	    } else {
-		outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */
+	} else if (status != 0x7fffffff) {    /* Not setup frame */
+	    if (status & TD_ES) {             /* An error happened */
+		lp->stats.tx_errors++; 
+		if (status & TD_NC) lp->stats.tx_carrier_errors++;
+		if (status & TD_LC) lp->stats.tx_window_errors++;
+		if (status & TD_UF) lp->stats.tx_fifo_errors++;
+		if (status & TD_LC) lp->stats.collisions++;
+		if (status & TD_EC) lp->pktStats.excessive_collisions++;
+		if (status & TD_DE) lp->stats.tx_aborted_errors++;
+	    
+		if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+		    lp->lostMedia++;
+		}
+		if (TX_PKT_PENDING) {
+		    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
+		}
+	    } else {                      /* Packet sent */
+		lp->stats.tx_packets++;
+		lp->lostMedia = 0;        /* Remove transient problem */
+		lp->linkOK++;
+	    }
+	    /* Free the buffer. */
+	    if (lp->tx_skb[entry] != NULL) {
+		dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE);
+		lp->tx_skb[entry] = NULL;
 	    }
-	} else {                              /* Packet sent */
-	    lp->stats.tx_packets++;
-	    lp->lostMedia = 0;                /* Remove transient problem */
-	}
-	/* Free the buffer if it's not a setup frame. */
-	if (lp->skb[entry] != NULL) {
-	    dev_kfree_skb(lp->skb[entry], FREE_WRITE);
-	    lp->skb[entry] = NULL;
 	}
 	
 	/* Update all the pointers */
@@ -1343,6 +1369,29 @@
 }
 
 static int
+de4x5_txur(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int omr;
+
+    omr = inl(DE4X5_OMR);
+    if (!(omr & OMR_SF)) {
+	omr &= ~(OMR_ST|OMR_SR);
+	outl(omr, DE4X5_OMR);
+	while (inl(DE4X5_STS) & STS_TS);
+	if ((omr & OMR_TR) < OMR_TR) {
+	    omr += 0x4000;
+	} else {
+	    omr |= OMR_SF;
+	}
+	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+    }
+    
+    return 0;
+}
+
+static int
 de4x5_close(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -1362,14 +1411,15 @@
     ** We stop the DE4X5 here... mask interrupts and stop TX & RX
     */
     DISABLE_IRQs;
-    
     STOP_DE4X5;
     
-    /*
-    ** Free the associated irq
-    */
+    /* Free the associated irq */
     free_irq(dev->irq, dev);
     lp->state = CLOSED;
+
+    /* Free any socket buffers */
+    de4x5_free_rx_buffs(dev);
+    de4x5_free_tx_buffs(dev);
     
     MOD_DEC_USE_COUNT;
     
@@ -1393,14 +1443,15 @@
     return &lp->stats;
 }
 
-static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
+static void
+load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
     lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
     lp->tx_ring[lp->tx_new].des1 &= TD_TER;
     lp->tx_ring[lp->tx_new].des1 |= flags;
-    lp->skb[lp->tx_new] = skb;
+    lp->tx_skb[lp->tx_new] = skb;
     barrier();
     lp->tx_ring[lp->tx_new].status = T_OWN;
     barrier();
@@ -1426,13 +1477,8 @@
 	    outl(omr, DE4X5_OMR);
 	} else { 
 	    SetMulticastFilter(dev);
-	    if (lp->setup_f == HASH_PERF) {
-		load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-			    SETUP_FRAME_LEN, NULL);
-	    } else {
-		load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-			    SETUP_FRAME_LEN, NULL);
-	    }
+	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+			                                SETUP_FRAME_LEN, NULL);
 	    
 	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	    outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
@@ -1448,7 +1494,8 @@
 ** from a list of ethernet multicast addresses.
 ** Little endian crc one liner from Matt Thomas, DEC.
 */
-static void SetMulticastFilter(struct device *dev)
+static void
+SetMulticastFilter(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct dev_mc_list *dmi=dev->mc_list;
@@ -1508,7 +1555,8 @@
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
 {
     int i, maxSlots, status;
     u_short vendor, device;
@@ -1575,7 +1623,8 @@
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void pci_probe(struct device *dev, u_long ioaddr)
+static void
+pci_probe(struct device *dev, u_long ioaddr)
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
@@ -1583,7 +1632,7 @@
     u_int class = DE4X5_CLASS_CODE;
     u_int iobase;
     struct bus_type *lp = &bus;
-    
+
     if ((!ioaddr || !loading_module) && autoprobed) return;
     
     if (!pcibios_present()) return;          /* No PCI bus in this machine! */
@@ -1607,7 +1656,7 @@
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
 	    if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue;
-	    
+
 	    /* Set the device number information */
 	    lp->device = dev_num;
 	    lp->bus_num = pb;
@@ -1626,14 +1675,13 @@
 	    /* Check if I/O accesses and Bus Mastering are enabled */
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
 	    if (!(status & PCI_COMMAND_IO)) continue;
-	    
 	    if (!(status & PCI_COMMAND_MASTER)) {
 		status |= PCI_COMMAND_MASTER;
 		pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
 		pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
 	    }
 	    if (!(status & PCI_COMMAND_MASTER)) continue;
-	    
+
 	    DevicePresent(DE4X5_APROM);
 	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
 		if ((dev = alloc_device(dev, iobase)) != NULL) {
@@ -1657,7 +1705,8 @@
 ** Allocate the device by pointing to the next available space in the
 ** device structure. Should one not be available, it is created.
 */
-static struct device *alloc_device(struct device *dev, u_long iobase)
+static struct device *
+alloc_device(struct device *dev, u_long iobase)
 {
     int addAutoProbe = 0;
     struct device *tmp = NULL, *ret;
@@ -1700,7 +1749,7 @@
 	    ** and initialize it (name, I/O address, next device (NULL) and
 	    ** initialisation probe routine).
 	    */
-	    dev->name = (char *)(dev + sizeof(struct device));
+	    dev->name = (char *)(dev + 1);
 	    if (num_eth > 9999) {
 		sprintf(dev->name,"eth????");/* New device name */
 	    } else {
@@ -1739,7 +1788,7 @@
 		    ** area and initialize it (name, I/O address, next device
 		    ** (NULL) and initialisation probe routine).
 		    */
-		    tmp->name = (char *)(tmp + sizeof(struct device));
+		    tmp->name = (char *)(tmp + 1);
 		    if (num_eth > 9999) {
 			sprintf(tmp->name,"eth????");
 		    } else {               /* New device name */
@@ -1765,7 +1814,8 @@
 ** [TP] or no recent receive activity) to check whether the user has been 
 ** sneaky and changed the port on us.
 */
-static int autoconf_media(struct device *dev)
+static int
+autoconf_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1783,7 +1833,7 @@
     } else if (lp->chipset == DC21140) {
 	next_tick = dc21140m_autoconf(dev);
     }
-    if (lp->autosense == AUTO) enable_ast(dev, next_tick);
+    enable_ast(dev, next_tick);
     
     return (lp->media);
 }
@@ -1800,7 +1850,8 @@
 ** I may have to "age out" locally queued packets so that the higher layer
 ** timeouts don't effectively duplicate packets on the network.
 */
-static int dc21040_autoconf(struct device *dev)
+static int
+dc21040_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1827,32 +1878,32 @@
 	break;
 	
       case TP:
-	dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
+	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
 		                                         TP_SUSPECT, test_tp);
 	break;
 	
       case TP_SUSPECT:
-	de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
 	break;
 	
       case BNC:
       case AUI:
       case BNC_AUI:
-	dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
+	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
 		                                  BNC_AUI_SUSPECT, ping_media);
 	break;
 	
       case BNC_AUI_SUSPECT:
-	de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
 	break;
 	
       case EXT_SIA:
-	dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
+	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
 		                              NC, EXT_SIA_SUSPECT, ping_media);
 	break;
 	
       case EXT_SIA_SUSPECT:
-	de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
 	break;
 	
       case NC:
@@ -1862,7 +1913,10 @@
 	/* JAE: for Alpha, default to BNC/AUI, *not* TP */
 	reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
 #endif  /* i386 */
-	de4x5_dbg_media(dev);
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = NO;
 	break;
@@ -1953,7 +2007,8 @@
 ** any more packets to be queued to the hardware. Re-enable everything only
 ** when the media is found.
 */
-static int dc21041_autoconf(struct device *dev)
+static int
+dc21041_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2013,6 +2068,7 @@
 		    lp->media = TP;
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2023,7 +2079,7 @@
 	break;
 	
       case ANS_SUSPECT:
-	de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
 	break;
 	
       case TP:
@@ -2046,6 +2102,7 @@
 		    }
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2056,7 +2113,7 @@
 	break;
 	
       case TP_SUSPECT:
-	de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
 	break;
 	
       case AUI:
@@ -2067,7 +2124,7 @@
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000);
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
 	    if (sts < 0) {
 		next_tick = sts & ~TIMER_CB;
 	    } else {
@@ -2075,6 +2132,7 @@
 		    lp->media = BNC;
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2085,7 +2143,7 @@
 	break;
 	
       case AUI_SUSPECT:
-	de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
 	break;
 	
       case BNC:
@@ -2097,7 +2155,7 @@
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000);
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
 	    if (sts < 0) {
 		next_tick = sts & ~TIMER_CB;
 	    } else {
@@ -2131,14 +2189,17 @@
 	break;
 	
       case BNC_SUSPECT:
-	de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
 	break;
 	
       case NC:
 	omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
 	outl(omr | OMR_FD, DE4X5_OMR);
 	reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
-	de4x5_dbg_media(dev);
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = NO;
 	break;
@@ -2147,10 +2208,16 @@
     return next_tick;
 }
 
-static int dc21140m_autoconf(struct device *dev)
+/*
+** Some autonegotiation chips are broken in that they do not return the
+** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
+** register, except at the first power up negotiation.
+*/
+static int
+dc21140m_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int ana, anlpa, cap, cr, sr, iobase = dev->base_addr;
+    int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     u_long imr, omr;
     
@@ -2163,12 +2230,14 @@
 	    next_tick &= ~TIMER_CB;
 	} else {
 	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+	    lp->tmp = MII_SR_ASSC;         /* Fake out the MII speed set */
 	    SET_10Mb;
 	    if (lp->autosense == _100Mb) {
 		lp->media = _100Mb;
 	    } else if (lp->autosense == _10Mb) {
 		lp->media = _10Mb;
-	    } else if ((lp->autosense == AUTO) && (sr=is_anc_capable(dev))) {
+	    } else if ((lp->autosense == AUTO) && 
+		                     ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
 		ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
 		ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM);
 		mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
@@ -2206,21 +2275,23 @@
 	    break;
 	    
 	  case 1:
-	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 3000)) < 0) {
+	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
 		next_tick = sr & ~TIMER_CB;
 	    } else {
 		lp->media = SPD_DET;
 		lp->local_state = 0;
 		if (sr) {                         /* Success! */
+		    lp->tmp = MII_SR_ASSC;
 		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
 		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    if ((anlpa & MII_ANLPA_ACK) && !(anlpa & MII_ANLPA_RF) &&
-			(cap = anlpa & MII_ANLPA_TAF & ana)) {
+		    if (!(anlpa & MII_ANLPA_RF) && 
+			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
 			if (cap & MII_ANA_100M) {
 			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
 			    lp->media = _100Mb;
 			} else if (cap & MII_ANA_10M) {
 			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+
 			    lp->media = _10Mb;
 			}
 		    }
@@ -2232,17 +2303,23 @@
 	break;
 	
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
-	if (!lp->phy[lp->active].id) {
-	    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
+        if (lp->timeout < 0) {
+	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
+		                                  (~inl(DE4X5_GEP) & GEP_LNP));
+	    SET_100Mb_PDET;
 	}
-	if (is_spd_100(dev) && is_100_up(dev)) {
-	    lp->media = _100Mb;
-	} else if (!is_spd_100(dev) && is_10_up(dev)) {
-	    lp->media = _10Mb;
+        if ((slnk = test_sym_link(dev, 6200)) < 0) {
+	    next_tick = slnk & ~TIMER_CB;
 	} else {
-	    lp->media = NC;
+	    if (is_spd_100(dev) && is_100_up(dev)) {
+		lp->media = _100Mb;
+	    } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
+		lp->media = _10Mb;
+	    } else {
+		lp->media = NC;
+	    }
+	    next_tick = dc21140m_autoconf(dev);
 	}
-	next_tick = dc21140m_autoconf(dev);
 	break;
 	
       case _100Mb:                               /* Set 100Mb/s */
@@ -2276,8 +2353,10 @@
 	break;
 	
       case NC:
-	SET_10Mb;
-	de4x5_dbg_media(dev);
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = FALSE;
 	break;
@@ -2286,12 +2365,16 @@
     return next_tick;
 }
 
-static void de4x5_init_connection(struct device *dev)
+static void
+de4x5_init_connection(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
 
-    de4x5_dbg_media(dev);
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+	lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
     de4x5_restore_skbs(dev);
     cli();
     de4x5_rx(dev);
@@ -2304,7 +2387,8 @@
     return;
 }
 
-static int de4x5_reset_phy(struct device *dev)
+static int
+de4x5_reset_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2360,7 +2444,8 @@
     return sts;
 }
 
-static int test_tp(struct device *dev, s32 msec)
+static int
+test_tp(struct device *dev, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2381,11 +2466,37 @@
     return sisr;
 }
 
+static int
+test_sym_link(struct device *dev, int msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int gep = 0;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+    }
+    
+    if (lp->phy[lp->active].id) {
+	gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
+    } else {
+	gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
+    }
+    if (!(gep & GEP_SLNK) && --lp->timeout) {
+	gep = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return gep;
+}
+
 /*
 **
 **
 */
-static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
+static int
+test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int test, iobase = dev->base_addr;
@@ -2395,7 +2506,7 @@
     }
     
     if (pol) pol = ~0;
-    reg = mii_rd(reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
+    reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
     test = (reg ^ pol) & mask;
     
     if (test && --lp->timeout) {
@@ -2407,7 +2518,8 @@
     return reg;
 }
 
-static int is_spd_100(struct device *dev)
+static int
+is_spd_100(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2424,7 +2536,8 @@
     return spd;
 }
 
-static int is_100_up(struct device *dev)
+static int
+is_100_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2438,7 +2551,8 @@
     }
 }
 
-static int is_10_up(struct device *dev)
+static int
+is_10_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2452,13 +2566,14 @@
     }
 }
 
-static int is_anc_capable(struct device *dev)
+static int
+is_anc_capable(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
     if (lp->phy[lp->active].id) {
-	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_ANC);
+	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else {
 	return 0;
     }
@@ -2468,7 +2583,8 @@
 ** Send a packet onto the media and watch for send errors that indicate the
 ** media is bad or unconnected.
 */
-static int ping_media(struct device *dev, int msec)
+static int
+ping_media(struct device *dev, int msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2501,34 +2617,112 @@
 }
 
 /*
+** This function does 2 things: on Intels it kmalloc's another buffer to
+** replace the one about to be passed up. On Alpha's it kmallocs a buffer
+** into which the packet is copied.
+*/
+static struct sk_buff *
+de4x5_alloc_rx_buff(struct device *dev, int index, int len)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p;
+
+#ifndef __alpha__
+    struct sk_buff *ret;
+    u_long i=0, tmp;
+
+    p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    tmp = virt_to_bus(p->data);
+    i = ((tmp + ALIGN) & ~ALIGN) - tmp;
+    skb_reserve(p, i);
+    lp->rx_ring[index].buf = tmp + i;
+
+    ret = lp->rx_skb[index];
+    lp->rx_skb[index] = p;
+    skb_put(ret, len);
+
+    return ret;
+
+#else
+    if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
+
+    p = dev_alloc_skb(len + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    skb_reserve(p, 2);	                               /* Align */
+    if (index < lp->rx_old) {                          /* Wrapped buffer */
+	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
+	memcpy(skb_put(p,tlen), bus_to_virt(lp->rx_ring[lp->rx_old].buf),tlen);
+	memcpy(skb_put(p,len-tlen), bus_to_virt(lp->rx_ring[0].buf), len-tlen);
+    } else {                                           /* Linear buffer */
+	memcpy(skb_put(p,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf),len);
+    }
+		    
+    return p;
+#endif
+}
+
+static void
+de4x5_free_rx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->rxRingSize; i++) {
+	if (lp->rx_skb[i]) {
+	    dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
+	}
+	lp->rx_ring[i].status = 0;
+	lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
+    }
+
+    return;
+}
+
+static void
+de4x5_free_tx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->txRingSize; i++) {
+	if (lp->tx_skb[i]) {
+	    dev_kfree_skb(lp->tx_skb[i], FREE_WRITE);
+	    lp->tx_skb[i] = NULL;
+	}
+	lp->tx_ring[i].status = 0;
+    }
+
+    /* Unload the locally queued packets */
+    while (lp->cache.skb) {
+	dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE);
+    }
+
+    return;
+}
+
+/*
 ** When a user pulls a connection, the DECchip can end up in a
 ** 'running - waiting for end of transmission' state. This means that we
 ** have to perform a chip soft reset to ensure that we can synchronize
 ** the hardware and software and make any media probes using a loopback
 ** packet meaningful.
 */
-static void de4x5_save_skbs(struct device *dev)
+static void
+de4x5_save_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int i;
     s32 omr;
 
     if (!lp->cache.save_cnt) {
 	STOP_DE4X5;
 	de4x5_tx(dev);                          /* Flush any sent skb's */
-	for (i=lp->tx_new; i!=lp->tx_old; i--) {
-	    if (lp->skb[i]) {
-		de4x5_putb_cache(dev, lp->skb[i]);
-		lp->skb[i] = NULL;
-	    }
-	    if (i==0) i=lp->txRingSize;
-	}
-        if (lp->skb[i]) {
-	    de4x5_putb_cache(dev, lp->skb[i]);
-	    lp->skb[i] = NULL;
-	}
-
+	de4x5_free_tx_buffs(dev);
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
@@ -2540,12 +2734,11 @@
     return;
 }
 
-static void de4x5_restore_skbs(struct device *dev)
+static void
+de4x5_restore_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    struct sk_buff *skb;
-    int i;
     s32 omr;
 
     if (lp->cache.save_cnt) {
@@ -2553,16 +2746,7 @@
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-	dev->tbusy = 1;
-
-	for (i=0; TX_BUFFS_AVAIL && lp->cache.skb; i++) {
-	    skb = de4x5_get_cache(dev);
-	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	}
-	if (TX_BUFFS_AVAIL) {
-	    dev->tbusy = 0;
-	}
+	dev->tbusy = 0;
 	lp->cache.save_cnt--;
 	START_DE4X5;
     }
@@ -2570,7 +2754,8 @@
     return;
 }
 
-static void de4x5_cache_state(struct device *dev, int flag)
+static void
+de4x5_cache_state(struct device *dev, int flag)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2609,7 +2794,8 @@
     return;
 }
 
-static void de4x5_put_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_put_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p;
@@ -2625,7 +2811,8 @@
     return;
 }
 
-static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2636,7 +2823,8 @@
     return;
 }
 
-static struct sk_buff *de4x5_get_cache(struct device *dev)
+static struct sk_buff *
+de4x5_get_cache(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2653,7 +2841,8 @@
 ** Check the Auto Negotiation State. Return OK when a link pass interrupt
 ** is received and the auto-negotiation status is NWAY OK.
 */
-static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
+static int
+test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2680,7 +2869,8 @@
     return sts;
 }
 
-static void de4x5_setup_intr(struct device *dev)
+static void
+de4x5_setup_intr(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2700,7 +2890,8 @@
 /*
 **
 */
-static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
+static void
+reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2716,7 +2907,8 @@
 /*
 ** Create a loopback ethernet packet with an invalid CRC
 */
-static void create_packet(struct device *dev, char *frame, int len)
+static void
+create_packet(struct device *dev, char *frame, int len)
 {
     int i;
     char *buf = frame;
@@ -2737,7 +2929,8 @@
 /*
 ** Known delay in microseconds
 */
-static void de4x5_us_delay(u32 usec)
+static void
+de4x5_us_delay(u32 usec)
 {
     udelay(usec);
     
@@ -2747,7 +2940,8 @@
 /*
 ** Known delay in milliseconds, in millisecond steps.
 */
-static void de4x5_ms_delay(u32 msec)
+static void
+de4x5_ms_delay(u32 msec)
 {
     u_int i;
     
@@ -2762,7 +2956,8 @@
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int EISA_signature(char *name, s32 eisa_id)
+static int
+EISA_signature(char *name, s32 eisa_id)
 {
     c_char *signatures[] = DE4X5_SIGNATURE;
     char ManCode[DE4X5_STRLEN];
@@ -2796,7 +2991,8 @@
 /*
 ** Look for a particular board name in the PCI configuration space
 */
-static int PCI_signature(char *name, struct bus_type *lp)
+static int
+PCI_signature(char *name, struct bus_type *lp)
 {
     c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
@@ -2833,7 +3029,8 @@
 ** Set up the Ethernet PROM counter to the start of the Ethernet address on
 ** the DC21040, else  read the SROM for the other chips.
 */
-static void DevicePresent(u_long aprom_addr)
+static void
+DevicePresent(u_long aprom_addr)
 {
     int i;
     struct bus_type *lp = &bus;
@@ -2851,7 +3048,8 @@
     return;
 }
 
-static int get_hw_addr(struct device *dev)
+static int
+get_hw_addr(struct device *dev)
 {
     u_long iobase = dev->base_addr;
     int broken, i, k, tmp, status = 0;
@@ -2902,7 +3100,7 @@
 	chksum |= (u_short) (inb(EISA_APROM) << 8);
 	if ((k != chksum) && (dec_only)) status = -1;
     }
-    
+
     return status;
 }
 
@@ -2910,7 +3108,8 @@
 ** Test for enet addresses in the first 32 bytes. The built-in strncmp
 ** didn't seem to work here...?
 */
-static int de4x5_bad_srom(struct bus_type *lp)
+static int
+de4x5_bad_srom(struct bus_type *lp)
 {
     int i, status = 0;
 
@@ -2925,7 +3124,8 @@
     return status;
 }
 
-static int de4x5_strncmp(char *a, char *b, int n)
+static int
+de4x5_strncmp(char *a, char *b, int n)
 {
     int ret=0;
 
@@ -2939,7 +3139,8 @@
 /*
 ** SROM Read
 */
-static short srom_rd(u_long addr, u_char offset)
+static short
+srom_rd(u_long addr, u_char offset)
 {
     sendto_srom(SROM_RD | SROM_SR, addr);
     
@@ -2950,7 +3151,8 @@
     return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
-static void srom_latch(u_int command, u_long addr)
+static void
+srom_latch(u_int command, u_long addr)
 {
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
@@ -2959,7 +3161,8 @@
     return;
 }
 
-static void srom_command(u_int command, u_long addr)
+static void
+srom_command(u_int command, u_long addr)
 {
     srom_latch(command, addr);
     srom_latch(command, addr);
@@ -2968,7 +3171,8 @@
     return;
 }
 
-static void srom_address(u_int command, u_long addr, u_char offset)
+static void
+srom_address(u_int command, u_long addr, u_char offset)
 {
     int i;
     char a;
@@ -2987,7 +3191,8 @@
     return;
 }
 
-static short srom_data(u_int command, u_long addr)
+static short
+srom_data(u_int command, u_long addr)
 {
     int i;
     short word = 0;
@@ -3007,7 +3212,8 @@
 }
 
 /*
-static void srom_busy(u_int command, u_long addr)
+static void
+srom_busy(u_int command, u_long addr)
 {
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
    
@@ -3021,7 +3227,8 @@
 }
 */
 
-static void sendto_srom(u_int command, u_long addr)
+static void
+sendto_srom(u_int command, u_long addr)
 {
     outl(command, addr);
     udelay(1);
@@ -3029,7 +3236,8 @@
     return;
 }
 
-static int getfrom_srom(u_long addr)
+static int
+getfrom_srom(u_long addr)
 {
     s32 tmp;
     
@@ -3043,7 +3251,8 @@
 ** MII Read/Write
 */
 
-static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
+static int
+mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3055,7 +3264,8 @@
     return mii_rdata(ioaddr);              /* Read data                      */
 }
 
-static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
+static void
+mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3069,7 +3279,8 @@
     return;
 }
 
-static int mii_rdata(u_long ioaddr)
+static int
+mii_rdata(u_long ioaddr)
 {
     int i;
     s32 tmp = 0;
@@ -3082,7 +3293,8 @@
     return tmp;
 }
 
-static void mii_wdata(int data, int len, u_long ioaddr)
+static void
+mii_wdata(int data, int len, u_long ioaddr)
 {
     int i;
     
@@ -3094,7 +3306,8 @@
     return;
 }
 
-static void mii_address(u_char addr, u_long ioaddr)
+static void
+mii_address(u_char addr, u_long ioaddr)
 {
     int i;
     
@@ -3107,11 +3320,12 @@
     return;
 }
 
-static void mii_ta(u_long rw, u_long ioaddr)
+static void
+mii_ta(u_long rw, u_long ioaddr)
 {
     if (rw == MII_STWR) {
 	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
-	getfrom_mii(MII_MRD | MII_RD, ioaddr);
+	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
     } else {
 	getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
@@ -3119,7 +3333,8 @@
     return;
 }
 
-static int mii_swap(int data, int len)
+static int
+mii_swap(int data, int len)
 {
     int i, tmp = 0;
     
@@ -3132,7 +3347,8 @@
     return tmp;
 }
 
-static void sendto_mii(u32 command, int data, u_long ioaddr)
+static void
+sendto_mii(u32 command, int data, u_long ioaddr)
 {
     u32 j;
     
@@ -3145,7 +3361,8 @@
     return;
 }
 
-static int getfrom_mii(u32 command, u_long ioaddr)
+static int
+getfrom_mii(u32 command, u_long ioaddr)
 {
     outl(command, ioaddr);
     udelay(1);
@@ -3159,7 +3376,8 @@
 ** Here's 3 ways to calculate the OUI from the ID registers. One's a brain
 ** dead approach, 2 aren't (clue: mine isn't!).
 */
-static int mii_get_oui(u_char phyaddr, u_long ioaddr)
+static int
+mii_get_oui(u_char phyaddr, u_long ioaddr)
 {
 /*
     union {
@@ -3202,7 +3420,8 @@
     return r2;                                  /* (I did it) My way */
 }
 
-static int mii_get_phy(struct device *dev)
+static int
+mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3246,7 +3465,8 @@
     return lp->mii_cnt;
 }
 
-static char *build_setup_frame(struct device *dev, int mode)
+static char *
+build_setup_frame(struct device *dev, int mode)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3277,14 +3497,16 @@
     return pa;                     /* Points to the next entry */
 }
 
-static void enable_ast(struct device *dev, u32 time_out)
+static void
+enable_ast(struct device *dev, u32 time_out)
 {
     timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
     
     return;
 }
 
-static void disable_ast(struct device *dev)
+static void
+disable_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3293,7 +3515,8 @@
     return;
 }
 
-static long de4x5_switch_to_mii(struct device *dev)
+static long
+de4x5_switch_to_mii(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3319,7 +3542,8 @@
     return omr;
 }
 
-static long de4x5_switch_to_srl(struct device *dev)
+static long
+de4x5_switch_to_srl(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3327,7 +3551,6 @@
     
     /* Deassert the OMR_PS bit in CSR6 */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    outl(omr | OMR_TTM, DE4X5_OMR);
     outl(omr, DE4X5_OMR);
     
     /* Soft Reset */
@@ -3345,7 +3568,8 @@
     return omr;
 }
 
-static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
+static void
+timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int dt;
@@ -3366,7 +3590,8 @@
     return;
 }
 
-static void de4x5_dbg_open(struct device *dev)
+static void
+de4x5_dbg_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3416,7 +3641,8 @@
     return;
 }
 
-static void de4x5_dbg_mii(struct device *dev, int k)
+static void
+de4x5_dbg_mii(struct device *dev, int k)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3442,7 +3668,8 @@
     return;
 }
 
-static void de4x5_dbg_media(struct device *dev)
+static void
+de4x5_dbg_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3473,7 +3700,8 @@
     return;
 }
 
-static void de4x5_dbg_srom(struct de4x5_srom *p)
+static void
+de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
 
@@ -3496,11 +3724,48 @@
     return;
 }
 
+static void
+de4x5_dbg_rx(struct sk_buff *skb, int len)
+{
+    int i, j;
+
+    if (de4x5_debug > 2) {
+	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+	       (u_char)skb->data[0],
+	       (u_char)skb->data[1],
+	       (u_char)skb->data[2],
+	       (u_char)skb->data[3],
+	       (u_char)skb->data[4],
+	       (u_char)skb->data[5],
+	       (u_char)skb->data[6],
+	       (u_char)skb->data[7],
+	       (u_char)skb->data[8],
+	       (u_char)skb->data[9],
+	       (u_char)skb->data[10],
+	       (u_char)skb->data[11],
+	       (u_char)skb->data[12],
+	       (u_char)skb->data[13],
+	       len);
+	if (de4x5_debug > 3) {
+	    for (j=0; len>0;j+=16, len-=16) {
+		printk("    %03x: ",j);
+		for (i=0; i<16 && i<len; i++) {
+		    printk("%02x ",(u_char)skb->data[i+j]);
+		}
+		printk("\n");
+	    }
+	}
+    }
+
+    return;
+}
+
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
 */
-static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
@@ -3540,13 +3805,8 @@
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
 	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
-	if (lp->setup_f == HASH_PERF) {
-	    load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-			SETUP_FRAME_LEN, NULL);
-	} else {
-	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-			SETUP_FRAME_LEN, NULL);
-	}
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+		                                        SETUP_FRAME_LEN, NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
 	dev->tbusy = 0;                              /* Unlock the TX ring */
diff -u --recursive --new-file v1.3.95/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v1.3.95/linux/drivers/net/de4x5.h	Wed Mar  6 14:53:46 1996
+++ linux/drivers/net/de4x5.h	Sat Apr 27 11:14:49 1996
@@ -671,9 +671,6 @@
 #define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down */
 #define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down */
 #define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down */
-#define _10Mb_SUSPECT   0x0808     /* Suspect 10Mb/s is down */
-#define _100Mb_SUSPECT  0x0809     /* Suspect 100Mb/s is down */
-#define LINK_RESET      0x080a     /* Reset the PHY and re-init auto sense */
 
 #define AUTO            0x4000     /* Auto sense the media or speed */
 #define TIMER_CB        0x80000000 /* Timer callback detection */
@@ -743,13 +740,15 @@
 */
 #define SET_10Mb {\
   if (lp->phy[lp->active].id) {\
-    mii_wr(MII_CR_10|MII_CR_ASSE,MII_CR,lp->phy[lp->active].addr,DE4X5_MII);\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\
-    omr |= (de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM;\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_10|(de4x5_full_duplex?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr |= ((de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM);\
     outl(omr, DE4X5_OMR);\
     outl(0, DE4X5_GEP);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
     omr |= (de4x5_full_duplex ? OMR_FD : 0);\
     outl(omr | OMR_TTM, DE4X5_OMR);\
     outl((de4x5_full_duplex ? 0 : GEP_FDXD), DE4X5_GEP);\
@@ -758,18 +757,37 @@
 
 #define SET_100Mb {\
   if (lp->phy[lp->active].id) {\
-    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\
+    int fdx=0;\
+    if (lp->phy[lp->active].id == NATIONAL_TX) {\
+        mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
+                      0x18, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\
     sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
-    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) omr |= OMR_FD;\
+    if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) fdx=1;\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    if (fdx) omr |= OMR_FD;\
     outl(omr, DE4X5_OMR);\
-    outl(((!(sr & MII_ANA_T4AM) && de4x5_full_duplex) ? 0:GEP_FDXD)|GEP_MODE,\
-	                                                          DE4X5_GEP);\
   } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
     omr |= (de4x5_full_duplex ? OMR_FD : 0);\
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
     outl((de4x5_full_duplex ? 0 : GEP_FDXD) | GEP_MODE, DE4X5_GEP);\
+  }\
+}
+
+/* FIX ME so I don't jam 10Mb networks */
+#define SET_100Mb_PDET {\
+  if (lp->phy[lp->active].id) {\
+    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    outl(omr, DE4X5_OMR);\
+  } else {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\
+    outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);\
   }\
 }
 
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/Makefile linux/drivers/sbus/Makefile
--- v1.3.95/linux/drivers/sbus/Makefile	Sun Apr 21 19:22:09 1996
+++ linux/drivers/sbus/Makefile	Thu Apr 25 13:27:42 1996
@@ -7,7 +7,18 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) char
+
 L_OBJS   := sbus.o dvma.o
 L_TARGET := sbus.a
+
+# Character devices for SBUS-based machines.
+#
+ifeq ($(CONFIG_SBUSCHAR),y)
+SUB_DIRS += char
+L_OBJS += char/sunchar.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v1.3.95/linux/drivers/sbus/char/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/Makefile	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,13 @@
+#
+# 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...
+
+O_TARGET := sunchar.o
+O_OBJS   := suncons.o sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v1.3.95/linux/drivers/sbus/char/suncons.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/suncons.c	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,1922 @@
+/* suncons.c: Sun SparcStation console support.
+ *
+ * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Added render_screen and faster scrolling Nov/27, miguel
+ * Added console palette code for cg6 Dec/13/95, miguel
+ * Added generic frame buffer support Dec/14/95, miguel
+ * Added cgsix and bwtwo drivers Jan/96, miguel
+ * Added 4m, and cg3 driver Feb/96, miguel
+ * Fixed the cursor on color displays Feb/96, miguel.
+ *
+ * Cleaned up the detection code, generic 8bit depth display 
+ * code, Mar/96 miguel
+ * 
+ * This file contains the frame buffer device drivers.
+ * Each driver is kept together in case we would like to
+ * split this file.
+ *
+ * Much of this driver is derived from the DEC TGA driver by
+ * Jay Estabrook who has done a nice job with the console
+ * driver abstraction btw.
+ *
+ * We try to make everything a power of two if possible to
+ * speed up the bit blit.  Doing multiplies, divides, and
+ * remainder routines end up calling software library routines
+ * since not all Sparcs have the hardware to do it.
+ *
+ * TODO:
+ * do not use minor to index into instances of the frame buffer,
+ * since the numbers assigned to us are not consecutive.
+ *
+ * do not blank the screen when frame buffer is mapped.
+ *
+ * Change the detection loop to use more than one video card.
+ */
+
+
+/* Define this one if you are debugging something in X, it will not disable the console output */
+/* #define DEBUGGING_X */
+/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
+
+#define GRAPHDEV_MAJOR 29
+
+#define FRAME_BUFFERS 1
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/fbio.h>
+#include <asm/io.h>
+#include <asm/pgtsun4c.h>	/* for the sun4c_nocache */
+
+#include "../../char/kbd_kern.h"
+#include "../../char/vt_kern.h"
+#include "../../char/consolemap.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+
+#define cmapsz 8192
+
+extern void register_console(void (*proc)(const char *));
+extern void console_print(const char *);
+extern unsigned char vga_font[];
+extern int graphics_on;
+extern int serial_console;
+
+/* Based upon what the PROM tells us, we can figure out where
+ * the console is currently located.  The situation can be either
+ * of the following two scenarios:
+ *
+ * 1) Console i/o is done over the serial line, ttya or ttyb
+ * 2) Console output on frame buffer (video card) and input
+ *    coming from the keyboard/mouse which each use a zilog8530
+ *    serial channel a piece.
+ */
+
+/* The following variables describe a Sparc console. */
+
+/* From the PROM */
+static char con_name[40];
+
+/* Screen dimensions and color depth. */
+static int con_depth, con_width, con_height, con_type;
+
+static int con_linebytes;
+
+/* Base address of first line. */
+static unsigned char *con_fb_base;
+
+/* Screen parameters: we compute those at startup to make the code faster */
+static int chars_per_line;	/* number of bytes per line */
+static int ints_per_line;	/* number of ints per  line */
+static int skip_bytes;		/* number of bytes we skip for the y margin */
+static int x_margin, y_margin;	/* the x and y margins */
+static int bytes_per_row;	/* bytes used by one screen line (of 16 scan lines)  */
+
+/* Functions used by the SPARC dependent console code
+ * to perform the restore_palette function.
+ */
+static void (*restore_palette)(void);
+void set_palette (void);
+
+
+ /* Our screen looks like at 1152 X 900:
+ *
+ *  0,0
+ *      ------------------------------------------------------------------
+ *      |                          ^^^^^^^^^^^                           |
+ *      |                          18 y-pixels                           |
+ *      |                          ^^^^^^^^^^^                           |
+ *   13 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
+ *    ....
+ *                         54 chars from top to bottom
+ *    ....
+ *  888 | <-64 pixels->|  <-- 128 8x16 characters -->    | <-64 pixels-> |
+ *      |                          ^^^^^^^^^^^                           |
+ *      |                          18 y-pixels                           |
+ *      |                          ^^^^^^^^^^^                           |
+ *      ------------------------------------------------------------------
+ */
+/* First for MONO displays. */
+#define SCREEN_WIDTH     1152     /* Screen width in pixels  */
+#define SCREEN_HEIGHT    900      /* Screen height in pixels */
+#define CHARS_PER_LINE   144      /* Make this empirical for speed */
+#define NICE_Y_MARGIN    18       /* We skip 18 y-pixels at top/bottom */
+#define NICE_X_MARGIN    8        /* We skip 64 x-pixels at left/right */
+#define FBUF_TOP_SKIP    2592     /* Empirical, (CHARS_PER_LINE * NICE_Y_MARGIN) */
+#define CHAR_HEIGHT      16
+#define ONE_ROW          2304     /* CHARS_PER_LINE * CHAR_HEIGHT */
+
+/* Now we have this, to compute the base frame buffer position
+ * for a new character to be rendered. 1 and 8 bit depth.
+ */
+#define FBUF_OFFSET(cindex) \
+        (((FBUF_TOP_SKIP) + (((cindex)>>7) * ONE_ROW)) + \
+	 ((NICE_X_MARGIN) + (((cindex)&127))))
+
+
+#define COLOR_FBUF_OFFSET(cindex) \
+        (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
+	 ((x_margin) + (((cindex)&127) << 3)))
+
+void
+__set_origin(unsigned short offset)
+{
+	/*
+	 * should not be called, but if so, do nothing...
+	 */
+}
+
+/* For the cursor, we just invert the 8x16 block at the cursor
+ * location.  Easy enough...
+ *
+ * Hide the cursor from view, during blanking, usually...
+ */
+static int cursor_pos = -1;
+void
+hide_cursor(void)
+{
+	unsigned long flags;
+	int j;
+
+	save_flags(flags); cli();
+
+	if(cursor_pos == -1) {
+		restore_flags (flags);
+		return;
+	}
+	/* We just zero out the area for now.  Certain graphics
+	 * cards like the cg6 have a hardware cursor that we could
+	 * use, but this is an optimization for some time later.
+	 */
+	switch (con_depth){
+	case 1: {
+		unsigned char *dst;
+		dst = (unsigned char *)((unsigned long)con_fb_base +
+					FBUF_OFFSET(cursor_pos));
+		for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
+			*dst = ~(0);
+		break;
+	}
+	case 8: {
+		unsigned long *dst;
+		const    int ipl = ints_per_line;
+		
+		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
+		for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
+			*dst = ~(0UL);
+			*(dst + 1) = ~(0UL);
+		}
+		break;
+	}
+	default:
+		break;
+	}
+	restore_flags(flags);
+}
+
+/* The idea is the following:
+ * we only use the colors in the range 0..15, and we only
+ * setup the palette on that range, so we better keep the
+ * pixel inversion using those colors, that's why we have
+ * those constants below.
+ */
+inline static void
+cursor_reverse (long *dst, int height, const int ints_on_line)
+{
+    int j;
+
+    for (j = 0; j < height; j++){
+	*dst     = ~(*dst)     & 0x0f0f0f0f;
+	*(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
+	dst += ints_on_line;
+    }
+}
+
+void
+set_cursor(int currcons)
+{
+	int j, idx, oldpos;
+	unsigned long flags;
+
+	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+		return;
+
+	if (__real_origin != __origin)
+		__set_origin(__real_origin);
+
+	save_flags(flags); cli();
+
+	idx = (pos - video_mem_base) >> 1;
+	oldpos = cursor_pos;
+	cursor_pos = idx;
+	if (!deccm) {
+		hide_cursor ();
+		restore_flags (flags);
+		return;
+	}
+	switch (con_depth){
+	case 1: {
+		unsigned char *dst, *opos;
+		
+		dst = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(idx));
+		opos = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(oldpos));
+		if(oldpos != -1) {
+			/* Restore what was at the old position */
+			for(j=0; j < CHAR_HEIGHT; j++, opos += CHARS_PER_LINE) {
+				*opos = ~*opos;
+			}
+		}
+		for(j=0; j < 16; j++, dst+=CHARS_PER_LINE) {
+			*dst = ~*dst;
+		}
+		break;
+	}
+	case 8: {
+		unsigned long *dst, *opos;
+		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
+		opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
+			
+		if(oldpos != -1) 
+			cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
+		cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
+		break;
+	}
+	default:
+	}
+	restore_flags(flags);
+}
+
+/*
+ * Render the current screen
+ * Only used at startup to avoid the caching that is being done in selection.h
+ */
+static void
+render_screen(void)
+{
+    int count;
+    unsigned short *contents;
+
+    count = video_num_columns * video_num_lines;
+    contents = (unsigned short *) video_mem_base;
+    
+    for (;count--; contents++)
+	sun_blitc (*contents, (unsigned long) contents);
+}
+
+unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc)
+{
+        can_do_color = (con_type != FBTYPE_SUN2BW);
+
+        video_type = VIDEO_TYPE_SUN;
+        *display_desc = "SUN";
+
+	if (!serial_console) {
+		/* If we fall back to PROM than our output have to remain readable. */
+		prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
+
+		/*
+		 * fake the screen memory with some CPU memory
+		 */
+		video_mem_base = kmem_start;
+		kmem_start += video_screen_size;
+		video_mem_term = kmem_start;
+
+		render_screen();
+	}
+	return kmem_start;
+}
+
+/*
+ * NOTE: get_scrmem() and set_scrmem() are here only because
+ * the VGA version of set_scrmem() has some direct VGA references.
+ */
+void
+get_scrmem(int currcons)
+{
+	memcpyw((unsigned short *)vc_scrbuf[currcons],
+		(unsigned short *)origin, video_screen_size);
+	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+	scr_end = video_mem_end = video_mem_start + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+	if (video_mem_term - video_mem_base < offset + video_screen_size)
+		offset = 0;
+	memcpyw((unsigned short *)(video_mem_base + offset),
+		(unsigned short *) origin, video_screen_size);
+	video_mem_start = video_mem_base;
+	video_mem_end = video_mem_term;
+	origin = video_mem_base + offset;
+	scr_end = origin + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+/*
+ * PIO_FONT support.
+ */
+int
+set_get_font(char * arg, int set, int ch512)
+{
+	int error, i, line;
+
+	if (!arg)
+		return -EINVAL;
+	error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
+			     ch512 ? 2* cmapsz : cmapsz);
+	if (error)
+		return error;
+
+	/* download the current font */
+	if (!set){
+		memset (arg, 0, cmapsz);
+		for (i = 0; i < 256; i++)
+		    for (line = 0; line < CHAR_HEIGHT; line++)
+			put_user (vga_font [i], arg+(i*32+line));
+		return 0;
+	}
+	
+        /* set the font */
+	for (i = 0; i < 256; i++)
+		for (line = 0; line < CHAR_HEIGHT; line++){
+			vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
+			if (con_depth == 1)
+				vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
+		}
+	return 0;
+}
+
+/*
+ * Adjust the screen to fit a font of a certain height
+ *
+ * Returns < 0 for error, 0 if nothing changed, and the number
+ * of lines on the adjusted console if changed.
+ *
+ * for now, we only support the built-in font...
+ */
+int
+con_adjust_height(unsigned long fontheight)
+{
+	return -EINVAL;
+}
+
+int
+set_get_cmap(unsigned char * arg, int set)
+{
+	int i;
+
+	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+	if (i)
+		return i;
+
+	for (i=0; i<16; i++) {
+		if (set) {
+			default_red[i] = get_user(arg++) ;
+			default_grn[i] = get_user(arg++) ;
+			default_blu[i] = get_user(arg++) ;
+		} else {
+			put_user (default_red[i], arg++) ;
+			put_user (default_grn[i], arg++) ;
+			put_user (default_blu[i], arg++) ;
+		}
+	}
+	if (set) {
+		for (i=0; i<MAX_NR_CONSOLES; i++)
+			if (vc_cons_allocated(i)) {
+				int j, k ;
+				for (j=k=0; j<16; j++) {
+					vc_cons[i].d->vc_palette[k++] = default_red[j];
+					vc_cons[i].d->vc_palette[k++] = default_grn[j];
+					vc_cons[i].d->vc_palette[k++] = default_blu[j];
+				}
+			}
+		set_palette();
+	}
+
+	return 0;
+}
+
+
+void
+sun_clear_screen(void)
+{
+	memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
+		(con_depth * con_height * con_width) / 8);
+	/* also clear out the "shadow" screen memory */
+	memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
+}
+
+/*
+ * dummy routines for the VESA blanking code, which is VGA only,
+ * so we don't have to carry that stuff around for the Sparc...
+ */
+void vesa_blank(void)
+{
+}
+void vesa_unblank(void)
+{
+}
+void set_vesa_blanking(const unsigned long arg)
+{
+}
+
+void vesa_powerdown(void)
+{
+}
+
+#undef color
+/* cg6 cursor status, kernel tracked copy */
+struct cg6_cursor {
+        short   enable;	        /* cursor is enabled */
+        struct  fbcurpos cpos;	/* position */
+        struct  fbcurpos chot;	/* hot-spot */
+        struct  fbcurpos size;	/* size of mask & image fields */
+        int     bits[2][32];	/* space for mask & image bits */
+	char    color [6];	/* cursor colors */
+};
+
+struct cg6_info {
+	struct bt_regs *bt;	/* color control */
+	void *fbc;
+	struct cg6_fhc *fhc;
+	struct cg6_tec *tec;
+	struct cg6_thc *thc;
+	struct cg6_cursor cursor; /* cursor control */
+	void *dhc;
+};
+
+struct bwtwo_info {
+        struct bwtwo_regs *regs;
+};
+
+struct cg3_info {
+	struct bt_regs *bt;	/* brooktree (color) registers */
+};
+
+/* Array holding the information for the frame buffers */
+typedef struct {
+	union {
+		struct bwtwo_info bwtwo;
+		struct cg3_info   cg3;
+		struct cg6_info   cg6;
+	} info;		        /* per frame information */
+	int    space;           /* I/O space this card resides in */
+	int    blanked;		/* true if video blanked */
+	int    open;		/* is this fb open? */
+	int    mmaped;		/* has this fb been mmapped? */
+	int    vtconsole;	/* virtual console where it is opened */
+	long   base;		/* frame buffer base    */
+	struct fbtype type;	/* frame buffer type    */
+	int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
+	void   (*loadcmap)(void *this, int index, int count);
+	void   (*blank)(void *this);
+	void   (*unblank)(void *this);
+	int    (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
+} fbinfo_t;
+
+static fbinfo_t fbinfo [FRAME_BUFFERS];
+
+/* We need to keep a copy of the color map to answer ioctl requests */
+static union {
+	unsigned char   map[256][3];    /* reasonable way to access */
+        unsigned int    raw[256*3/4];   /* hardware wants it like this */
+} color_map;
+
+#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
+
+static int
+fb_open (struct inode * inode, struct file * file)
+{
+	int minor = MINOR (inode->i_rdev);
+
+	if (minor >= FRAME_BUFFERS)
+		return -EBADF;
+	if (fbinfo [minor].open)
+		return -EBUSY;
+	fbinfo [minor].open = 1;
+	fbinfo [minor].mmaped = 0;
+	return 0;
+}
+
+static int
+fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int minor = MINOR (inode->i_rdev);
+	fbinfo_t *fb;
+	struct fbcmap *cmap;
+	int i;
+	
+	if (minor >= FRAME_BUFFERS)
+		return -EBADF;
+	fb = &fbinfo [minor];
+	
+	switch (cmd){
+	case FBIOGTYPE:		/* return frame buffer type */
+		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
+		if (i) return i;
+		*(struct fbtype *)arg = (fb->type);
+		break;
+	case FBIOGATTR:{
+		struct fbgattr *fba = (struct fbgattr *) arg;
+		
+		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
+		if (i) return i;
+		fba->real_type = fb->type.fb_type;
+		fba->owner = 0;
+		fba->fbtype = fb->type;
+		fba->sattr.flags = 0;
+		fba->sattr.emu_type = fb->type.fb_type;
+		fba->sattr.dev_specific [0] = -1;
+		fba->emu_types [0] = fb->type.fb_type;
+		fba->emu_types [1] = -1;
+		break;
+	}
+	case FBIOSVIDEO:
+		i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+		if (i) return i;
+		
+		if (*(int *)arg){
+			if (!fb->blanked || !fb->unblank)
+				break;
+			(*fb->unblank)(fb);
+			fb->blanked = 0;
+		} else {
+			if (fb->blanked || !fb->blank)
+				break;
+			(*fb->blank)(fb);
+			fb->blanked = 1;
+		}
+		break;
+	case FBIOGVIDEO:
+		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
+		if (i) return i;
+		*(int *) arg = fb->blanked;
+		break;
+	case FBIOPUTCMAP: {	/* load color map entries */
+		char *rp, *gp, *bp;
+		int end, count;;
+		
+		if (!fb->loadcmap)
+			return -EINVAL;
+		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+		if (i) return i;
+		cmap = (struct fbcmap *) arg;
+		count = cmap->count;
+		if ((cmap->index < 0) || (cmap->index > 255))
+			return -EINVAL;
+		if (cmap->index + count > 256)
+			count = 256 - cmap->index;
+		i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
+		if (i) return i;
+
+		end = cmap->index + count;
+		for (i = cmap->index; i < end; i++){
+			color_map.map [i][0] = *rp++;
+			color_map.map [i][1] = *gp++;
+			color_map.map [i][2] = *bp++;
+		}
+		(*fb->loadcmap)(fb, cmap->index, count);
+                break;			
+	}
+
+	default:
+		if (fb->ioctl){
+			i = fb->ioctl (inode, file, cmd, arg, fb);
+			if (i == -EINVAL)
+				printk ("[[FBIO: %8.8x]]\n", cmd);
+			return i;
+		}
+		printk ("[[FBIO: %8.8x]]\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void
+fb_close (struct inode * inode, struct file *filp)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct fbcursor cursor;
+	
+	if (minor >= FRAME_BUFFERS)
+		return;
+	if (fbinfo [minor].open)
+		fbinfo [minor].open = 0;
+	vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
+
+	/* Leaving graphics mode, turn off the cursor */
+	graphics_on = 0;
+	if (fbinfo [minor].mmaped)
+		sun_clear_screen ();
+	cursor.set    = FB_CUR_SETCUR;
+	cursor.enable = 0;
+	fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
+	set_palette ();
+	render_screen ();
+	return;
+}
+
+static int
+fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+	int minor = MINOR (inode->i_rdev);
+	fbinfo_t *fb;
+
+	if (minor >= FRAME_BUFFERS)
+		return -ENXIO;
+	/* FIXME: the fg_console below should actually be the
+	 * console on which the invoking process is running
+	 */
+	if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
+		return -ENXIO;
+	fbinfo [minor].vtconsole = fg_console;
+	fb = &fbinfo [minor];
+
+	if (fb->mmap){
+		int v;
+		
+		v = (*fb->mmap)(inode, file, vma, fb->base, fb);
+		if (v) return v;
+		fbinfo [minor].mmaped = 1;
+		vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
+		graphics_on = 1;
+		return 0;
+	} else
+		return -ENXIO;
+}
+
+static struct file_operations graphdev_fops =
+{
+	NULL,			/* lseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* select */
+	fb_ioctl,
+	fb_mmap,
+	fb_open,		/* open */
+	fb_close,		/* close */
+};
+
+/* Call the frame buffer routine for setting the palette */
+void
+set_palette (void)
+{
+	if (console_blanked || vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
+		return;
+
+	if (fbinfo [0].loadcmap){
+		int i, j;
+	
+		/* First keep color_map with the palette colors */
+		for (i = 0; i < 16; i++){
+			j = color_table [i];
+			color_map.map [i][0] = default_red [j];
+			color_map.map [i][1] = default_grn [j];
+			color_map.map [i][2] = default_blu [j];
+		}
+		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
+	}
+}
+
+/* Called when returning to prom */
+void
+console_restore_palette (void)
+{
+        if (restore_palette)
+	        (*restore_palette) ();
+}
+
+/* This routine should be moved to srmmu.c */
+static __inline__ unsigned int
+srmmu_get_pte (unsigned long addr)
+{
+	register unsigned long entry;
+
+	__asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
+			     "=r" (entry):
+			     "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
+	return entry;
+}
+
+unsigned int
+get_phys (unsigned int addr)
+{
+	switch (sparc_cpu_model){
+	case sun4c:
+		return sun4c_get_pte (addr) << PAGE_SHIFT;
+	case sun4m:
+		return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
+	default:
+		panic ("get_phys called for unsupported cpu model\n");
+		return 0;
+	}
+}
+
+/* CG6 support code */
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the the frame buffer control
+ * The FHC could be the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0
+#define CG6_BROOKTREE_OFFSET 0x200000
+#define CG6_DHC_OFFSET       0x240000
+#define CG6_ALT_OFFSET       0x280000
+#define CG6_FHC_OFFSET       0x300000
+#define CG6_THC_OFFSET       0x301000
+#define CG6_FBC_OFFSET       0x700000
+#define CG6_TEC_OFFSET       0x701000
+#define CG6_RAM_OFFSET       0x800000
+
+struct bt_regs {
+	unsigned int  addr;	/* address register */
+	unsigned int  color_map; /* color map */
+	unsigned int  control;	/* control register */
+	unsigned int  cursor;	/* cursor map register */
+};
+
+/* The contents are unknown */
+struct cg6_tec {
+	int tec_matrix;
+	int tec_clip;
+	int tec_vdc;
+};
+
+struct cg6_thc {
+        unsigned int thc_xxx0[512];  /* ??? */
+        unsigned int thc_hsync1;     /* hsync timing */
+        unsigned int thc_hsync2;
+        unsigned int thc_hsync3;
+        unsigned int thc_vsync1;     /* vsync timing */
+        unsigned int thc_vsync2;
+        unsigned int thc_refresh;
+        unsigned int thc_misc;
+        unsigned int thc_xxx1[56];
+        unsigned int thc_cursxy;             /* cursor x,y position (16 bits each) */
+        unsigned int thc_cursmask[32];       /* cursor mask bits */
+        unsigned int thc_cursbits[32];       /* what to show where mask enabled */
+};
+
+static void
+cg6_restore_palette (void)
+{
+	volatile struct bt_regs *bt;
+
+	bt = fbinfo [0].info.cg6.bt;
+	bt->addr = 0;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+	unsigned int size, page, r, map_size;
+	unsigned int map_offset = 0;
+	fbinfo_t *fb = (fbinfo_t *) xx;
+	
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG6_TEC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.tec);
+			break;
+		case CG6_FBC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fbc);
+			break;
+		case CG6_FHC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fhc);
+			break;
+		case CG6_THC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.thc);
+			break;
+		case CG6_BTREGS:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.bt);
+			break;
+			
+		case CG6_DHC:
+			map_size = PAGE_SIZE * 40;
+			map_offset = get_phys ((uint)fb->info.cg6.dhc);
+			break;
+			
+		case CG6_ROM:
+			map_size = 0;
+			break;
+
+		case CG6_RAM:
+			map_size = size-page;
+			map_offset = get_phys ((uint) con_fb_base);
+			if (map_size < fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
+#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
+
+static void
+cg6_loadcmap (void *fbinfo, int index, int count)
+{
+	fbinfo_t *fb = (fbinfo_t *) fbinfo;
+	struct bt_regs *bt = fb->info.cg6.bt;
+	int i;
+	
+	bt->addr = index << 24;
+	for (i = index; count--; i++){
+		bt->color_map = color_map.map [i][0] << 24;
+		bt->color_map = color_map.map [i][1] << 24;
+		bt->color_map = color_map.map [i][2] << 24;
+	}
+}
+
+/* Load cursor information */
+static void
+cg6_setcursor (struct cg6_info *info)
+{
+	unsigned int v;
+	struct cg6_cursor *c = &info->cursor;
+	
+	if (c->enable){
+		v = ((c->cpos.fbx - c->chot.fbx) << 16)
+		   |((c->cpos.fby - c->chot.fby) & 0xffff);
+	} else {
+		/* Magic constant to turn off the cursor */
+		v = ((65536-32) << 16) | (65536-32);
+	}
+	info->thc->thc_cursxy = v;
+}
+
+#undef pos
+static int
+cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
+{
+	int op = cursor->set;
+	volatile struct cg6_thc *thc = fb->info.cg6.thc;
+	struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
+	int i, bytes = 0;
+	
+	if (op & FB_CUR_SETSHAPE){
+		if ((unsigned int) cursor->size.fbx > 32)
+			return -EINVAL;
+		if ((unsigned int) cursor->size.fby > 32)
+			return -EINVAL;
+		bytes = (cursor->size.fby * 32)/8;
+		i = verify_area (VERIFY_READ, cursor->image, bytes);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, cursor->mask, bytes);
+		if (i) return i;
+	}
+	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
+		if (op & FB_CUR_SETCUR)
+			cursor_info->enable = cursor->enable;
+		if (op & FB_CUR_SETPOS)
+			cursor_info->cpos = cursor->pos;
+		if (op & FB_CUR_SETHOT)
+			cursor_info->chot = cursor->hot;
+		cg6_setcursor (&fb->info.cg6);
+	}
+	if (op & FB_CUR_SETSHAPE){
+		unsigned int u;
+		
+		cursor_info->size = cursor->size;
+		memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
+		memcpy (cursor_info->bits [0], cursor->mask, bytes);
+		memcpy (cursor_info->bits [1], cursor->image, bytes);
+		u = ~0;
+		if (cursor_info->size.fbx < 32)
+			u = ~(u  >> cursor_info->size.fbx);
+		for (i = 0; i < 32; i++){
+			int m = cursor_info->bits [0][i] & u;
+			thc->thc_cursmask [i] = m;
+			thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
+		}
+	}
+	return 0;
+}
+
+/* Handle cg6-specific ioctls */
+static int
+cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+	int i;
+
+	switch (cmd){
+	case FBIOGCURMAX:
+		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
+		if (i) return i;
+		((struct fbcurpos *) arg)->fbx = 32;
+		((struct fbcurpos *) arg)->fby = 32;
+		break;
+
+	case FBIOSVIDEO:
+		/* vesa_blank and vesa_unblank could do the job on fb [0] */
+		break;
+
+	case FBIOSCURSOR:
+		return cg6_scursor ((struct fbcursor *) arg, fb);
+
+	case FBIOSCURPOS:
+		/*
+		i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
+		if (i) return i;
+		*/
+		fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
+		cg6_setcursor (&fb->info.cg6);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void
+cg6_setup (int slot, unsigned int cg6, int cg6_io)
+{
+	struct cg6_info *cg6info;
+
+	printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
+	
+	/* Fill in parameters we left out */
+	fbinfo [slot].type.fb_cmsize = 256;
+	fbinfo [slot].mmap = cg6_mmap;
+	fbinfo [slot].loadcmap = cg6_loadcmap;
+	fbinfo [slot].ioctl = (void *) cg6_ioctl;
+	fbinfo [slot].blank = 0;
+	fbinfo [slot].unblank = 0;
+	
+	cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
+
+	/* Map the hardware registers */
+	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
+		 sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
+	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
+		 sizeof (int), "cgsix_fhc", cg6_io, 0);
+	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
+		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
+	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
+		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
+	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
+		 0x40000, "cgsix_dhc", cg6_io, 0);
+	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
+		 0x1000, "cgsix_fbc", cg6_io, 0);
+	if (!con_fb_base){
+		con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
+                    fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
+	}
+	if (!slot)
+		restore_palette = cg6_restore_palette;
+}
+
+/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
+#define CG3_REGS 0x400000
+#define CG3_RAM  0x800000
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+/* The cg3 palette is loaded with 4 color values at each time  */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+static void
+cg3_loadcmap (void *fbinfo, int index, int count)
+{
+	fbinfo_t *fb = (fbinfo_t *) fbinfo;
+	struct bt_regs *bt = fb->info.cg3.bt;
+	int *i, steps;
+
+	i = &color_map.raw [D4M3(index)];
+	steps = D4M3(index+count-1) - D4M3(index)+3;
+	bt->addr = D4M4(index);
+	while (steps--)
+		bt->color_map = *i++;
+}
+
+/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
+/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation          */
+static int
+cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+	unsigned int size, page, r, map_size;
+	unsigned int map_offset = 0;
+	fbinfo_t *fb = (fbinfo_t *) xx;
+	
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG3_MMAP_OFFSET:
+			map_size = size-page;
+			map_offset = get_phys ((uint) con_fb_base);
+			if (map_size > fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+cg3_setup (int slot, unsigned int cg3, int cg3_io)
+{
+	struct cg3_info *cg3info;
+
+	printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
+	
+	/* Fill in parameters we left out */
+	fbinfo [slot].type.fb_cmsize = 256;
+	fbinfo [slot].mmap = cg3_mmap;
+	fbinfo [slot].loadcmap = cg3_loadcmap;
+	fbinfo [slot].ioctl = 0; /* no special ioctls */
+
+	cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
+
+	/* Map the card registers */
+	cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
+		 sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
+	
+	if (!con_fb_base){
+		con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
+                    fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
+	}
+}
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bwtwo_regs {
+	char          unknown [16];
+#define BWTWO_ENABLE_VIDEO 0x40
+	unsigned char control;
+	char          unknown2 [15];
+};
+
+static int
+bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+{
+	unsigned int size, map_offset, r;
+	fbinfo_t *fb = (fbinfo_t *) xx;
+	int map_size;
+	
+	map_size = size = vma->vm_end - vma->vm_start;
+	
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
+		(unsigned int) base,
+		(unsigned int) vma->vm_start, size,
+		(unsigned int) vma->vm_offset);
+
+	/* This routine should also map the register if asked for, but we don't do that yet */
+	map_offset = get_phys ((uint) con_fb_base);
+	r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
+				 fb->space);
+	if (r) return -EAGAIN;
+	vma->vm_inode = inode;
+	inode->i_count++;
+	return 0;
+}
+
+static void
+bwtwo_blank (void *xx)
+{
+	fbinfo_t *fb = (fbinfo_t *) xx;
+
+	fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_unblank (void *xx)
+{
+	fbinfo_t *fb = (fbinfo_t *) xx;
+	fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
+{
+	printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
+	fbinfo [slot].type.fb_cmsize = 2;
+	fbinfo [slot].mmap = bwtwo_mmap;
+	fbinfo [slot].loadcmap = 0;
+	fbinfo [slot].ioctl = 0;
+	fbinfo [slot].blank = bwtwo_blank;
+	fbinfo [slot].unblank = bwtwo_unblank;
+	fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
+		0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
+}
+
+static void
+cg14_setup (int slot, unsigned int cg14, int cg14_io)
+{
+	printk ("cgfourteen%d at 0x%8.8x\n", slot, cg14);
+	fbinfo [slot].type.fb_cmsize = 256;
+	fbinfo [slot].mmap =  0;
+	fbinfo [slot].loadcmap = 0;
+	fbinfo [slot].ioctl = 0;
+	fbinfo [slot].blank = 0;
+	fbinfo [slot].unblank = 0;
+}
+
+static char *known_cards [] = {
+	"cgsix", "cgthree", "bwtwo", "SUNW,tcx", "cgfourteen", 0
+};
+
+static int
+known_card (char *name)
+{
+	int i;
+
+	for (i = 0; known_cards [i]; i++)
+		if (strcmp (name, known_cards [i]) == 0)
+			return 1;
+	return 0;
+}
+
+static struct {
+	int depth;
+	int resx, resy;
+	int x_margin, y_margin;
+} scr_def [] = {
+	{ 1, 1152, 900,  8,  18 },
+	{ 8, 1152, 900,  64, 18 },
+	{ 8, 1280, 1024, 96, 80 },
+	{ 8, 1024, 768,  0,  0 },
+	{ 0 },
+};
+
+static int
+cg14_present(void)
+{
+	int root, n;
+
+	prom_printf ("Looking for cg14\n");
+	root = prom_getchild (prom_root_node);
+	if ((n = prom_searchsiblings (root, "obio")) == 0)
+		return 0;
+
+	n = prom_getchild (n);
+	if ((n = prom_searchsiblings (n, "cgfourteen")) == 0)
+		return 0;
+	prom_printf ("Cg14 found!\n");
+	return n;
+}
+
+static int
+sparc_console_probe(void)
+{
+	int propl, con_node, i;
+	struct linux_sbus_device *sbdp;
+	unsigned int fbbase = 0xb001b001;
+	int fbiospace = 0;
+	int cg14 = 0;
+
+	/* XXX The detection code needs to support multiple video cards in one system */
+	con_node = 0;
+	switch(prom_vers) {
+	case PROM_V0:
+		/* V0 proms are at sun4c only. Can skip many checks. */
+		con_type = FBTYPE_NOTYPE;
+		if(SBus_chain == 0) {
+			prom_printf("SBUS chain is NULL, bailing out...\n");
+			prom_halt();
+		}
+		for_each_sbusdev(sbdp, SBus_chain) {
+			con_node = sbdp->prom_node;
+
+			/* If no "address" than it is not the PROM console. */
+			if(sbdp->num_vaddrs) {
+				if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
+					con_type = FBTYPE_SUNFAST_COLOR;
+					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+					fbiospace = sbdp->reg_addrs[0].which_io;
+					break;
+				} else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
+					con_type = FBTYPE_SUN3COLOR;
+					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+					fbiospace = sbdp->reg_addrs[0].which_io;
+					break;
+				} else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
+					con_type = FBTYPE_SUN2BW;
+					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
+					fbiospace = sbdp->reg_addrs[0].which_io;
+					break;
+				}
+			}
+		}
+		if(con_type == FBTYPE_NOTYPE) return -1;
+		con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
+		strncpy(con_name, sbdp->prom_name, sizeof (con_name));
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		for_each_sbusdev(sbdp, SBus_chain) {
+		        prom_printf ("Trying: %s\n", sbdp->prom_name);
+			if (known_card (sbdp->prom_name))
+				break;
+		}
+		if (!sbdp){
+			if (!(cg14 = cg14_present ())){
+				prom_printf ("Could not find a known video card on this machine\n");
+				prom_halt ();
+			} 
+		}
+		if (!cg14){
+			prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
+			fbbase = (long) sbdp->reg_addrs [0].phys_addr;
+			fbiospace = sbdp->reg_addrs[0].which_io;
+			con_node = (*romvec->pv_v2devops.v2_inst2pkg)
+				(*romvec->pv_v2bootargs.fd_stdout);
+			/*
+			 * Determine the type of hardware accelerator.
+			 */
+			propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
+			if (propl < 0 || propl >= sizeof (con_name)) {
+				/* Early cg3s had no "emulation". */
+				propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
+				if (propl < 0) {
+					prom_printf("console: no device name!!\n");
+					return -1;
+				}
+			}
+			if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
+				con_type = FBTYPE_SUNFAST_COLOR;
+			} else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
+				con_type = FBTYPE_SUN3COLOR;
+			} else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
+				con_type = FBTYPE_MDICOLOR;
+			} else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
+				con_type = FBTYPE_SUN2BW;
+			} else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
+				con_type = FBTYPE_SUN3COLOR;
+			} else {
+				prom_printf("console: \"%s\" is unsupported\n", con_name);
+				return -1;
+			}
+			propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
+			if (propl != 4) {
+				con_fb_base = 0;
+			}
+		} else {
+			int bases [2];
+
+			con_node = cg14;
+			prom_printf ("Found a cg14\n");
+			propl = prom_getproperty (cg14, "address",
+						  (char *) &bases[0], 8);
+			prom_printf ("Size=%d, %x\n", propl, bases [1]);
+			con_fb_base = (unsigned char *) bases [1];
+			con_type = FBTYPE_MDICOLOR;
+		}
+		break;
+	default:
+		return -1;
+	};
+
+	/* Get the device geometry */
+	con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
+	con_width = prom_getintdefault(con_node, "width", 1152);
+	con_height = prom_getintdefault(con_node, "height", 900);
+
+	/* Currently we just support 1-bit and 8-bit depth displays */
+	if (con_type == FBTYPE_SUN2BW) {
+		con_depth = 1;
+	} else {
+		con_depth = 8;
+	}
+	for (i = 0; scr_def [i].depth; i++){
+		if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
+			continue;
+		if (scr_def [i].depth != con_depth)
+		        continue;
+		x_margin = scr_def [i].x_margin;
+		y_margin = scr_def [i].y_margin;
+		chars_per_line = (con_width * con_depth) / 8;
+		skip_bytes = chars_per_line * y_margin;
+		ints_per_line = chars_per_line / 4;
+		bytes_per_row = CHAR_HEIGHT * chars_per_line;
+		break;
+	}
+	if (!scr_def [i].depth){
+		x_margin = y_margin = 0;
+		prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
+		prom_halt ();
+	}
+	/* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
+	if ((con_linebytes*8) / con_depth != con_width) {
+		prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
+			con_linebytes, con_width, con_depth);
+		return -1;
+	}
+
+	/* Negate the font table on 1 bit depth cards so we have white on black */
+	if (con_depth == 1)
+		for(i=0; i<(16 * 256); i++)
+			vga_font[i] = ~vga_font[i];
+
+	/* Fill in common fb information */
+	fbinfo [0].type.fb_type   = con_type;
+	fbinfo [0].type.fb_height = con_height;
+	fbinfo [0].type.fb_width  = con_width;
+	fbinfo [0].type.fb_depth  = con_depth;
+	fbinfo [0].type.fb_size   = PAGE_ALIGN((con_linebytes) * (con_height));
+	fbinfo [0].space = fbiospace;
+	fbinfo [0].blanked = 0;
+
+	/* Should be filled in for supported video cards */
+	fbinfo [0].mmap = 0; 
+	fbinfo [0].loadcmap = 0;
+	fbinfo [0].ioctl = 0;
+	fbinfo [0].blank = 0;
+	fbinfo [0].unblank = 0;
+
+	if (fbbase == 0xb001b001){
+		printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
+	}
+
+	/* Per card setup */
+	switch (con_type){
+	case FBTYPE_SUN3COLOR:
+		cg3_setup (0, fbbase, fbiospace);
+		break;
+	case FBTYPE_SUNFAST_COLOR:
+		cg6_setup (0, fbbase, fbiospace);
+		break;
+	case FBTYPE_SUN2BW:
+		bwtwo_setup (0, fbbase, fbiospace);
+		break;
+	case FBTYPE_MDICOLOR:
+		cg14_setup (0, fbbase, fbiospace);
+		break;
+	default:
+		break;
+	}
+	if (!con_fb_base){
+		prom_printf ("PROM does not have an 'address' property for this\n"
+			     "frame buffer and the Linux drivers do not know how\n"
+			     "to map the video of this device\n");
+		prom_halt ();
+	}
+	fbinfo [0].base = (long) con_fb_base;
+	
+	/* Register the frame buffer device */
+	if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
+		printk ("Could not register graphics device\n");
+		return -EIO;
+	}
+	return 0; /* success */
+}
+
+/* video init code, called from within the SBUS bus scanner at
+ * boot time.
+ */
+void
+sun_console_init(void)
+{
+	if(serial_console)
+		return;
+
+	if(sparc_console_probe()) {
+		prom_printf("Could not probe console, bailing out...\n");
+		prom_halt();
+	}
+	sun_clear_screen();
+}
+
+/*
+ * sun_blitc
+ *
+ * Displays an ASCII character at a specified character cell
+ *  position.
+ *
+ * Called from scr_writew() when the destination is
+ *  the "shadow" screen
+ */
+static unsigned int
+fontmask_bits[16] = {
+    0x00000000,
+    0x000000ff,
+    0x0000ff00,
+    0x0000ffff,
+    0x00ff0000,
+    0x00ff00ff,
+    0x00ffff00,
+    0x00ffffff,
+    0xff000000,
+    0xff0000ff,
+    0xff00ff00,
+    0xff00ffff,
+    0xffff0000,
+    0xffff00ff,
+    0xffffff00,
+    0xffffffff
+};
+
+int
+sun_blitc(unsigned int charattr, unsigned long addr)
+{
+	int j, idx;
+	unsigned char *font_row;
+
+#ifndef DEBUGGING_X
+	if (graphics_on)
+		return 0;
+#endif
+	idx = (addr - video_mem_base) >> 1;
+
+	/* Invalidate the cursor position if necessary. */
+	if(idx == cursor_pos)
+		cursor_pos = -1;
+	font_row = &vga_font[(charattr & 0xff) << 4];
+
+	switch (con_depth){
+	case 1: {
+		register unsigned char *dst;
+		
+		dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
+		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+			*dst = *font_row;
+		break;
+	}
+	case 8: {
+		register unsigned long *dst;
+		unsigned long fgmask, bgmask, data, rowbits, attrib;
+		const int ipl = ints_per_line;
+		
+		dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
+		attrib = (charattr >> 8) & 0x0ff;
+		fgmask = attrib & 0x0f;
+		bgmask = (attrib >> 4) & 0x0f;
+		fgmask = fgmask << 8 | fgmask;
+		fgmask |= fgmask << 16;
+		bgmask = bgmask << 8 | bgmask;
+		bgmask |= bgmask << 16;
+		
+		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
+			rowbits = *font_row;
+			data = fontmask_bits[(rowbits>>4)&0xf];
+			data = (data & fgmask) | (~data & bgmask);
+			*dst = data;
+			data = fontmask_bits[rowbits&0xf];
+			data = (data & fgmask) | (~data & bgmask);
+			*(dst+1) = data;
+		}
+		break;
+	} /* case */
+	} /* switch */
+	return (0);
+}
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v1.3.95/linux/drivers/sbus/char/sunkbd.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunkbd.c	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,1317 @@
+/* keyboard.c: Sun keyboard driver.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Added vuid event generation and /dev/kbd device for SunOS
+ * compatibility - Miguel (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <asm/kbio.h>
+#include <asm/vuid_event.h>
+#include <asm/delay.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+
+#include "../../char/kbd_kern.h"
+#include "../../char/diacr.h"
+#include "../../char/vt_kern.h"
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+/* Define this one if you are making a new frame buffer driver */
+/* it will not block the keyboard */
+/* #define CODING_NEW_DRIVER */
+
+/* KBD device number, temporal */
+#define KBD_MAJOR 11
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+
+#ifndef KBD_DEFMODE
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+#endif
+
+#ifndef KBD_DEFLEDS
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock
+ * is on. This seems a good reason to start with NumLock off.
+ */
+#define KBD_DEFLEDS 0
+#endif
+
+#ifndef KBD_DEFLOCK
+#define KBD_DEFLOCK 0
+#endif
+
+extern void poke_blanked_console(void);
+extern void ctrl_alt_del(void);
+extern void reset_vc(unsigned int new_console);
+extern void scrollback(int);
+extern void scrollfront(int);
+
+unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+
+/*
+ * global state includes the following, and various static variables
+ * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
+ * (last_console is now a global variable)
+ */
+
+/* shift state counters.. */
+static unsigned char k_down[NR_SHIFT] = {0, };
+/* keyboard key bitmap */
+#define BITS_PER_LONG (8*sizeof(unsigned long))
+static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
+
+void push_kbd (int scan);
+int kbd_redirected = 0;
+
+static int dead_key_next = 0;
+/* 
+ * In order to retrieve the shift_state (for the mouse server), either
+ * the variable must be global, or a new procedure must be created to 
+ * return the value. I chose the former way.
+ */
+/*static*/ int shift_state = 0;
+static int npadch = -1;			/* -1 or number assembled on pad */
+static unsigned char diacr = 0;
+static char rep = 0;			/* flag telling character repeat */
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct tty_struct **ttytab;
+static struct kbd_struct * kbd = kbd_table;
+static struct tty_struct * tty = NULL;
+
+extern void compute_shiftstate(void);
+
+typedef void (*k_hand)(unsigned char value, char up_flag);
+typedef void (k_handfn)(unsigned char value, char up_flag);
+
+static k_handfn
+	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+	do_meta, do_ascii, do_lock, do_lowercase, do_ignore;
+
+static k_hand key_handler[16] = {
+	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+	do_meta, do_ascii, do_lock, do_lowercase,
+	do_ignore, do_ignore, do_ignore, do_ignore
+};
+
+typedef void (*void_fnp)(void);
+typedef void (void_fn)(void);
+
+static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
+	num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
+	SAK, decr_console, incr_console, spawn_console, bare_num;
+
+static void_fnp spec_fn_table[] = {
+	do_null,	enter,		show_ptregs,	show_mem,
+	show_state,	send_intr,	lastcons,	caps_toggle,
+	num,		hold,		scroll_forw,	scroll_back,
+	boot_it,	caps_on,	compose,	SAK,
+	decr_console,	incr_console,	spawn_console,	bare_num
+};
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+	255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
+	NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
+	255, NR_ASCII - 1, NR_LOCK - 1, 255
+};
+
+const int NR_TYPES = SIZE(max_vals);
+
+static void put_queue(int);
+static unsigned char handle_diacr(unsigned char);
+
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+static struct pt_regs * pt_regs;
+
+volatile unsigned char sunkbd_layout;
+volatile unsigned char sunkbd_type;
+#define SUNKBD_TYPE2        0x02
+#define SUNKBD_TYPE3        0x03
+#define SUNKBD_TYPE4        0x04
+
+#define SUNKBD_LOUT_TYP4    0x00
+#define SUNKBD_LOUT_TYP5    0x22
+
+volatile int kbd_reset_pending;
+volatile int kbd_layout_pending;
+
+/* commands */
+#define SKBDCMD_RESET       0x1
+#define SKBDCMD_GLAYOUT     0xf
+#define SKBDCMD_BELLON      0x2
+#define SKBDCMD_BELLOFF     0x3
+#define SKBDCMD_SETLED      0xe
+#define SKBDCMD_NOCLICK     0xb
+#define SKBDCMD_CLICK       0xa
+
+static unsigned char sunkbd_clickp;
+
+/* The led set commands require sending the SETLED byte then
+ * a byte encoding which led's to have set.  Here are the bit
+ * values, a bit set = led-on.
+ */
+#define LED_NLOCK           0x1   /* Num-lock */
+#define LED_CMPOSE          0x2   /* Compose */
+#define LED_SCRLCK          0x4   /* Scroll-lock */
+#define LED_CLOCK           0x8   /* Caps-lock */
+
+/* Special state characters */
+#define SKBD_RESET          0xff
+#define SKBD_ALLUP          0x7f
+#define SKBD_LYOUT          0xfe
+
+/* On the Sparc the keyboard could be one of two things.
+ * It could be a real keyboard speaking over one of the
+ * channels of the second zs8530 chip (other channel is
+ * used by the Sun mouse).  Else we have serial console
+ * going, and thus the other zs8530 chip is who we speak
+ * to.  Either way, we communicate through the zs8530
+ * driver for all our I/O.
+ */
+
+#define SUNKBD_UBIT     0x80      /* If set, key went up */
+#define SUNKBD_KMASK    0x7f      /* Other bits are the keycode */
+
+#define KEY_LSHIFT      0x81
+#define KEY_RSHIFT      0x82
+#define KEY_CONTROL     0x83
+#define KEY_NILL        0x84
+#define KEY_CAPSLOCK    0x85
+#define KEY_ALT         0x86
+#define KEY_L1          0x87
+
+extern void kbd_put_char(unsigned char ch);
+static inline void send_cmd(unsigned char c)
+{
+	kbd_put_char(c);
+}
+
+/* kbd_bh() calls this to send the SKBDCMD_SETLED to the sun keyboard
+ * with the proper bit pattern for the leds to be set.  It basically
+ * converts the kbd->ledflagstate values to corresponding sun kbd led
+ * bit value.
+ */
+static inline unsigned char vcleds_to_sunkbd(unsigned char vcleds)
+{
+	unsigned char retval = 0;
+
+	if(vcleds & (1<<VC_SCROLLOCK))
+		retval |= LED_SCRLCK;
+	if(vcleds & (1<<VC_NUMLOCK))
+		retval |= LED_NLOCK;
+	if(vcleds & (1<<VC_CAPSLOCK))
+		retval |= LED_CLOCK;
+	return retval;
+}
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL   97
+#define E0_KPSLASH 98
+#define E0_PRSCR   99
+#define E0_RALT    100
+#define E0_BREAK   101  /* (control-pause) */
+#define E0_HOME    102
+#define E0_UP      103
+#define E0_PGUP    104
+#define E0_LEFT    105
+#define E0_RIGHT   106
+#define E0_END     107
+#define E0_DOWN    108
+#define E0_PGDN    109
+#define E0_INS     110
+#define E0_DEL     111
+
+#define E1_PAUSE   119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85           /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86     124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
+  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
+  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO   112
+/* LK450 */
+#define E0_F13     113
+#define E0_F14     114
+#define E0_HELP    115
+#define E0_DO      116
+#define E0_F17     117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for  the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK	124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW	125
+#define E0_MSRW	126
+#define E0_MSTM	127
+
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
+  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
+  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
+  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
+  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
+  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
+  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
+  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
+  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
+};
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+	  return -EINVAL;
+	if (scancode < 128)
+	  high_keys[scancode - SC_LIM] = keycode;
+	else
+	  e0_keys[scancode - 128] = keycode;
+	return 0;
+}
+
+int getkeycode(unsigned int scancode)
+{
+	return
+	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
+	    e0_keys[scancode - 128];
+}
+
+void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+static void keyboard_timer (unsigned long ignored);
+
+static struct timer_list
+auto_repeat_timer = { NULL, NULL, 0, 0, keyboard_timer };
+
+/* Keeps track of the last pressed key */
+static unsigned char last_keycode;
+
+static void
+keyboard_timer (unsigned long ignored)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	/* Auto repeat: send regs = 0 to indicate autorepeat */
+	sunkbd_inchar (last_keycode, 0, 0);
+	del_timer (&auto_repeat_timer);
+	auto_repeat_timer.expires = jiffies + HZ/20;
+	add_timer (&auto_repeat_timer);
+	restore_flags(flags);
+}
+
+/* #define SKBD_DEBUG */
+/* This is our keyboard 'interrupt' routine. */
+void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
+{
+	unsigned char keycode;
+	char up_flag;                          /* 0 or SUNKBD_UBIT */
+	char raw_mode;
+
+	if(ch == SKBD_RESET) {
+		kbd_reset_pending = 1;
+		return;
+	}
+	if(ch == SKBD_LYOUT) {
+		kbd_layout_pending = 1;
+		return;
+	}
+	if(kbd_reset_pending) {
+		sunkbd_type = ch;
+		kbd_reset_pending = 0;
+		if(ch == SUNKBD_TYPE4)
+			send_cmd(SKBDCMD_GLAYOUT);
+		return;
+	} else if(kbd_layout_pending) {
+		sunkbd_layout = ch;
+		kbd_layout_pending = 0;
+		return;
+	} else if(ch == SKBD_ALLUP) {
+		/* eat it */
+		return;
+	}
+#ifdef SKBD_DEBUG
+	if(ch == 0x7f)
+		printk("KBD<ALL KEYS UP>");
+	else
+		printk("KBD<%x %s>", ch,
+		       ((ch&0x80) ? "UP" : "DOWN"));
+#endif
+
+	/* Whee, a real character. */
+	if (regs){
+		pt_regs = regs;
+		last_keycode = keycode = ch;
+	} else
+		keycode = ch;
+	
+	mark_bh(KEYBOARD_BH);
+	do_poke_blanked_console = 1;
+	mark_bh(CONSOLE_BH);
+	kbd = kbd_table + fg_console;
+	tty = ttytab[fg_console];
+	if((raw_mode = (kbd->kbdmode == VC_RAW))) {
+		if (kbd_redirected == fg_console+1)
+			push_kbd (keycode);
+		else
+			put_queue(keycode);
+		/* we do not return yet, because we want to maintain
+		 * the key_down array, so that we have the correct
+		 * values  when finishing RAW mode or when changing VT's.
+		 */
+	}
+	up_flag = (keycode & SUNKBD_UBIT);  /* The 'up' bit */
+	keycode &= SUNKBD_KMASK;            /* all the rest */
+	del_timer (&auto_repeat_timer);
+	if(up_flag) {
+		rep = 0;
+		clear_bit(keycode, key_down);
+	} else {
+		auto_repeat_timer.expires = jiffies+HZ/5;
+		add_timer (&auto_repeat_timer);
+		rep = set_bit(keycode, key_down);
+	}
+
+	if(raw_mode)
+		return;
+
+	if(kbd->kbdmode == VC_MEDIUMRAW) {
+		put_queue(keycode + up_flag);
+		return;
+	}
+
+ 	/*
+	 * Small change in philosophy: earlier we defined repetition by
+	 *	 rep = keycode == prev_keycode;
+	 *	 prev_keycode = keycode;
+	 * but now by the fact that the depressed key was down already.
+	 * Does this ever make a difference? Yes.
+	 */
+
+	/*
+ 	 *  Repeat a key only if the input buffers are empty or the
+ 	 *  characters get echoed locally. This makes key repeat usable
+ 	 *  with slow applications and under heavy loads.
+	 */
+	if (!rep ||
+	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
+	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
+		u_short keysym;
+		u_char type;
+
+		/* the XOR below used to be an OR */
+		int shift_final = shift_state ^ kbd->lockstate;
+		ushort *key_map = key_maps[shift_final];
+
+		if (key_map != NULL) {
+			keysym = key_map[keycode];
+			type = KTYP(keysym);
+
+			if (type >= 0xf0) {
+			    type -= 0xf0;
+			    if (type == KT_LETTER) {
+				type = KT_LATIN;
+				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
+				    if (key_map)
+				      keysym = key_map[keycode];
+				}
+			    }
+			    (*key_handler[type])(keysym & 0xff, up_flag);
+			    if (type != KT_SLOCK)
+			      kbd->slockstate = 0;
+			}
+		} else {
+			/* maybe beep? */
+			/* we have at least to update shift_state */
+			compute_shiftstate();
+		}
+	}
+}
+
+static void put_queue(int ch)
+{
+	wake_up(&keypress_wait);
+	if (tty) {
+		tty_insert_flip_char(tty, ch, 0);
+		tty_schedule_flip(tty);
+	}
+}
+
+static void puts_queue(char *cp)
+{
+	wake_up(&keypress_wait);
+	if (!tty)
+		return;
+
+	while (*cp) {
+		tty_insert_flip_char(tty, *cp, 0);
+		cp++;
+	}
+	tty_schedule_flip(tty);
+}
+
+static void applkey(int key, char mode)
+{
+	static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+	buf[1] = (mode ? 'O' : '[');
+	buf[2] = key;
+	puts_queue(buf);
+}
+
+static void enter(void)
+{
+	put_queue(13);
+	if (vc_kbd_mode(kbd,VC_CRLF))
+		put_queue(10);
+}
+
+static void caps_toggle(void)
+{
+	if (rep)
+		return;
+	chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void caps_on(void)
+{
+	if (rep)
+		return;
+	set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void show_ptregs(void)
+{
+	if (pt_regs)
+		show_regs(pt_regs);
+}
+
+static void hold(void)
+{
+	if (rep || !tty)
+		return;
+
+	/*
+	 * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+	 * these routines are also activated by ^S/^Q.
+	 * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+	 */
+	if (tty->stopped)
+		start_tty(tty);
+	else
+		stop_tty(tty);
+}
+
+static void num(void)
+{
+	if (vc_kbd_mode(kbd,VC_APPLIC))
+		applkey('P', 1);
+	else
+		bare_num();
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void bare_num(void)
+{
+	if (!rep)
+		chg_vc_kbd_led(kbd,VC_NUMLOCK);
+}
+
+static void lastcons(void)
+{
+	/* switch to the last used console, ChN */
+	set_console(last_console);
+}
+
+static void decr_console(void)
+{
+	int i;
+ 
+	for (i = fg_console-1; i != fg_console; i--) {
+		if (i == -1)
+			i = MAX_NR_CONSOLES-1;
+		if (vc_cons_allocated(i))
+			break;
+	}
+	set_console(i);
+}
+
+static void incr_console(void)
+{
+	int i;
+
+	for (i = fg_console+1; i != fg_console; i++) {
+		if (i == MAX_NR_CONSOLES)
+			i = 0;
+		if (vc_cons_allocated(i))
+			break;
+	}
+	set_console(i);
+}
+
+static void send_intr(void)
+{
+	if (!tty)
+		return;
+	tty_insert_flip_char(tty, 0, TTY_BREAK);
+	tty_schedule_flip(tty);
+}
+
+static void scroll_forw(void)
+{
+	scrollfront(0);
+}
+
+static void scroll_back(void)
+{
+	scrollback(0);
+}
+
+static void boot_it(void)
+{
+	extern int obp_system_intr(void);
+
+	if (!obp_system_intr())
+		ctrl_alt_del();
+	/* sigh.. atempt to prevent multiple entry */
+	last_keycode=1;
+	rep = 0;
+}
+
+static void compose(void)
+{
+	dead_key_next = 1;
+}
+
+int spawnpid, spawnsig;
+
+static void spawn_console(void)
+{
+        if (spawnpid)
+	   if(kill_proc(spawnpid, spawnsig, 1))
+	     spawnpid = 0;
+}
+
+static void SAK(void)
+{
+	do_SAK(tty);
+#if 0
+	/*
+	 * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
+	 * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
+	 * handling.
+	 * 
+	 * We should do this some day --- the whole point of a secure
+	 * attention key is that it should be guaranteed to always
+	 * work.
+	 */
+	reset_vc(fg_console);
+	do_unblank_screen();	/* not in interrupt routine? */
+#endif
+}
+
+static void do_ignore(unsigned char value, char up_flag)
+{
+}
+
+static void do_null()
+{
+	compute_shiftstate();
+}
+
+static void do_spec(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	if (value >= SIZE(spec_fn_table))
+		return;
+	spec_fn_table[value]();
+}
+
+static void do_lowercase(unsigned char value, char up_flag)
+{
+	printk("keyboard.c: do_lowercase was called - impossible\n");
+}
+
+static void do_self(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;		/* no action, if this is a key release */
+
+	if (diacr)
+		value = handle_diacr(value);
+
+	if (dead_key_next) {
+		dead_key_next = 0;
+		diacr = value;
+		return;
+	}
+
+	put_queue(value);
+}
+
+#define A_GRAVE  '`'
+#define A_ACUTE  '\''
+#define A_CFLEX  '^'
+#define A_TILDE  '~'
+#define A_DIAER  '"'
+static unsigned char ret_diacr[] =
+	{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
+
+/* If a dead key pressed twice, output a character corresponding to it,	*/
+/* otherwise just remember the dead key.				*/
+
+static void do_dead(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+
+	value = ret_diacr[value];
+	if (diacr == value) {   /* pressed twice */
+		diacr = 0;
+		put_queue(value);
+		return;
+	}
+	diacr = value;
+}
+
+
+/* If space is pressed, return the character corresponding the pending	*/
+/* dead key, otherwise try to combine the two.				*/
+
+unsigned char handle_diacr(unsigned char ch)
+{
+	int d = diacr;
+	int i;
+
+	diacr = 0;
+	if (ch == ' ')
+		return d;
+
+	for (i = 0; i < accent_table_size; i++) {
+		if (accent_table[i].diacr == d && accent_table[i].base == ch)
+			return accent_table[i].result;
+	}
+
+	put_queue(d);
+	return ch;
+}
+
+static void do_cons(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	want_console = value;
+}
+
+static void do_fn(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	if (value < SIZE(func_table)) {
+		if (func_table[value])
+			puts_queue(func_table[value]);
+	} else
+		printk("do_fn called with value=%d\n", value);
+}
+
+static void do_pad(unsigned char value, char up_flag)
+{
+	static const char *pad_chars = "0123456789+-*/\015,.?";
+	static const char *app_map = "pqrstuvwxylSRQMnn?";
+
+	if (up_flag)
+		return;		/* no action, if this is a key release */
+
+	/* kludge... shift forces cursor/number keys */
+	if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
+		applkey(app_map[value], 1);
+		return;
+	}
+
+	if (!vc_kbd_led(kbd,VC_NUMLOCK))
+		switch (value) {
+			case KVAL(K_PCOMMA):
+			case KVAL(K_PDOT):
+				do_fn(KVAL(K_REMOVE), 0);
+				return;
+			case KVAL(K_P0):
+				do_fn(KVAL(K_INSERT), 0);
+				return;
+			case KVAL(K_P1):
+				do_fn(KVAL(K_SELECT), 0);
+				return;
+			case KVAL(K_P2):
+				do_cur(KVAL(K_DOWN), 0);
+				return;
+			case KVAL(K_P3):
+				do_fn(KVAL(K_PGDN), 0);
+				return;
+			case KVAL(K_P4):
+				do_cur(KVAL(K_LEFT), 0);
+				return;
+			case KVAL(K_P6):
+				do_cur(KVAL(K_RIGHT), 0);
+				return;
+			case KVAL(K_P7):
+				do_fn(KVAL(K_FIND), 0);
+				return;
+			case KVAL(K_P8):
+				do_cur(KVAL(K_UP), 0);
+				return;
+			case KVAL(K_P9):
+				do_fn(KVAL(K_PGUP), 0);
+				return;
+			case KVAL(K_P5):
+				applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
+				return;
+		}
+
+	put_queue(pad_chars[value]);
+	if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+		put_queue(10);
+}
+
+static void do_cur(unsigned char value, char up_flag)
+{
+	static const char *cur_chars = "BDCA";
+	if (up_flag)
+		return;
+
+	applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
+}
+
+static void do_shift(unsigned char value, char up_flag)
+{
+	int old_state = shift_state;
+
+	if (rep)
+		return;
+
+	/* Mimic typewriter:
+	   a CapsShift key acts like Shift but undoes CapsLock */
+	if (value == KVAL(K_CAPSSHIFT)) {
+		value = KVAL(K_SHIFT);
+		if (!up_flag)
+			clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+	}
+
+	if (up_flag) {
+		/* handle the case that two shift or control
+		   keys are depressed simultaneously */
+		if (k_down[value])
+			k_down[value]--;
+	} else
+		k_down[value]++;
+
+	if (k_down[value])
+		shift_state |= (1 << value);
+	else
+		shift_state &= ~ (1 << value);
+
+	/* kludge, no joke... */
+	if (up_flag && shift_state != old_state && npadch != -1) {
+		put_queue(npadch & 0xff);
+		npadch = -1;
+	}
+}
+
+/* called after returning from RAW mode or when changing consoles -
+   recompute k_down[] and shift_state from key_down[] */
+/* maybe called when keymap is undefined, so that shiftkey release is seen */
+void compute_shiftstate(void)
+{
+	int i, j, k, sym, val;
+
+	shift_state = 0;
+	for(i=0; i < SIZE(k_down); i++)
+	  k_down[i] = 0;
+
+	for(i=0; i < SIZE(key_down); i++)
+	  if(key_down[i]) {	/* skip this word if not a single bit on */
+	    k = i*BITS_PER_LONG;
+	    for(j=0; j<BITS_PER_LONG; j++,k++)
+	      if(test_bit(k, key_down)) {
+		sym = U(plain_map[k]);
+		if(KTYP(sym) == KT_SHIFT) {
+		  val = KVAL(sym);
+		  if (val == KVAL(K_CAPSSHIFT))
+		    val = KVAL(K_SHIFT);
+		  k_down[val]++;
+		  shift_state |= (1<<val);
+		}
+	      }
+	  }
+}
+
+static void do_meta(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+
+	if (vc_kbd_mode(kbd, VC_META)) {
+		put_queue('\033');
+		put_queue(value);
+	} else
+		put_queue(value | 0x80);
+}
+
+static void do_ascii(unsigned char value, char up_flag)
+{
+	int base;
+
+	if (up_flag)
+		return;
+
+	if (value < 10)    /* decimal input of code, while Alt depressed */
+	    base = 10;
+	else {       /* hexadecimal input of code, while AltGr depressed */
+	    value -= 10;
+	    base = 16;
+	}
+
+	if (npadch == -1)
+	  npadch = value;
+	else
+	  npadch = npadch * base + value;
+}
+
+static void do_lock(unsigned char value, char up_flag)
+{
+	if (up_flag || rep)
+		return;
+	chg_vc_kbd_lock(kbd, value);
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+
+static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char ledioctl;
+
+unsigned char getledstate(void) {
+    return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led) {
+    if (!(led & ~7)) {
+	ledioctl = led;
+	kbd->ledmode = LED_SHOW_IOCTL;
+    } else
+	kbd->ledmode = LED_SHOW_FLAGS;
+    set_leds();
+}
+
+static struct ledptr {
+    unsigned int *addr;
+    unsigned int mask;
+    unsigned char valid:1;
+} ledptrs[3];
+
+void register_leds(int console, unsigned int led,
+		   unsigned int *addr, unsigned int mask) {
+    struct kbd_struct *kbd = kbd_table + console;
+    if (led < 3) {
+	ledptrs[led].addr = addr;
+	ledptrs[led].mask = mask;
+	ledptrs[led].valid = 1;
+	kbd->ledmode = LED_SHOW_MEM;
+    } else
+	kbd->ledmode = LED_SHOW_FLAGS;
+}
+
+static inline unsigned char getleds(void){
+    struct kbd_struct *kbd = kbd_table + fg_console;
+    unsigned char leds;
+
+    if (kbd->ledmode == LED_SHOW_IOCTL)
+      return ledioctl;
+    leds = kbd->ledflagstate;
+    if (kbd->ledmode == LED_SHOW_MEM) {
+	if (ledptrs[0].valid) {
+	    if (*ledptrs[0].addr & ledptrs[0].mask)
+	      leds |= 1;
+	    else
+	      leds &= ~1;
+	}
+	if (ledptrs[1].valid) {
+	    if (*ledptrs[1].addr & ledptrs[1].mask)
+	      leds |= 2;
+	    else
+	      leds &= ~2;
+	}
+	if (ledptrs[2].valid) {
+	    if (*ledptrs[2].addr & ledptrs[2].mask)
+	      leds |= 4;
+	    else
+	      leds &= ~4;
+	}
+    }
+    return leds;
+}
+
+/*
+ * This routine is the bottom half of the keyboard interrupt
+ * routine, and runs with all interrupts enabled. It does
+ * console changing, led setting and copy_to_cooked, which can
+ * take a reasonably long time.
+ *
+ * Aside from timing (which isn't really that important for
+ * keyboard interrupts as they happen often), using the software
+ * interrupt routines for this thing allows us to easily mask
+ * this when we don't want any of the above to happen. Not yet
+ * used, but this allows for easy and efficient race-condition
+ * prevention later on.
+ */
+static void kbd_bh(void)
+{
+	unsigned char leds = getleds();
+
+	if (leds != ledstate) {
+		ledstate = leds;
+		send_cmd(SKBDCMD_SETLED);
+		send_cmd(vcleds_to_sunkbd(leds));
+	}
+}
+
+int kbd_init(void)
+{
+	int i, opt_node;
+	struct kbd_struct kbd0;
+	extern struct tty_driver console_driver;
+
+	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
+	kbd0.ledmode = LED_SHOW_FLAGS;
+	kbd0.lockstate = KBD_DEFLOCK;
+	kbd0.modeflags = KBD_DEFMODE;
+	kbd0.kbdmode = VC_XLATE;
+ 
+	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
+		kbd_table[i] = kbd0;
+
+	ttytab = console_driver.table;
+
+	/* XXX Check keyboard-click? property in 'options' PROM node XXX */
+	if(sparc_cpu_model != sun4) {
+		opt_node = prom_getchild(prom_root_node);
+		opt_node = prom_searchsiblings(opt_node, "options");
+		i = prom_getintdefault(opt_node, "keyboard-click?", -1);
+		if(i != -1)
+			sunkbd_clickp = 1;
+		else
+			sunkbd_clickp = 0;
+	} else {
+		sunkbd_clickp = 0;
+	}
+	init_bh(KEYBOARD_BH, kbd_bh);
+	mark_bh(KEYBOARD_BH);
+	return 0;
+}
+
+/* /dev/kbd support */
+
+#define KBD_QSIZE 32
+static Firm_event kbd_queue [KBD_QSIZE];
+static int kbd_head, kbd_tail;
+char kbd_opened;
+static struct wait_queue *kbd_wait;
+static struct fasync_struct *kb_fasync;
+
+void
+push_kbd (int scan)
+{
+	int next = (kbd_head + 1) % KBD_QSIZE;
+
+	if (scan == KBD_IDLE)
+		return;
+	if (next != kbd_tail){
+		kbd_queue [kbd_head].id = scan & KBD_KEYMASK;
+		kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN;
+		kbd_queue [kbd_head].time = xtime;
+		kbd_head = next;
+	}
+	if (kb_fasync)
+		kill_fasync (kb_fasync, SIGIO);
+	wake_up_interruptible (&kbd_wait);
+}
+
+static int
+kbd_read (struct inode *inode, struct file *f, char *buffer, int count)
+{
+	struct wait_queue wait = { current, NULL };
+	char *end, *p;
+
+	/* Return EWOULDBLOCK, because this is what the X server expects */
+	if (kbd_head == kbd_tail){
+		if (f->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		add_wait_queue (&kbd_wait, &wait);
+		while (kbd_head == kbd_tail && !(current->signal & ~current->blocked)){
+			current->state = TASK_INTERRUPTIBLE;
+			schedule ();
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue (&kbd_wait, &wait);
+	}
+	/* There is data in the keyboard, fill the user buffer */
+	end = buffer+count;
+	p = buffer;
+	for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){
+		*(Firm_event *)p = kbd_queue [kbd_tail];
+#ifdef KBD_DEBUG
+		printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");
+#endif
+		kbd_tail++;
+		kbd_tail %= KBD_QSIZE;
+	}
+	return p-buffer;
+}
+
+/* Needed by X */
+static int
+kbd_fasync (struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper (inode, filp, on, &kb_fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int
+kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait)
+{
+	if (sel_type != SEL_IN)
+		return 0;
+	if (kbd_head != kbd_tail)
+		return 1;
+	select_wait (&kbd_wait, wait);
+	return 0;
+}
+
+static int
+kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd){
+	case KIOCTYPE:	          /* return keyboard type */
+		if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int)))
+			return -EFAULT;
+	        *(int *) arg = sunkbd_type;
+		break;
+	case KIOCGTRANS:
+		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+			return -EFAULT;
+	        *(int *) arg = TR_UNTRANS_EVENT;
+		break;
+	case KIOCTRANS:
+		if (verify_area (VERIFY_READ, (void *) arg, sizeof (int)))
+			return -EFAULT;
+	        if (*(int *) arg != TR_UNTRANS_EVENT)
+			return -EINVAL;
+		break;
+	case KIOCLAYOUT:
+		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+			return -EFAULT;
+	        *(int *) arg = sunkbd_layout;
+		break;
+	case KIOCSDIRECT:
+		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+			return -EFAULT;
+#ifndef CODING_NEW_DRIVER
+		if (*(int *) arg)
+			kbd_redirected = fg_console + 1;
+		else
+			kbd_redirected = 0;
+		kbd_table [fg_console].kbdmode = kbd_redirected ? VC_RAW : VC_XLATE;
+#endif
+		break;
+	case KIOCCMD:
+		/* Need to support beep on/off, keyclick on/off */
+		return 0;
+	case FIONREAD:		/* return number of bytes in kbd queue */
+	{
+		int count;
+		
+		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
+			return -EFAULT;
+		count = kbd_head - kbd_tail;
+		* (int *)arg = (count < 0) ? KBD_QSIZE - count : count;
+		return 0;
+	}
+	default:
+		printk ("Unknown Keyboard ioctl: %8.8x\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+kbd_open (struct inode *i, struct file *f)
+{
+	if (kbd_opened)
+		return 0;
+	kbd_opened = fg_console + 1;
+	kbd_head = kbd_tail = 0;
+	return 0;
+}
+
+static void
+kbd_close (struct inode *i, struct file *f)
+{
+	if (kbd_redirected)
+		kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
+	kbd_redirected = 0;
+	kbd_opened = 0;
+
+	kbd_fasync (i, f, 0);
+}
+
+static struct
+file_operations kbd_fops =
+{
+	NULL,			/* seek */
+	kbd_read,		/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	kbd_select,		/* select */
+	kbd_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	kbd_open,		/* open */
+	kbd_close,		/* close */
+	NULL,			/* fsync */
+	kbd_fasync,		/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+void
+keyboard_zsinit(void)
+{
+	int timeout = 0;
+
+	/* Test out the leds */
+	sunkbd_type = 255;
+	send_cmd(SKBDCMD_RESET);
+	while((sunkbd_type==255) && timeout < 500000) {
+		udelay(100);
+		timeout += 20;
+	}
+
+	if(timeout>=500000) {
+		printk("keyboard: not present\n");
+		return;
+	}
+
+	if(sunkbd_type != SUNKBD_TYPE4) {
+		printk("Sun TYPE %d keyboard detected ", sunkbd_type);
+	} else {
+		udelay(200);
+		timeout=0;
+		while(timeout++ < 500000)
+			barrier();
+		printk("Sun TYPE %d keyboard detected ",
+		       ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4));
+	}
+	if(sunkbd_type == SUNKBD_TYPE2)
+		sunkbd_clickp = 0;
+
+	if(sunkbd_clickp)
+		printk("with keyclick\n");
+	else
+		printk("without keyclick\n");
+
+	/* Dork with led lights, then turn them all off */
+	send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */
+	send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */
+
+	/* Register the /dev/kbd interface */
+	if (register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){
+		printk ("Could not register /dev/kbd device\n");
+		return;
+	}
+	return;
+}
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunkeymap.c linux/drivers/sbus/char/sunkeymap.c
--- v1.3.95/linux/drivers/sbus/char/sunkeymap.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunkeymap.c	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf100,	0xf101,	0xf109,
+	0xf102,	0xf10a,	0xf103,	0xf10b,	0xf104,	0xf701,	0xf105,	0xf200,
+	0xf106,	0xf107,	0xf108,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf209,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf01b,	0xf031,	0xf032,
+	0xf033,	0xf034,	0xf035,	0xf036,	0xf037,	0xf038,	0xf039,	0xf030,
+	0xf02d,	0xf03d,	0xf060,	0xf07f,	0xf115,	0xf03d,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf009,	0xfb71,	0xfb77,
+	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,	0xfb70,
+	0xf05b,	0xf05d,	0xf07f,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xfb61,	0xfb73,	0xfb64,
+	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,
+	0xf05c,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xfb7a,	0xfb78,	0xfb63,	0xfb76,
+	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf700,	0xf00a,
+	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf020,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf10a,	0xf10b,	0xf113,
+	0xf10c,	0xf10a,	0xf10d,	0xf10b,	0xf10e,	0xf701,	0xf105,	0xf200,
+	0xf110,	0xf107,	0xf112,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf203,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf01b,	0xf021,	0xf040,
+	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,	0xf02a,	0xf028,	0xf029,
+	0xf05f,	0xf02b,	0xf07e,	0xf07f,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf009,	0xfb51,	0xfb57,
+	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,	0xfb4f,	0xfb50,
+	0xf07b,	0xf07d,	0xf07f,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xfb41,	0xfb53,	0xfb44,
+	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,
+	0xf07c,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
+	0xf20b,	0xf200,	0xf208,	0xf700,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
+	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf200,
+	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf020,	0xf200,	0xf20a,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf50c,	0xf50d,	0xf515,
+	0xf50e,	0xf516,	0xf50f,	0xf517,	0xf510,	0xf701,	0xf200,	0xf200,
+	0xf512,	0xf513,	0xf514,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf202,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf040,
+	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,	0xf05b,	0xf05d,	0xf07d,
+	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xfb71,	0xfb77,
+	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,	0xfb70,
+	0xf200,	0xf07e,	0xf200,	0xf20e,	0xf911,	0xf912,	0xf913,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf914,	0xfb73,	0xf917,
+	0xf919,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,
+	0xf200,	0xf201,	0xf30e,	0xf90e,	0xf90f,	0xf910,	0xf90a,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
+	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf90b,	0xf90c,	0xf90d,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf100,	0xf101,	0xf109,
+	0xf102,	0xf10a,	0xf103,	0xf10b,	0xf104,	0xf701,	0xf200,	0xf200,
+	0xf107,	0xf200,	0xf108,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf204,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf000,
+	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,	0xf07f,	0xf200,	0xf200,
+	0xf01f,	0xf200,	0xf000,	0xf008,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xf011,	0xf017,
+	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,
+	0xf01b,	0xf01d,	0xf008,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf001,	0xf013,	0xf004,
+	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,
+	0xf01c,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf200,
+	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf000,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf701,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf200,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf000,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xf011,	0xf017,
+	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,
+	0xf200,	0xf200,	0xf200,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf001,	0xf013,	0xf004,
+	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,
+	0xf200,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf500,	0xf501,	0xf509,
+	0xf502,	0xf50a,	0xf503,	0xf50b,	0xf504,	0xf701,	0xf505,	0xf200,
+	0xf507,	0xf200,	0xf508,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf209,
+	0xf210,	0xf200,	0xf200,	0xf600,	0xf211,	0xf81b,	0xf831,	0xf832,
+	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,	0xf838,	0xf839,	0xf830,
+	0xf82d,	0xf83d,	0xf860,	0xf87f,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf809,	0xf871,	0xf877,
+	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,	0xf86f,	0xf870,
+	0xf85b,	0xf85d,	0xf200,	0xf87f,	0xf907,	0xf908,	0xf909,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf861,	0xf873,	0xf864,
+	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,
+	0xf85c,	0xf80d,	0xf30e,	0xf904,	0xf905,	0xf906,	0xf900,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xf87a,	0xf878,	0xf863,	0xf876,
+	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf200,
+	0xf901,	0xf902,	0xf903,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf820,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf500,	0xf501,	0xf509,
+	0xf502,	0xf50a,	0xf503,	0xf50b,	0xf504,	0xf701,	0xf200,	0xf200,
+	0xf507,	0xf200,	0xf508,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf200,
+	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf20c,	0xf200,	0xf114,	0xf200,	0xf811,	0xf817,
+	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,	0xf810,
+	0xf200,	0xf200,	0xf200,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf801,	0xf813,	0xf804,
+	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,
+	0xf200,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
+	0xf118,	0xf200,	0xf208,	0xf700,	0xf81a,	0xf818,	0xf803,	0xf816,
+	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
+	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', '\300'},	{'`', 'a', '\340'},
+	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
+	{'^', 'A', '\302'},	{'^', 'a', '\342'},
+	{'~', 'A', '\303'},	{'~', 'a', '\343'},
+	{'"', 'A', '\304'},	{'"', 'a', '\344'},
+	{'O', 'A', '\305'},	{'o', 'a', '\345'},
+	{'0', 'A', '\305'},	{'0', 'a', '\345'},
+	{'A', 'A', '\305'},	{'a', 'a', '\345'},
+	{'A', 'E', '\306'},	{'a', 'e', '\346'},
+	{',', 'C', '\307'},	{',', 'c', '\347'},
+	{'`', 'E', '\310'},	{'`', 'e', '\350'},
+	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
+	{'^', 'E', '\312'},	{'^', 'e', '\352'},
+	{'"', 'E', '\313'},	{'"', 'e', '\353'},
+	{'`', 'I', '\314'},	{'`', 'i', '\354'},
+	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
+	{'^', 'I', '\316'},	{'^', 'i', '\356'},
+	{'"', 'I', '\317'},	{'"', 'i', '\357'},
+	{'-', 'D', '\320'},	{'-', 'd', '\360'},
+	{'~', 'N', '\321'},	{'~', 'n', '\361'},
+	{'`', 'O', '\322'},	{'`', 'o', '\362'},
+	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
+	{'^', 'O', '\324'},	{'^', 'o', '\364'},
+	{'~', 'O', '\325'},	{'~', 'o', '\365'},
+	{'"', 'O', '\326'},	{'"', 'o', '\366'},
+	{'/', 'O', '\330'},	{'/', 'o', '\370'},
+	{'`', 'U', '\331'},	{'`', 'u', '\371'},
+	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
+	{'^', 'U', '\333'},	{'^', 'u', '\373'},
+	{'"', 'U', '\334'},	{'"', 'u', '\374'},
+	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
+	{'T', 'H', '\336'},	{'t', 'h', '\376'},
+	{'s', 's', '\337'},	{'"', 'y', '\377'},
+	{'s', 'z', '\337'},	{'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunkeymap.map linux/drivers/sbus/char/sunkeymap.map
--- v1.3.95/linux/drivers/sbus/char/sunkeymap.map	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunkeymap.map	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,372 @@
+# Keyboard map for the Sun Type4/Type5 keyboards
+# found on SparcStations
+keymaps 0-2,4-5,8,12
+#
+#
+# Stop/L1
+keycode	0x01 =
+# SND_LOWER
+keycode	0x02 =
+# Again/L2
+keycode	0x03 =
+# SND_LOUDER
+keycode	0x04 =
+keycode	0x05 = F1			F11	Console_13
+	control	keycode			0x05 = F1
+	alt	keycode			0x05 = Console_1
+	control	alt	keycode		0x05 = Console_1
+keycode	0x06 = F2			F12	Console_14
+	control	keycode			0x06 = F2
+	alt	keycode			0x06 = Console_2
+	control	alt	keycode		0x06 = Console_2
+keycode	0x07 = F10			F20	Console_22
+	control	keycode			0x07 = F10
+	alt	keycode			0x07 = Console_10
+	control	alt	keycode		0x07 = Console_10
+keycode	0x08 = F3			F13	Console_15
+	control	keycode			0x08 = F3
+	alt	keycode			0x08 = Console_3
+	control	alt	keycode		0x08 = Console_3
+keycode	0x09 = F11			F11	Console_23
+	control	keycode			0x09 = F11
+	alt	keycode			0x09 = Console_11
+	control	alt	keycode		0x09 = Console_11
+keycode	0x0a = F4			F14	Console_16
+	control	keycode			0x0a = F4
+	alt	keycode			0x0a = Console_4
+	control	alt	keycode		0x0a = Console_4
+keycode	0x0b = F12			F12	Console_24
+	control	keycode			0x0b = F12
+	alt	keycode			0x0b = Console_12
+	control	alt	keycode		0x0b = Console_12
+keycode	0x0c = F5			F15	Console_17
+	control	Keycode			0x0c = F5
+	alt	keycode			0x0c = Console_5
+	control	alt	keycode		0x0c = Console_5
+keycode	0x0d = AltGr
+keycode 0x0e = F6			F6
+	alt	keycode			0x0e = Console_6
+# BLANK KEY on type 5 keyboards
+keycode 0x0f =
+keycode 0x10 = F7			F17	Console_19
+	control	Keycode			0x10 = F7
+	alt	keycode			0x10 = Console_7
+	control	alt	keycode		0x10 = Console_7
+keycode 0x11 = F8			F8	Console_20
+	control	keycode			0x10 = F8
+	alt	keycode			0x10 = Console_8
+	control	alt	keycode		0x10 = Console_8
+keycode 0x12 = F9			F19	Console_21
+	control	keycode			0x12 = F9
+	alt	keycode			0x12 = Console_9
+	control	alt	keycode		0x12 = Console_9
+keycode 0x13 = Alt
+keycode 0x14 = Up
+keycode 0x15 = Pause
+# Print Screen
+keycode 0x16 = 
+keycode 0x17 = Scroll_Lock	Show_Memory	Show_Registers
+	control	keycode				0x17 = Show_State
+	alt	keycode				0x17 = Scroll_Lock
+keycode 0x18 = Left
+	alt	keycode				0x18 = Decr_Console
+# Props/L3
+keycode 0x19 =
+# UNDO/L4
+keycode 0x1a =
+keycode 0x1b = Down
+keycode 0x1c = Right
+	alt	keycode				0x1c = Incr_Console
+keycode 0x1d = Escape		Escape
+	alt	keycode				0x1d = Meta_Escape
+keycode 0x1e = one		exclam
+	alt	keycode				0x1e = Meta_one
+keycode 0x1f = two		at		at
+	control	keycode				0x1f = nul
+	shift	control	keycode			0x1f = nul
+	alt	keycode				0x1f = Meta_two
+keycode 0x20 = three		numbersign
+	control	keycode				0x20 = Escape
+	alt	keycode				0x20 = Meta_three
+keycode 0x21 = four		dollar		dollar
+	control	keycode				0x21 = Control_backslash
+	alt	keycode				0x21 = Meta_four
+keycode 0x22 = five		percent
+	control	keycode				0x22 = Control_bracketright
+	alt	keycode				0x22 = Meta_five
+keycode 0x23 = six		asciicircum
+	control	keycode				0x23 = Control_asciicircum
+	alt	keycode				0x23 = Meta_six
+keycode 0x24 = seven		ampersand	braceleft
+	control	keycode				0x24 = Control_underscore
+	alt	keycode				0x24 = Meta_seven
+keycode 0x25 = eight		asterisk	bracketleft
+	control	keycode				0x25 = Delete
+	alt	keycode				0x25 = Meta_eight
+keycode 0x26 = nine		parenleft	bracketright
+	alt	keycode				0x26 = Meta_nine
+keycode 0x27 = zero		parenright	braceright
+	alt	keycode				0x27 = Meta_zero
+keycode 0x28 = minus		underscore	backslash
+	control	keycode				0x28 = Control_underscore
+	shift	control	keycode			0x28 = Control_underscore
+	alt	keycode				0x28 = Meta_minus
+keycode 0x29 = equal		plus
+	alt	keycode				0x29 = Meta_equal
+keycode 0x2a = grave		asciitilde
+	control	keycode				0x2a = nul
+	alt	keycode				0x2a = Meta_grave
+# Is marked as BackSpace but we define it as delete just like the i386
+# keyboard maps does
+keycode 0x2b = Delete		Delete
+	control	keycode				0x2b = BackSpace
+	alt	keycode				0x2b = Meta_Delete
+keycode 0x2c = Insert
+# This is really keypad = on type 4 keyboards
+keycode 0x2d = equal
+keycode 0x2e = KP_Divide
+keycode 0x2f = KP_Multiply
+# Power ON/OFF key on type 5 keyboard
+keycode 0x30 =
+# FRONT/L5
+keycode 0x31 = 
+keycode 0x32 = KP_Period
+#	altgr	control	keycode			0x32 = Boot
+	control	alt	keycode			0x32 = Boot
+# COPY/L6
+keycode 0x33 =
+# Home key, same difference
+keycode 0x34 = Find
+keycode 0x35 = Tab		Tab
+	alt	keycode				0x35 = Meta_Tab
+keycode 0x36 = q
+keycode 0x37 = w
+keycode 0x38 = e
+	altgr	keycode				0x38 = Hex_E
+keycode 0x39 = r
+keycode 0x3a = t
+keycode 0x3b = y
+keycode 0x3c = u
+keycode 0x3d = i
+keycode 0x3e = o
+keycode 0x3f = p
+keycode 0x40 = bracketleft	braceleft
+	control	keycode				0x40 = Escape
+	alt	keycode				0x40 = Meta_bracketleft
+keycode 0x41 = bracketright	braceright	asciitilde
+	control	keycode				0x41 = Control_bracketright
+	alt	keycode				0x41 = Meta_bracketright
+keycode 0x42 = Delete		Delete
+	control	keycode				0x42 = BackSpace
+	alt	keycode				0x43 = Meta_Delete
+keycode 0x43 = Compose
+keycode 0x44 = KP_7
+	alt	keycode				0x44 = Ascii_7
+	altgr	keycode				0x44 = Hex_7
+keycode 0x45 = KP_8
+	alt	keycode				0x45 = Ascii_8
+	altgr	keycode				0x45 = Hex_8
+keycode 0x46 = KP_9
+	alt	keycode				0x46 = Ascii_9
+	altgr	keycode				0x46 = Hex_9
+keycode 0x47 = KP_Subtract
+# OPEN/L6
+keycode 0x48 = 
+# PASTE/L8
+keycode 0x49 =
+keycode 0x4a = Select
+# No key produces 0x4b to my knowledge
+keycode 0x4b =
+keycode 0x4c = Control
+keycode 0x4d = a
+	altgr	keycode				0x4d = Hex_A
+keycode 0x4e = s
+keycode 0x4f = d
+	altgr	keycode				0x4f = Hex_D
+keycode 0x50 = f
+	altgr	keycode				0x50 = Hex_F
+keycode 0x51 = g
+keycode 0x52 = h
+keycode 0x53 = j
+keycode 0x54 = k
+keycode 0x55 = l
+keycode 0x56 = semicolon	colon
+	alt	keycode				0x56 = Meta_semicolon
+keycode 0x57 = apostrophe	quotedbl
+	control	keycode				0x57 = Control_g
+	alt	keycode				0x57 = Meta_apostrophe
+keycode 0x58 = backslash	bar
+	control	keycode				0x58 = Control_backslash
+	alt	keycode				0x58 = Meta_backslash
+keycode 0x59 = Return
+	alt	keycode				0x59 = Meta_Control_m
+keycode 0x5a = KP_Enter
+keycode 0x5b = KP_4
+	alt	keycode				0x5b = Ascii_4
+	altgr	keycode				0x5b = Hex_4
+keycode 0x5c = KP_5
+	alt	keycode				0x5c = Ascii_5
+	altgr	keycode				0x5c = Hex_5
+keycode 0x5d = KP_6
+	alt	keycode				0x5d = Ascii_6
+	altgr	keycode				0x5d = Hex_6
+keycode 0x5e = KP_0
+	alt	keycode				0x5e = Ascii_0
+	altgr	keycode				0x5e = Hex_0
+# FIND/L9
+keycode 0x5f =
+keycode 0x60 = Prior
+	shift	keycode				0x60 = Scroll_Backward
+# CUT/L10
+keycode 0x61 =
+keycode 0x62 = Num_Lock
+# Linux/i386 console makes no distinction between right/left shift
+# so neither do we.
+keycode 0x63 = Shift
+keycode 0x64 = z
+keycode 0x65 = x
+keycode 0x66 = c
+	altgr	keycode				0x66 = Hex_C
+keycode 0x67 = v
+keycode 0x68 = b
+	altgr	keycode				0x68 = Hex_B
+keycode 0x69 = n
+keycode 0x6a = m
+keycode 0x6b = comma		less
+	alt	keycode				0x6b = Meta_comma
+keycode 0x6c = period		greater
+	control	keycode				0x6c = Compose
+	alt	keycode				0x6c = Meta_period
+keycode 0x6d = slash		question
+	control	keycode				0x6d = Delete
+	alt	keycode				0x6d = Meta_slash
+keycode 0x6e = Shift
+keycode 0x6f = Linefeed
+keycode 0x70 = KP_1
+	alt	keycode				0x70 = Ascii_1
+	altgr	keycode				0x70 = Hex_1
+keycode 0x71 = KP_2
+	alt	keycode				0x71 = Ascii_2
+	altgr	keycode				0x71 = Hex_2
+keycode 0x72 = KP_3
+	alt	keycode				0x72 = Ascii_3
+	altgr	keycode				0x72 = Hex_3
+# To my knowledge no key produces 0x73, 0x74, or 0x75
+keycode 0x73 =
+keycode 0x74 =
+keycode 0x75 =
+keycode 0x76 = Help
+keycode 0x77 = Caps_Lock
+# A True Meta-key, unused at this time
+keycode 0x78 =
+keycode 0x79 = space		space
+	control	keycode				0x79 = nul
+	alt	keycode				0x79 = Meta_space
+# Another real Meta-key, again unused
+keycode 0x7a =
+keycode 0x7b = Next
+	shift	keycode				0x7b = Scroll_Forward
+# No keys produce the following
+keycode 0x7c =
+keycode 0x7d = KP_Add
+keycode 0x7e =
+# keycode 0x7f is special and it means 'all keys released' and is
+# taken care of within the sun keyboard driver itself
+keycode 0x7f =
+# Thats all folks...
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v1.3.95/linux/drivers/sbus/char/sunmouse.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunmouse.c	Thu Apr 25 13:27:42 1996
@@ -0,0 +1,420 @@
+/* sunmouse.c: Sun mouse driver for the Sparc
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Parts based on the psaux.c driver written by:
+ * Johan Myreen.
+ *
+ * Dec/19/95 Added SunOS mouse ioctls - miguel.
+ * Jan/5/96  Added VUID support, sigio support - miguel.
+ * Mar/5/96  Added proper mouse stream support - miguel.
+ */
+
+/* The mouse is run off of one of the Zilog serial ports.  On
+ * that port is the mouse and the keyboard, each gets a zs channel.
+ * The mouse itself is mouse-systems in nature.  So the protocol is:
+ *
+ * Byte 1) Button state which is bit-encoded as
+ *            0x4 == left-button down, else up
+ *            0x2 == middle-button down, else up
+ *            0x1 == right-button down, else up
+ *
+ * Byte 2) Delta-x
+ * Byte 3) Delta-y
+ * Byte 4) Delta-x again
+ * Byte 5) Delta-y again
+ *
+ * One day this driver will have to support more than one mouse in the system.
+ *
+ * This driver has two modes of operation: the default VUID_NATIVE is
+ * set when the device is opened and allows the application to see the
+ * mouse character stream as we get it from the serial (for gpm for
+ * example).  The second method, VUID_FIRM_EVENT will provide cooked
+ * events in Firm_event records.
+ * */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fcntl.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/vuid_event.h>
+#include <linux/random.h>
+/* The following keeps track of software state for the Sun
+ * mouse.
+ */
+#define STREAM_SIZE   2048
+#define EV_SIZE       (STREAM_SIZE/sizeof (Firm_event))
+#define BUTTON_LEFT   4
+#define BUTTON_MIDDLE 2
+#define BUTTON_RIGHT  1
+
+struct sun_mouse {
+	unsigned char transaction[5];  /* Each protocol transaction */
+	unsigned char byte;            /* Counter, starts at 0 */
+	unsigned char button_state;    /* Current button state */
+	unsigned char prev_state;      /* Previous button state */
+	int delta_x;                   /* Current delta-x */
+	int delta_y;                   /* Current delta-y */
+	int present;
+	int ready;		       /* set if there if data is available */
+	int active;		       /* set if device is open */
+        int vuid_mode;	               /* VUID_NATIVE or VUID_FIRM_EVENT */
+	struct wait_queue *proc_list;
+	struct fasync_struct *fasync;
+	
+	/* The event/stream queue */
+	unsigned int head;
+	unsigned int tail;
+	union {
+		char stream [STREAM_SIZE];
+		Firm_event ev [0];
+	} queue;
+};
+
+static struct sun_mouse sunmouse;
+#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
+#define bstate sunmouse.button_state
+#define pstate sunmouse.prev_state
+
+extern void mouse_put_char(char ch);
+
+/* #define SMOUSE_DEBUG */
+
+static void
+push_event (Firm_event *ev)
+{
+	int next = (sunmouse.head + 1) % EV_SIZE;
+	
+	if (next != sunmouse.tail){
+		sunmouse.queue.ev [sunmouse.head] = *ev;
+		sunmouse.head = next;
+	}
+}
+
+static int
+queue_empty (void)
+{
+	return sunmouse.head == sunmouse.tail;
+}
+
+static Firm_event *
+get_from_queue (void)
+{
+	Firm_event *result;
+	
+	result = &sunmouse.queue.ev [sunmouse.tail];
+	sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
+	return result;
+}
+
+static void
+push_char (char c)
+{
+	int next = (sunmouse.head + 1) % STREAM_SIZE;
+
+	if (next != sunmouse.tail){
+		sunmouse.queue.stream [sunmouse.head] = c;
+		sunmouse.head = next;
+	}
+	sunmouse.ready = 1;
+	if (sunmouse.fasync)
+		kill_fasync (sunmouse.fasync, SIGIO);
+	wake_up_interruptible (&sunmouse.proc_list);
+}
+
+/* The following is called from the zs driver when bytes are received on
+ * the Mouse zs8530 channel.
+ */
+void
+sun_mouse_inbyte(unsigned char byte, unsigned char status)
+{
+	signed char mvalue;
+	int d;
+	Firm_event ev;
+
+	add_mouse_randomness (byte);
+	if(!sunmouse.active)
+		return;
+
+	if (!gen_events){
+		push_char (byte);
+		return;
+	}
+	/* Check for framing errors and parity errors */
+	/* XXX TODO XXX */
+
+	/* If the mouse sends us a byte from 0x80 to 0x87
+	 * we are starting at byte zero in the transaction
+	 * protocol.
+	 */
+	if(byte >= 0x80 && byte <= 0x87)
+		sunmouse.byte = 0;
+
+	mvalue = (signed char) byte;
+	switch(sunmouse.byte) {
+	case 0:
+		/* Button state */
+		sunmouse.button_state = (~byte) & 0x7;
+#ifdef SMOUSE_DEBUG
+		printk("B<Left %s, Middle %s, Right %s>",
+		       ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
+		       ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
+		       ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
+#endif
+		sunmouse.byte++;
+		return;
+	case 1:
+		/* Delta-x 1 */
+#ifdef SMOUSE_DEBUG
+		printk("DX1<%d>", mvalue);
+#endif
+		sunmouse.delta_x = mvalue;
+		sunmouse.byte++;
+		return;
+	case 2:
+		/* Delta-y 1 */
+#ifdef SMOUSE_DEBUG
+		printk("DY1<%d>", mvalue);
+#endif
+		sunmouse.delta_y = mvalue;
+		sunmouse.byte++;
+		return;
+	case 3:
+		/* Delta-x 2 */
+#ifdef SMOUSE_DEBUG
+		printk("DX2<%d>", mvalue);
+#endif
+		sunmouse.delta_x += mvalue;
+		sunmouse.byte++;
+		return;
+	case 4:
+		/* Last byte, Delta-y 2 */
+#ifdef SMOUSE_DEBUG
+		printk("DY2<%d>", mvalue);
+#endif
+		sunmouse.delta_y += mvalue;
+		sunmouse.byte = 69;  /* Some ridiculous value */
+		break;
+	case 69:
+		/* Until we get the (0x80 -> 0x87) value we aren't
+		 * in the middle of a real transaction, so just
+		 * return.
+		 */
+		return;
+	default:
+		printk("sunmouse: bogon transaction state\n");
+		sunmouse.byte = 69;  /* What could cause this? */
+		return;
+	};
+	d = bstate ^ pstate;
+	pstate = bstate;
+	if (d){
+		if (d & BUTTON_LEFT){
+			ev.id = MS_LEFT;
+			ev.value = bstate & BUTTON_LEFT;
+		}
+		if (d & BUTTON_RIGHT){
+			ev.id = MS_RIGHT;
+			ev.value = bstate & BUTTON_RIGHT;
+		}
+		if (d & BUTTON_MIDDLE){
+			ev.id = MS_MIDDLE;
+			ev.value = bstate & BUTTON_MIDDLE;
+		}
+		ev.time = xtime;
+		ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
+		push_event (&ev);
+	}
+	if (sunmouse.delta_x){
+		ev.id = LOC_X_DELTA;
+		ev.time = xtime;
+		ev.value = sunmouse.delta_x;
+		push_event (&ev);
+		sunmouse.delta_x = 0;
+	}
+	if (sunmouse.delta_y){
+		ev.id = LOC_Y_DELTA;
+		ev.time = xtime;
+		ev.value = sunmouse.delta_y;
+		push_event (&ev);
+	}
+	
+        /* We just completed a transaction, wake up whoever is awaiting
+	 * this event.
+	 */
+	sunmouse.ready = 1;
+	if (sunmouse.fasync)
+		kill_fasync (sunmouse.fasync, SIGIO);
+	wake_up_interruptible(&sunmouse.proc_list);
+	return;
+}
+
+static int
+sun_mouse_open(struct inode * inode, struct file * file)
+{
+	if(!sunmouse.present)
+		return -EINVAL;
+	if(sunmouse.active)
+		return -EBUSY;
+	sunmouse.active = 1;
+	sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
+	sunmouse.button_state = 0x80;
+	sunmouse.vuid_mode = VUID_NATIVE;
+	return 0;
+}
+
+static int
+sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static void
+sun_mouse_close(struct inode *inode, struct file *file)
+{
+	sunmouse.active = sunmouse.ready = 0;
+	sun_mouse_fasync (inode, file, 0);
+}
+
+static int
+sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
+		int count)
+{
+	return -EINVAL;  /* foo on you */
+}
+
+static int
+sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
+	       int count)
+{
+	struct wait_queue wait = { current, NULL };
+
+	if (queue_empty ()){
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		add_wait_queue (&sunmouse.proc_list, &wait);
+		while (queue_empty () && !(current->signal & ~current->blocked)){
+			current->state = TASK_INTERRUPTIBLE;
+			schedule ();
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue (&sunmouse.proc_list, &wait);
+	}
+	if (gen_events){
+		char *p = buffer, *end = buffer+count;
+		
+		while (p < end && !queue_empty ()){
+			*(Firm_event *)p = *get_from_queue ();
+			p += sizeof (Firm_event);
+		}
+		sunmouse.ready = !queue_empty ();
+		inode->i_atime = CURRENT_TIME;
+		return p-buffer;
+	} else {
+		int c;
+		
+		for (c = count; !queue_empty () && c; c--){
+			*buffer++ = sunmouse.queue.stream [sunmouse.tail];
+			sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
+		}
+		sunmouse.ready = !queue_empty ();
+		inode->i_atime = CURRENT_TIME;
+		return count-c;
+	}
+	/* Only called if nothing was sent */
+	if (current->signal & ~current->blocked)
+		return -ERESTARTSYS;
+	return 0;
+}
+
+static int
+sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
+			    select_table *wait)
+{
+	if(sel_type != SEL_IN)
+		return 0;
+	if(sunmouse.ready)
+		return 1;
+	select_wait(&sunmouse.proc_list, wait);
+	return 0;
+}
+int
+sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int i;
+	
+	switch (cmd){
+		/* VUIDGFORMAT - Get input device byte stream format */
+	case _IOR('v', 2, int):
+		i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
+		if (i) return i;
+		*(int *)arg = sunmouse.vuid_mode;
+		break;
+
+		/* VUIDSFORMAT - Set input device byte stream format*/
+	case _IOW('v', 1, int):
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
+	        if (i) return i;
+		i = *(int *) arg;
+		if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
+			sunmouse.vuid_mode = *(int *)arg;
+			sunmouse.head = sunmouse.tail = 0;
+		} else
+			return -EINVAL;
+		break;
+		
+	default:
+		printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
+		return -1;
+	}
+	return 0;
+}
+
+struct file_operations sun_mouse_fops = {
+	NULL,
+	sun_mouse_read,
+	sun_mouse_write,
+	NULL,
+	sun_mouse_select,
+	sun_mouse_ioctl,
+	NULL,
+	sun_mouse_open,
+	sun_mouse_close,
+	NULL,
+	sun_mouse_fasync,
+};
+
+static struct miscdevice sun_mouse_mouse = {
+	SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
+};
+
+int
+sun_mouse_init(void)
+{
+	printk("Sun Mouse-Systems mouse driver version 1.00\n");
+	sunmouse.present = 1;
+	sunmouse.ready = sunmouse.active = 0;
+	misc_register (&sun_mouse_mouse);
+	sunmouse.delta_x = sunmouse.delta_y = 0;
+	sunmouse.button_state = 0x80;
+	sunmouse.proc_list = NULL;
+	return 0;
+}
+
+void
+sun_mouse_zsinit(void)
+{
+	sunmouse.ready = 1;
+}
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v1.3.95/linux/drivers/sbus/char/sunserial.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunserial.c	Thu Apr 25 13:27:43 1996
@@ -0,0 +1,2196 @@
+/* serial.c: Serial port driver for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#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/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/delay.h>
+#include <asm/kdebug.h>
+
+#include "sunserial.h"
+
+#define NUM_SERIAL 2     /* Two chips on board. */
+#define NUM_CHANNELS (NUM_SERIAL * 2)
+
+#define KEYBOARD_LINE 0x2
+#define MOUSE_LINE    0x3
+
+struct sun_zslayout *zs_chips[NUM_SERIAL] = { 0, 0, };
+struct sun_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, 0, 0, };
+struct sun_zschannel *zs_conschan;
+struct sun_zschannel *zs_mousechan;
+struct sun_zschannel *zs_kbdchan;
+struct sun_zschannel *zs_kgdbchan;
+int zs_nodes[NUM_SERIAL] = { 0, 0, };
+
+struct sun_serial zs_soft[NUM_CHANNELS];
+struct sun_serial *zs_chain;  /* IRQ servicing chain */
+int zilog_irq;
+
+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;
+static struct l1a_kbd_state l1a_state = { 0, 0 };
+struct sun_serial *zs_consinfo = 0;
+
+/* Keyboard defines for L1-A processing... */
+#define SUNKBD_RESET   0xff
+#define SUNKBD_L1      0x01
+#define SUNKBD_UP      0x80
+#define SUNKBD_A       0x4d
+
+extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+extern void sun_mouse_inbyte(unsigned char byte, unsigned char status);
+
+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 */
+	0, 0,                        /* BRG time constant, write 12 + 13 */
+	(BRSRC | BRENABL),           /* write 14 */
+	(DCDIE)                      /* write 15 */
+};
+
+#define ZS_CLOCK         4915200   /* Zilog input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+  
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* 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 change_speed(struct sun_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * 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;
+
+static inline int serial_paranoia_check(struct sun_serial *info,
+					dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"Warning: null sun_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * 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 Zilog8530 registers.  The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ */
+static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned char reg)
+{
+	unsigned char retval;
+
+	channel->control = reg;
+	udelay(5);
+	retval = channel->control;
+	udelay(5);
+	return retval;
+}
+
+static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value)
+{
+	channel->control = reg;
+	udelay(5);
+	channel->control = value;
+	udelay(5);
+	return;
+}
+
+static inline void load_zsregs(struct sun_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 sun_serial *ss, int set)
+{
+	if(set) {
+		ss->curregs[5] |= (RTS | DTR);
+		ss->pendregs[5] = ss->curregs[5];
+		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+	} else {
+		ss->curregs[5] &= ~(RTS | DTR);
+		ss->pendregs[5] = ss->curregs[5];
+		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+	}
+	return;
+}
+
+static inline void kgdb_chaninit(struct sun_serial *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 & 255);
+	kgdb_regs[R13] = ((brg >> 8) & 255);
+	load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct sun_serial *ss)
+{
+	struct sun_zschannel *channel = ss->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)&0xff) << 8);
+	brg |= (read_zsreg(channel, 12)&0xff);
+	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->curregs[5] & TxENAB) {
+		info->curregs[5] &= ~TxENAB;
+		info->pendregs[5] &= ~TxENAB;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+		info->curregs[5] |= TxENAB;
+		info->pendregs[5] = info->curregs[5];
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+	/* If we are doing kadb, we call the debugger
+	 * else we just drop into the boot monitor.
+	 * Note that we must flush the user windows
+	 * first before giving up control.
+	 */
+	printk("\n");
+	flush_user_windows();
+	if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&
+	   (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
+		sp_enter_debugger();
+	else
+		prom_halt();
+
+	/* XXX We want to notify the keyboard driver that all
+	 * XXX keys are in the up state or else weird things
+	 * XXX happen...
+	 */
+
+	return;
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct sun_zschannel *zsc)
+{
+	zsc->control = ERR_RES;
+	udelay(5);
+	zsc->control = RES_H_IUS;
+	udelay(5);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct sun_serial *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task_irq_off(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, stat;
+
+	ch = info->zs_channel->data;
+	udelay(5);
+	stat = read_zsreg(info->zs_channel, R1);
+	udelay(5);
+
+	/* If this is the console keyboard, we need to handle
+	 * L1-A's here.
+	 */
+	if(info->cons_keyb) {
+		if(ch == SUNKBD_RESET) {
+			l1a_state.kbd_id = 1;
+			l1a_state.l1_down = 0;
+		} else if(l1a_state.kbd_id) {
+			l1a_state.kbd_id = 0;
+		} else if(ch == SUNKBD_L1) {
+			l1a_state.l1_down = 1;
+		} else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+			l1a_state.l1_down = 0;
+		} else if(ch == SUNKBD_A && l1a_state.l1_down) {
+			/* whee... */
+			batten_down_hatches();
+			/* Clear the line and continue execution... */
+			rs_recv_clear(info->zs_channel);
+			l1a_state.l1_down = 0;
+			l1a_state.kbd_id = 0;
+			return;
+		}
+		rs_recv_clear(info->zs_channel);
+		sunkbd_inchar(ch, stat, regs);
+
+		return;
+	}
+	if(info->cons_mouse) {
+		rs_recv_clear(info->zs_channel);
+		sun_mouse_inbyte(ch, stat);
+		return;
+	}
+	if(info->is_cons) {
+		if(ch==0) { /* whee, break received */
+			batten_down_hatches();
+			rs_recv_clear(info->zs_channel);
+			return;
+		} else if (ch == 1) {
+			show_state();
+			return;
+		} else if (ch == 2) {
+			show_buffers();
+			return;
+		}
+		/* It is a 'keyboard interrupt' ;-) */
+		wake_up(&keypress_wait);
+	}
+	/* 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();
+		goto clear_and_exit;
+	}
+
+	if(!tty)
+		goto clear_and_exit;
+
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+		queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+	tty->flip.count++;
+	if(stat & PAR_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+	else if(stat & Rx_OVR)
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+	else if(stat & CRC_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+	else
+		*tty->flip.flag_buf_ptr++ = 0; /* XXX */
+	*tty->flip.char_buf_ptr++ = ch;
+
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+
+clear_and_exit:
+	rs_recv_clear(info->zs_channel);
+	return;
+}
+
+static _INLINE_ void transmit_chars(struct sun_serial *info)
+{
+	/* P3: In theory we have to test readiness here because a
+	 * serial console can clog the chip through rs_put_char().
+	 * David did not do this. I think he relies on 3-chars FIFO in 8530.
+	 * Let's watch for lost _output_ characters. XXX
+	 */
+
+	if (info->x_char) {
+		/* Send next char */
+		info->zs_channel->data = info->x_char;
+		udelay(5);
+		info->x_char = 0;
+		goto clear_and_return;
+	}
+
+	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+		/* Thats peculiar... */
+		info->zs_channel->control = RES_Tx_P;
+		udelay(5);
+		goto clear_and_return;
+	}
+
+	/* Send char */
+	info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+	udelay(5);
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+	if(info->xmit_cnt <= 0) {
+		info->zs_channel->control = RES_Tx_P;
+		udelay(5);
+		goto clear_and_return;
+	}
+
+clear_and_return:
+	/* Clear interrupt */
+	info->zs_channel->control = RES_H_IUS;
+	udelay(5);
+	return;
+}
+
+static _INLINE_ void status_handle(struct sun_serial *info)
+{
+	unsigned char status;
+
+	/* Get status from Read Register 0 */
+	status = info->zs_channel->control;
+	udelay(5);
+	/* Clear status condition... */
+	info->zs_channel->control = RES_EXT_INT;
+	udelay(5);
+	/* Clear the interrupt */
+	info->zs_channel->control = RES_H_IUS;
+	udelay(5);
+
+#if 0
+	if(status & DCD) {
+		if((info->tty->termios->c_cflag & CRTSCTS) &&
+		   ((info->curregs[3] & AUTO_ENAB)==0)) {
+			info->curregs[3] |= AUTO_ENAB;
+			info->pendregs[3] |= AUTO_ENAB;
+			write_zsreg(info->zs_channel, 3, info->curregs[3]);
+		}
+	} else {
+		if((info->curregs[3] & AUTO_ENAB)) {
+			info->curregs[3] &= ~AUTO_ENAB;
+			info->pendregs[3] &= ~AUTO_ENAB;
+			write_zsreg(info->zs_channel, 3, info->curregs[3]);
+		}
+	}
+#endif
+	/* Whee, if this is console input and this is a
+	 * 'break asserted' status change interrupt, call
+	 * the boot prom.
+	 */
+	if((status & BRK_ABRT) && info->break_abort)
+		batten_down_hatches();
+
+	/* XXX Whee, put in a buffer somewhere, the status information
+	 * XXX whee whee whee... Where does the information go...
+	 */
+	return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct sun_serial * info;
+	unsigned char zs_intreg;
+
+	info = zs_chain;
+	if (!info)
+		return;
+
+	zs_intreg = read_zsreg(info->zs_channel, 3);
+
+	/* 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_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
+#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+	/* *** Chip 1 *** */
+	/* Channel A -- /dev/ttya, could be the console */
+	if(zs_intreg & CHAN_A_IRQMASK) {
+		if (zs_intreg & CHARxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHATxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHAEXT)
+			status_handle(info);
+	}
+
+	info=info->zs_next;
+
+	/* Channel B -- /dev/ttyb, could be the console */
+	if(zs_intreg & CHAN_B_IRQMASK) {
+		if (zs_intreg & CHBRxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHBTxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHBEXT)
+			status_handle(info);
+	}
+
+	info = info->zs_next;
+
+	zs_intreg = read_zsreg(info->zs_channel, 3);
+	/* *** Chip 2 *** */
+	/* Channel A -- /dev/kbd, pass communication to keyboard driver */
+	if(zs_intreg & CHAN_A_IRQMASK) {
+		if (zs_intreg & CHARxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHATxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHAEXT)
+			status_handle(info);
+	}
+
+	info=info->zs_next;
+
+	/* Channel B -- /dev/mouse, pass communication to mouse driver */
+	if(zs_intreg & CHAN_B_IRQMASK) {
+		if (zs_intreg & CHBRxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHBTxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHBEXT)
+			status_handle(info);
+	}
+
+	return;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct sun_serial	*info = (struct sun_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+	struct sun_serial	*info = (struct sun_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work very well for 16450's, but gives barely
+ * passable results for a 16550A.  (Although at the expense of much
+ * CPU overhead).
+ */
+static void rs_timer(void)
+{
+	printk("rs_timer called\n");
+	prom_halt();
+	return;
+}
+
+static int startup(struct sun_serial * info)
+{
+	unsigned long flags;
+
+	if (info->flags & ZILOG_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+#endif
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+	ZS_CLEARFIFO(info->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	info->zs_channel->control = ERR_RES;
+	udelay(5);
+	info->zs_channel->control = RES_H_IUS;
+	udelay(5);
+
+	/*
+	 * Now, initialize the Zilog
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
+	info->pendregs[1] = info->curregs[1];
+	info->curregs[3] |= (RxENABLE | Rx8);
+	info->pendregs[3] = info->curregs[3];
+	/* We enable Tx interrupts as needed. */
+	info->curregs[5] |= (TxENAB | Tx8);
+	info->pendregs[5] = info->curregs[5];
+	info->curregs[9] |= (NV | MIE);
+	info->pendregs[9] = info->curregs[9];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	write_zsreg(info->zs_channel, 9, info->curregs[9]);
+	
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	info->zs_channel->control = ERR_RES;
+	udelay(5);
+	info->zs_channel->control = RES_H_IUS;
+	udelay(5);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+#if 0  /* Works well and stops the machine. */
+	timer_table[RS_TIMER].expires = jiffies + 2;
+	timer_active |= 1 << RS_TIMER;
+#endif
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info);
+
+	info->flags |= ZILOG_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct sun_serial * info)
+{
+	unsigned long	flags;
+
+	if (!(info->flags & ZILOG_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       info->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	
+	info->flags &= ~ZILOG_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct sun_serial *info)
+{
+	unsigned short port;
+	unsigned cflag;
+	int	i;
+	int	brg;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		/* XXX CBAUDEX is not obeyed.
+		 * It is impossible at a 32bits SPARC.
+		 * But we have to report this to user ... someday.
+		 */
+		i = B9600;
+	}
+	info->zs_baud = baud_table[i];
+	info->clk_divisor = 16;
+
+	info->curregs[4] = X16CLK;
+	info->curregs[11] = TCBR | RCBR;
+	brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+	info->curregs[12] = (brg & 255);
+	info->curregs[13] = ((brg >> 8) & 255);
+	info->curregs[14] = BRSRC | BRENABL;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx5;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx5;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS6:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx6;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx6;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS7:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx7;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx7;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx8;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx8;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	}
+	info->curregs[4] &= ~(0x0c);
+	if (cflag & CSTOPB) {
+		info->curregs[4] |= SB2;
+	} else {
+		info->curregs[4] |= SB1;
+	}
+	info->pendregs[4] = info->curregs[4];
+	if (cflag & PARENB) {
+		info->curregs[4] |= PAR_ENA;
+		info->pendregs[4] |= PAR_ENA;
+	} else {
+		info->curregs[4] &= ~PAR_ENA;
+		info->pendregs[4] &= ~PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->curregs[4] |= PAR_EVEN;
+		info->pendregs[4] |= PAR_EVEN;
+	} else {
+		info->curregs[4] &= ~PAR_EVEN;
+		info->pendregs[4] &= ~PAR_EVEN;
+	}
+
+	/* Load up the new values */
+	load_zsregs(info->zs_channel, info->curregs);
+
+	return;
+}
+
+/* This is for mouse/keyboard output.
+ * XXX mouse output??? can we send it commands??? XXX
+ */
+void kbd_put_char(unsigned char ch)
+{
+	struct sun_zschannel *chan = zs_kbdchan;
+	int flags, loops = 0;
+
+	if(!chan)
+		return;
+
+	save_flags(flags); cli();
+	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+		loops++;
+		udelay(5);
+	}
+
+	chan->data = ch;
+	udelay(5);
+	restore_flags(flags);
+}
+
+void mouse_put_char(char ch)
+{
+	struct sun_zschannel *chan = zs_mousechan;
+	int flags, loops = 0;
+
+	if(!chan)
+		return;
+
+	save_flags(flags); cli();
+	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+		loops++;
+		udelay(5);
+	}
+
+	chan->data = ch;
+	udelay(5);
+	restore_flags(flags);
+}
+
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+	struct sun_zschannel *chan = zs_conschan;
+	int flags, loops = 0;
+
+	if(!chan)
+		return;
+
+	save_flags(flags); cli();
+	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
+		loops++;
+		udelay(5);
+	}
+
+	chan->data = ch;
+	udelay(5);
+	restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+	struct sun_zschannel *chan = zs_kgdbchan;
+
+	while((chan->control & Tx_BUF_EMP)==0)
+		udelay(5);
+
+	chan->data = kgdb_char;
+}
+
+char getDebugChar(void)
+{
+	struct sun_zschannel *chan = zs_kgdbchan;
+
+	while((chan->control & Rx_CH_AV)==0)
+		barrier();
+	return chan->data;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+	int left;		/* Output no more than that */
+	unsigned long flags;
+	struct sun_serial *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);
+
+		rs_put_char(c);
+
+		save_flags(flags);  cli();
+		left = MIN(info->xmit_cnt, left-1);
+	}
+
+	/* Last character is being transmitted now (hopefuly). */
+	zs_conschan->control = RES_Tx_P;
+	udelay(5);
+
+	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')
+			rs_put_char('\r');
+		rs_put_char(c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	rs_fair_output();
+
+	return;
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	info->curregs[5] |= TxENAB;
+	info->pendregs[5] |= TxENAB;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+	/*
+	 * Send a first (bootstrapping) character. A best solution is
+	 * to call transmit_chars() here which handles output in a
+	 * generic way. Current transmit_chars() not only transmits,
+	 * but resets interrupts also what we do not desire here.
+	 * XXX Discuss with David.
+	 */
+	if (info->zs_channel->control & Tx_BUF_EMP) {
+		/* Send char */
+		info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+		udelay(5);
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+	}
+	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 sun_serial *info = (struct sun_serial *)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 && !tty->hw_stopped &&
+	    !(info->curregs[5] & TxENAB)) {
+		/* Enable transmitter */
+		info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+		info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		info->curregs[5] |= TxENAB;
+		info->pendregs[5] |= TxENAB;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+	return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		info->x_char = STOP_CHAR(tty);
+
+	/* Turn off RTS line */
+	cli();
+	info->curregs[5] &= ~RTS;
+	info->pendregs[5] &= ~RTS;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			info->x_char = START_CHAR(tty);
+	}
+
+	/* Assert RTS line */
+	cli();
+	info->curregs[5] |= RTS;
+	info->pendregs[5] |= RTS;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct sun_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+	return 0;
+}
+
+static int set_serial_info(struct sun_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct sun_serial old_info;
+	int 			retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!suser()) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ZILOG_USR_MASK) !=
+		     (info->flags & ~ZILOG_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+			       (new_serial.flags & ZILOG_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ZILOG_FLAGS) |
+			(new_serial.flags & ZILOG_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * 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 RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct sun_serial * info, unsigned int *value)
+{
+	unsigned char status;
+
+	cli();
+	status = info->zs_channel->control;
+	sti();
+	put_user(status,value);
+	return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(	struct sun_serial * info, int duration)
+{
+	if (!info->port)
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
+	schedule();
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	int retval;
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				send_break(info, HZ/4);	/* 1/4 second */
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+		case TIOCGSOFTCAR:
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			if (error)
+				return error;
+			put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+				    (unsigned long *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+			arg = get_fs_long((unsigned long *) arg);
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCGSERIAL:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct));
+			if (error)
+				return error;
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct sun_serial));
+			if (error)
+				return error;
+			memcpy_tofs((struct sun_serial *) arg,
+				    info, sizeof(struct sun_serial));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+
+	change_speed(info);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * ZILOG structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ZILOG_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ZILOG_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ZILOG_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	/** if (!info->iscons) ... **/
+	info->curregs[3] &= ~RxENABLE;
+	info->pendregs[3] = info->curregs[3];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+	info->curregs[1] &= ~(0x18);
+	info->pendregs[1] = info->curregs[1];
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	ZS_CLEARFIFO(info->zs_channel);
+
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+		if (tty->ldisc.close)
+			(tty->ldisc.close)(tty);
+		tty->ldisc = ldiscs[N_TTY];
+		tty->termios->c_line = N_TTY;
+		if (tty->ldisc.open)
+			(tty->ldisc.open)(tty);
+	}
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + info->close_delay;
+			schedule();
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+			 ZILOG_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+	
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct sun_serial *info)
+{
+	struct wait_queue wait = { current, NULL };
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & ZILOG_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ZILOG_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ZILOG_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ZILOG_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ZILOG_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ZILOG_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	info->count--;
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE))
+			zs_rtsdtr(info, 1);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ZILOG_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    !(info->flags & ZILOG_CLOSING) && do_clocal)
+			break;
+		if (current->signal & ~current->blocked) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ZILOG_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct sun_serial	*info;
+	int 			retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	/* The zilog lines for the mouse/keyboard must be
+	 * opened using their respective drivers.
+	 */
+	if ((line < 0) || (line >= NUM_CHANNELS))
+		return -ENODEV;
+	if((line == KEYBOARD_LINE) || (line == MOUSE_LINE))
+		return -ENODEV;
+	info = zs_soft + line;
+	/* Is the kgdb running over this line? */
+	if (info->kgdb_channel)
+		return -ENODEV;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+	printk("Sparc Zilog8530 serial driver version 1.00\n");
+}
+
+/* Probe the PROM for the request zs chip number. */
+static inline struct sun_zslayout *get_zs(int chip)
+{
+	struct linux_prom_irqs tmp_irq;
+	unsigned long paddr = 0;
+	unsigned long vaddr = 0;
+	int zsnode, tmpnode, iospace, slave;
+	static int irq = 0;
+
+#if CONFIG_AP1000
+        printk("No zs chip\n");
+        return NULL;
+#endif
+
+	iospace = 0;
+	if(chip < 0 || chip >= NUM_SERIAL)
+		panic("get_zs bogon zs chip number");
+
+	if(sparc_cpu_model == sun4) {
+		/* Grrr, these have to be hardcoded aieee */
+		switch(chip) {
+		case 0:
+			paddr = 0xf1000000;
+			break;
+		case 1:
+			paddr = 0xf0000000;
+			break;
+		};
+		iospace = 0;
+		zs_nodes[chip] = 0;
+		if(!irq)
+			zilog_irq = irq = 12;
+		vaddr = (unsigned long)
+			sparc_alloc_io((char *) paddr, 0, 8,
+				       "Zilog Serial", iospace, 0);
+	} else {
+		/* Can use the prom for other machine types */
+		zsnode = prom_getchild(prom_root_node);
+		tmpnode = prom_searchsiblings(zsnode, "obio");
+		if(tmpnode)
+			zsnode = prom_getchild(tmpnode);
+		if(!zsnode)
+			panic("get_zs no zs serial prom node");
+		while(zsnode) {
+			zsnode = prom_searchsiblings(zsnode, "zs");
+			slave = prom_getintdefault(zsnode, "slave", -1);
+			if(slave==chip) {
+				/* The one we want */
+				vaddr = (unsigned long)
+					prom_getintdefault(zsnode, "address",
+							       0xdeadbeef);
+				if(vaddr == 0xdeadbeef)
+					prom_halt();
+				zs_nodes[chip] = zsnode;
+				prom_getproperty(zsnode, "intr",
+						 (char *) &tmp_irq,
+						 sizeof(tmp_irq));
+#ifdef OLD_STYLE_IRQ
+				tmp_irq.pri &= 0xf;
+#endif
+				if(!irq) {
+					irq = zilog_irq = tmp_irq.pri;
+				} else {
+					if(tmp_irq.pri != irq)
+						panic("zilog: bogon irqs");
+				}
+				break;
+			}
+			zsnode = prom_getsibling(zsnode);
+		}
+		if(!zsnode)
+			panic("get_zs whee chip not found");
+	}
+	if(!vaddr)
+		panic("get_zs whee no serial chip mappable");
+
+	return (struct sun_zslayout *) vaddr;
+
+}
+
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct sun_serial *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->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 this is console input, we handle the break received
+	 * status interrupt on this line to mean prom_halt().
+	 */
+	if(zs_cons_chanin == channel) {
+		ss->break_abort = 1;
+		i = 1;
+	}
+	if(o && i)
+		io = 1;
+	if(ss->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->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")));
+	}
+}
+
+volatile int test_done;
+extern void keyboard_zsinit(void);
+extern void sun_mouse_zsinit(void);
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+	int chip, channel, i, flags;
+	struct sun_serial *info;
+
+#if CONFIG_AP1000
+        printk("not doing rs_init()\n");
+        return 0;
+#endif
+
+	/* Setup base handler, and timer table. */
+	init_bh(SERIAL_BH, do_serial_bh);
+	timer_table[RS_TIMER].fn = rs_timer;
+	timer_table[RS_TIMER].expires = 0;
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	/* SPARC: Not all of this is exactly right for us. */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NUM_CHANNELS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	save_flags(flags); cli();
+
+	/* Set up our interrupt linked list */
+	zs_chain = &zs_soft[0];
+	zs_soft[0].zs_next = &zs_soft[1];
+	zs_soft[1].zs_next = &zs_soft[2];
+	zs_soft[2].zs_next = &zs_soft[3];
+	zs_soft[3].zs_next = 0;
+
+	for(chip = 0; chip < NUM_SERIAL; chip++) {
+		/* If we are doing kgdb over one of the channels on
+		 * chip zero, kgdb_channel will be set to 1 by the
+		 * rs_kgdb_hook() routine below.
+		 */
+		if(!zs_chips[chip]) {
+			zs_chips[chip] = get_zs(chip);
+			/* Two channels per chip */
+			zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+			zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+			zs_soft[(chip*2)].kgdb_channel = 0;
+			zs_soft[(chip*2)+1].kgdb_channel = 0;
+		}
+		/* First, set up channel A on this chip. */
+		channel = chip * 2;
+		zs_soft[channel].zs_channel = zs_channels[channel];
+		zs_soft[channel].change_needed = 0;
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+		zs_soft[channel].cons_mouse = 0;
+		/* If not keyboard/mouse and is console serial
+		 * line, then enable receiver interrupts.
+		 */
+		if((channel<KEYBOARD_LINE) && (zs_soft[channel].is_cons)) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+			write_zsreg(zs_soft[channel].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(zs_soft[channel].kgdb_channel)
+			kgdb_chaninit(&zs_soft[channel], 1, zs_soft[channel].zs_baud);
+
+		if(channel == KEYBOARD_LINE) {
+			/* Tell keyboard driver about our presence. */
+			if(zs_soft[channel].zs_baud != 1200)
+				panic("Weird keyboard serial baud rate");
+			zs_soft[channel].cons_keyb = 1;
+			zs_kbdchan = zs_soft[channel].zs_channel;
+			/* Enable Rx/Tx, IRQs, and inform kbd driver */
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R4,
+				    (PAR_EVEN | X16CLK | SB1));
+			write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R11,
+				    (TCBR | RCBR));
+			write_zsreg(zs_soft[channel].zs_channel, R14,
+				    (BRSRC | BRENABL));
+			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+			write_zsreg(zs_soft[channel].zs_channel, R5,
+				    (Tx8 | TxENAB | DTR | RTS));
+#if 0
+			write_zsreg(zs_soft[channel].zs_channel, R15,
+				    (DCDIE | CTSIE | TxUIE | BRKIE));
+#endif
+			ZS_CLEARERR(zs_soft[channel].zs_channel);
+			ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+		}
+
+		/* Now, channel B */
+		channel++;
+		zs_soft[channel].zs_channel = zs_channels[channel];
+		zs_soft[channel].change_needed = 0;
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+		zs_soft[channel].cons_keyb = 0;
+		/* If not keyboard/mouse and is console serial
+		 * line, then enable receiver interrupts.
+		 */
+		if(channel<KEYBOARD_LINE && zs_soft[channel].is_cons) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9,
+				    (NV | MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R10,
+				    (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R3,
+				    (Rx8|RxENABLE));
+			write_zsreg(zs_soft[channel].zs_channel, R5,
+				    (Tx8 | TxENAB | RTS | DTR));
+		}
+		if(channel == MOUSE_LINE) {
+			/* Tell mouse driver about our presence. */
+			if(zs_soft[channel].zs_baud != 1200)
+				panic("Weird mouse serial baud rate");
+			zs_soft[channel].cons_mouse = 1;
+			zs_mousechan = zs_soft[channel].zs_channel;
+			/* Enable Rx, IRQs, and inform mouse driver */
+			write_zsreg(zs_soft[channel].zs_channel, R1, (INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+#if 0 /* XXX hangs sun4c's sometimes */
+			write_zsreg(zs_soft[channel].zs_channel, R15,
+				    (DCDIE | CTSIE | TxUIE | BRKIE));
+#endif
+			sun_mouse_zsinit();
+		} else {
+			zs_soft[channel].cons_mouse = 0;
+		}
+	}
+
+	for(info=zs_chain, i=0; info; info = info->zs_next, i++)
+	{
+		info->magic = SERIAL_MAGIC;
+		info->port = (int) info->zs_channel;
+		info->line = i;
+		info->tty = 0;
+		info->irq = zilog_irq;
+		info->custom_divisor = 16;
+		info->close_delay = 50;
+		info->closing_wait = 3000;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->tqueue.routine = do_softint;
+		info->tqueue.data = info;
+		info->tqueue_hangup.routine = do_serial_hangup;
+		info->tqueue_hangup.data = info;
+		info->callout_termios =callout_driver.init_termios;
+		info->normal_termios = serial_driver.init_termios;
+		info->open_wait = 0;
+		info->close_wait = 0;
+		printk("tty%02d at 0x%04x (irq = %d)", info->line, 
+		       info->port, info->irq);
+		printk(" is a Zilog8530\n");
+	}
+
+	if (request_irq(zilog_irq,
+			rs_interrupt,
+			(SA_INTERRUPT | SA_STATIC_ALLOC),
+			"Zilog8530", NULL))
+		panic("Unable to attach zs intr\n");
+	restore_flags(flags);
+
+	keyboard_zsinit();
+
+	return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* SPARC: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+	return;
+}
+
+/* Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the ttya/ttyb serial ports.
+ * 'chip' should be zero, as chip 1 drives the mouse/keyboard.
+ * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels
+ * are addressed backwards, channel B is first, then channel A.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+	if(chip)
+		panic("rs_cons_hook called with chip not zero");
+	if(!zs_chips[chip]) {
+		zs_chips[chip] = get_zs(chip);
+		/* Two channels per chip */
+		zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+	}
+	zs_soft[channel].zs_channel = zs_channels[channel];
+	zs_soft[channel].change_needed = 0;
+	zs_soft[channel].clk_divisor = 16;
+	zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+	rs_cons_check(&zs_soft[channel], channel);
+	if(out)
+		zs_cons_chanout = ((chip * 2) + channel);
+	else
+		zs_cons_chanin = ((chip * 2) + channel);
+
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+	int chip = 0;
+
+	if(!zs_chips[chip]) {
+		zs_chips[chip] = get_zs(chip);
+		/* Two channels per chip */
+		zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+	}
+	zs_soft[tty_num].zs_channel = zs_channels[tty_num];
+	zs_kgdbchan = zs_soft[tty_num].zs_channel;
+	zs_soft[tty_num].change_needed = 0;
+	zs_soft[tty_num].clk_divisor = 16;
+	zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
+	zs_soft[tty_num ^ 1].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);
+	udelay(5);
+	ZS_CLEARFIFO(zs_kgdbchan);
+}
diff -u --recursive --new-file v1.3.95/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h
--- v1.3.95/linux/drivers/sbus/char/sunserial.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunserial.h	Thu Apr 25 13:27:43 1996
@@ -0,0 +1,420 @@
+/* serial.h: Definitions for the Sparc Zilog serial driver.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_SERIAL_H
+#define _SPARC_SERIAL_H
+
+/* Just one channel */
+struct sun_zschannel {
+	volatile unsigned char control;
+	volatile unsigned char pad1;
+	volatile unsigned char data;
+	volatile unsigned char pad2;
+};
+
+/* The address space layout for each zs chip.  Yes they are
+ * backwards.
+ */
+struct sun_zslayout {
+	struct sun_zschannel channelB;
+	struct sun_zschannel channelA;
+};
+
+/* We need to keep track of the keyboard state, *ahead* of what
+ * the keyboard driver sees, which will be later on after the
+ * interrupt via tqueue wait queues and/or base-handler processing.
+ */
+struct l1a_kbd_state {
+	unsigned char kbd_id;
+	unsigned char l1_down;
+};
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+	int	type;
+	int	line;
+	int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	reserved_char[2];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
+};
+
+/*
+ * 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
+ */
+
+struct sun_serial {
+	struct sun_serial *zs_next;       /* For IRQ servicing chain */
+	struct sun_zschannel *zs_channel; /* Channel registers */
+	unsigned char read_reg_zero;
+
+	char soft_carrier;  /* Use soft carrier on this channel */
+	char cons_keyb;     /* Channel runs the keyboard */
+	char cons_mouse;    /* Channel runs the mouse */
+	char break_abort;   /* Is serial console in, so process brk/abrt */
+	char kgdb_channel;  /* Kgdb is running on this channel */
+	char is_cons;       /* Is this our console. */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int zs_baud;
+
+	/* Current write register values */
+	unsigned char curregs[NUM_ZSREGS];
+
+	/* Values we need to set next opportunity */
+	unsigned char pendregs[NUM_ZSREGS];
+
+	char change_needed;
+
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			flags; 		/* defined in tty.h */
+	int			type; 		/* UART type */
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+};
+
+
+#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 */
+
+/* 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	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 */
+
+/* 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	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	CRC_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)    (channel->control = ERR_RES)
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+				     garbage = channel->data; \
+				     udelay(2); \
+				     garbage = channel->data; \
+				     udelay(2); \
+				     garbage = channel->data; \
+				     udelay(2); } while(0)
+
+#endif /* !(_SPARC_SERIAL_H) */
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.95/linux/drivers/scsi/Makefile	Wed Apr 10 17:02:24 1996
+++ linux/drivers/scsi/Makefile	Fri Apr 26 10:30:51 1996
@@ -84,6 +84,38 @@
   endif
 endif
 
+ifeq ($(CONFIG_A3000_SCSI),y)
+L_OBJS += a3000.o wd33c93.o
+else
+  ifeq ($(CONFIG_A3000_SCSI),m)
+  M_OBJS += a3000.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_A2091_SCSI),y)
+L_OBJS += a2091.o wd33c93.o
+else
+  ifeq ($(CONFIG_A2091_SCSI),m)
+  M_OBJS += a2091.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_GVP11_SCSI),y)
+L_OBJS += gvp11.o wd33c93.o
+else
+  ifeq ($(CONFIG_GVP11_SCSI),m)
+  M_OBJS += gvp11.o wd33c93.o
+  endif
+endif
+
+ifeq ($(CONFIG_ATARI_SCSI),y)
+L_OBJS += atari_scsi.o
+else
+  ifeq ($(CONFIG_ATARI_SCSI),m)
+  M_OBJS += atari_scsi.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_PPA),y)
 L_OBJS += ppa.o
 else
@@ -165,6 +197,14 @@
 else
   ifeq ($(CONFIG_SCSI_U14_34F),m)
   M_OBJS += u14-34f.o
+  endif
+endif
+
+ifeq ($(CONFIG_SCSI_SUNESP),y)
+L_OBJS += esp.o
+else
+  ifeq ($(CONFIG_SCSI_SUNESP),m)
+  M_OBJS += esp.o
   endif
 endif
 
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v1.3.95/linux/drivers/scsi/NCR5380.h	Fri Apr 12 15:51:59 1996
+++ linux/drivers/scsi/NCR5380.h	Fri Apr 26 10:30:51 1996
@@ -298,7 +298,7 @@
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (Scsi_Cmnd *cmd);
+int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int);
 #ifndef NCR5380_queue_command
 static 
 #endif
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v1.3.95/linux/drivers/scsi/a2091.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/a2091.c	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/a2091.h linux/drivers/scsi/a2091.h
--- v1.3.95/linux/drivers/scsi/a2091.h	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/a2091.h	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,6 @@
 #ifndef A2091_H
 
-/* $Id: a2091.h,v 1.3 1996/03/12 20:41:46 root Exp root $
+/* $Id: a2091.h,v 1.4 1996/04/25 20:57:48 root Exp root $
  *
  * Header file for the Commodore A2091 Zorro II SCSI controller for Linux
  *
@@ -14,7 +14,7 @@
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v1.3.95/linux/drivers/scsi/a3000.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/a3000.c	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/a3000.h linux/drivers/scsi/a3000.h
--- v1.3.95/linux/drivers/scsi/a3000.h	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/a3000.h	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,6 @@
 #ifndef A3000_H
 
-/* $Id: a3000.h,v 1.2 1996/02/29 22:10:29 root Exp root $
+/* $Id: a3000.h,v 1.3 1996/04/25 20:58:09 root Exp root $
  *
  * Header file for the Amiga 3000 built-in SCSI controller for Linux
  *
@@ -14,7 +14,7 @@
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- v1.3.95/linux/drivers/scsi/atari_NCR5380.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/atari_NCR5380.c	Fri Apr 26 12:12:25 1996
@@ -47,7 +47,7 @@
  *    inside the execution of NCR5380_intr(), leading to recursive
  *    calls.
  *
- *  - I've added a function merge_consecutive_buffers() that trys to
+ *  - I've added a function merge_consecutive_buffers() that tries to
  *    merge scatter-gather buffers that are located at consecutive
  *    physical addresses and can be processed with the same DMA setup.
  *    Since most scatter-gather operations work on a page (4K) of
@@ -1995,7 +1995,7 @@
      * other phase and will have to source/sink data.
      * 
      * We really don't care what value was on the bus or what value
-     * the target see's, so we just handshake.
+     * the target sees, so we just handshake.
      */
     
     while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
@@ -2280,7 +2280,7 @@
 		    printk("scsi%d: target %d lun %d linked command complete.\n",
 			HOSTNO, cmd->target, cmd->lun);
 #endif
-		    /* Enable reselect interupts */
+		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		    /*
 		     * Sanity check : A linked command should only terminate
@@ -2348,7 +2348,7 @@
 #else
 		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
 #endif
-		    /* Enable reselect interupts */
+		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 
 		    /* 
@@ -2429,7 +2429,7 @@
 		case MESSAGE_REJECT:
 		    /* Accept message by clearing ACK */
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    /* Enable reselect interupts */
+		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		    switch (hostdata->last_message) {
 		    case HEAD_OF_QUEUE_TAG:
@@ -2439,7 +2439,7 @@
 			 * queuing, even though it announced this ability in
 			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
 			 * clear 'tagged_supported' and lock the LUN, since
-			 * the command is treated as untagged furtheron.
+			 * the command is treated as untagged further on.
 			 */
 			cmd->device->tagged_supported = 0;
 			hostdata->busy[cmd->target] |= (1 << cmd->lun);
@@ -2494,7 +2494,7 @@
 		case RESTORE_POINTERS:
 		    /* Accept message by clearing ACK */
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    /* Enable reselect interupts */
+		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		    break;
 		case EXTENDED_MESSAGE:
@@ -2713,7 +2713,7 @@
 #ifdef SUPPORT_TAGS
     /* If the phase is still MSGIN, the target wants to send some more
      * messages. In case it supports tagged queuing, this is probably a
-     * SIMPLE_QEUE_TAG for the I_T_L_Q nexus.
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
      */
     tag = TAG_NONE;
     if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
@@ -3002,7 +3002,7 @@
 
 
 /* 
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
  * 
  * Purpose : reset the SCSI bus.
  *
@@ -3010,7 +3010,7 @@
  *
  */ 
 
-static int NCR5380_reset( Scsi_Cmnd *cmd )
+static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
 #if 0
     SETUP_HOSTDATA(cmd->host);
@@ -3045,7 +3045,7 @@
     /* After the reset, there are no more connected or disconnected commands
      * and no busy units; to avoid problems with re-inserting the commands
      * into the issue_queue (via scsi_done()), the aborted commands are
-     * remebered in local variables first.
+     * remembered in local variables first.
      */
     save_flags(flags);
     cli();
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v1.3.95/linux/drivers/scsi/atari_scsi.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/atari_scsi.c	Fri Apr 26 12:12:25 1996
@@ -1,5 +1,5 @@
 /*
- * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
+ * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port
  *
  * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  *
@@ -40,19 +40,19 @@
 /* totally empty if there is a lot of disk traffic.                       */
 /*                                                                        */
 /* For this reasons I decided to employ a more elaborate scheme:          */
-/*  - First, we give up the lock everytime we can (for fairness), this    */
+/*  - First, we give up the lock every time we can (for fairness), this    */
 /*    means every time a command finishes and there are no other commands */
 /*    on the disconnected queue.                                          */
 /*  - If there are others waiting to lock the DMA chip, we stop           */
-/*    issueing commands, i.e. moving them onto the issue queue.           */
+/*    issuing commands, i.e. moving them onto the issue queue.           */
 /*    Because of that, the disconnected queue will run empty in a         */
 /*    while. Instead we go to sleep on a 'fairness_queue'.                */
 /*  - If the lock is released, all processes waiting on the fairness      */
-/*    queue will be woken. The first of them trys to re-lock the DMA,     */
+/*    queue will be woken. The first of them tries to re-lock the DMA,     */
 /*    the others wait for the first to finish this task. After that,      */
 /*    they can all run on and do their commands...                        */
 /* This sounds complicated (and it is it :-(), but it seems to be a       */
-/* good compromise between fairness and performance: As long as noone     */
+/* good compromise between fairness and performance: As long as no one     */
 /* else wants to work with the ST-DMA chip, SCSI can go along as          */
 /* usual. If now someone else comes, this behaviour is changed to a       */
 /* "fairness mode": just already initiated commands are finished and      */
@@ -324,7 +324,7 @@
 #endif
 
 	/* Look if it was the DMA that has interrupted: First possibility
-	 * is that a bus error occured...
+	 * is that a bus error occurred...
 	 */
 	if (dma_stat & 0x80) {
 		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
@@ -335,7 +335,7 @@
 	}
 
 	/* If the DMA is active but not finished, we have the the case
-	 * that some other 5380 interrupt occured within the DMA transfer.
+	 * that some other 5380 interrupt occurred within the DMA transfer.
 	 * This means we have residual bytes, if the desired end address
 	 * is not yet reached. Maybe we have to fetch some bytes from the
 	 * rest data register, too. The residual must be calculated from
@@ -537,7 +537,7 @@
 }
 
 /* This function manages the locking of the ST-DMA.
- * If the DMA isn't locked already for SCSI, it trys to lock it by
+ * If the DMA isn't locked already for SCSI, it tries to lock it by
  * calling stdma_lock(). But if the DMA is locked by the SCSI code and
  * there are other drivers waiting for the chip, we do not issue the
  * command immediately but wait on 'falcon_fairness_queue'. We will be
@@ -585,7 +585,7 @@
 
 
 /* This is the wrapper function for NCR5380_queue_command(). It just
- * trys to get the lock on the ST-DMA (see above) and then calls the
+ * tries to get the lock on the ST-DMA (see above) and then calls the
  * original function.
  */
 
@@ -772,7 +772,7 @@
 		remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr);
 #endif
 	}
-	if (atari_dma_bufffer)
+	if (atari_dma_buffer)
 		scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE);
 	return 1;
 }
@@ -840,7 +840,7 @@
 #endif
 }
 
-int atari_scsi_reset( Scsi_Cmnd *cmd )
+int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
 	int		rv;
 	struct NCR5380_hostdata *hostdata =
@@ -866,7 +866,7 @@
 #endif /* REAL_DMA */
 	}
 
-	rv = NCR5380_reset( cmd );
+	rv = NCR5380_reset(cmd, reset_flags);
 
 	/* Re-enable ints */
 	if (IS_A_TT()) {
@@ -955,7 +955,7 @@
 	 * ++roman: For the Medusa, there's no need at all for that cache stuff,
 	 * because the hardware does bus snooping (fine!).
 	 */
-	dma_cache_maintainance( addr, count, dir );
+	dma_cache_maintenance( addr, count, dir );
 
 	if (count == 0)
 		printk("SCSI warning: DMA programmed for 0 bytes !\n");
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h
--- v1.3.95/linux/drivers/scsi/atari_scsi.h	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/atari_scsi.h	Fri Apr 26 12:12:25 1996
@@ -22,7 +22,7 @@
 int atari_scsi_detect (Scsi_Host_Template *);
 const char *atari_scsi_info (struct Scsi_Host *);
 int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int atari_scsi_reset (Scsi_Cmnd *);
+int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
 int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
 #ifdef MODULE
 int atari_scsi_release (struct Scsi_Host *);
@@ -34,7 +34,7 @@
  * values should work, too; try it! (but cmd_per_lun costs memory!) */
 
 /* But there seems to be a bug somewhere that requires CAN_QUEUE to be
- * 2*CMD_OER_LUN. At least on a TT, no suprious timeouts seen since
+ * 2*CMD_OER_LUN. At least on a TT, no spurious timeouts seen since
  * changed CMD_PER_LUN... */
 
 /* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v1.3.95/linux/drivers/scsi/gvp11.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/gvp11.c	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blk.h>
+#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/gvp11.h linux/drivers/scsi/gvp11.h
--- v1.3.95/linux/drivers/scsi/gvp11.h	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/gvp11.h	Fri Apr 26 10:30:51 1996
@@ -1,6 +1,6 @@
 #ifndef GVP11_H
 
-/* $Id: gvp11.h,v 1.4 1996/03/12 20:42:40 root Exp root $
+/* $Id: gvp11.h,v 1.5 1996/04/25 20:58:31 root Exp root $
  *
  * Header file for the GVP Series II SCSI controller for Linux
  *
@@ -15,7 +15,7 @@
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 #ifndef NULL
 #define NULL 0
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.95/linux/drivers/scsi/hosts.c	Sun Apr 21 19:22:11 1996
+++ linux/drivers/scsi/hosts.c	Fri Apr 26 10:30:51 1996
@@ -41,6 +41,22 @@
 
 #include "hosts.h"
 
+#ifdef CONFIG_A3000_SCSI
+#include "a3000.h"
+#endif
+
+#ifdef CONFIG_A2091_SCSI
+#include "a2091.h"
+#endif
+
+#ifdef CONFIG_GVP11_SCSI
+#include "gvp11.h"
+#endif
+
+#ifdef CONFIG_ATARI_SCSI
+#include "atari_scsi.h"
+#endif
+
 #ifdef CONFIG_SCSI_ADVANSYS
 #include "advansys.h"
 #endif
@@ -147,7 +163,7 @@
 
 
 /*
-static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.10 1996/04/16 08:09:36 davem Exp $";
+static const char RCSid[] = "$Header: /usr/src/linux-1.3.95/drivers/scsi/RCS/hosts.c,v 1.7 1996/04/25 22:21:56 root Exp root $";
 */
 
 /*
@@ -179,6 +195,24 @@
 
 static Scsi_Host_Template builtin_scsi_hosts[] =
 {
+#ifdef CONFIG_AMIGA
+#ifdef CONFIG_A3000_SCSI
+	A3000_SCSI,
+#endif
+#ifdef CONFIG_A2091_SCSI
+	A2091_SCSI,
+#endif
+#ifdef CONFIG_GVP11_SCSI
+	GVP11_SCSI,
+#endif
+#endif
+
+#ifdef CONFIG_ATARI
+#ifdef CONFIG_ATARI_SCSI
+	ATARI_SCSI,
+#endif
+#endif
+
 #ifdef CONFIG_SCSI_ADVANSYS
 	ADVANSYS,
 #endif
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.95/linux/drivers/scsi/scsi.c	Wed Apr 24 17:00:41 1996
+++ linux/drivers/scsi/scsi.c	Thu Apr 25 07:47:15 1996
@@ -288,7 +288,7 @@
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"EMULEX","MD21/S2     ESDI","*",BLIST_FORCELUN | BLIST_SINGLELUN},
+{"EMULEX","MD21/S2     ESDI","*",BLIST_SINGLELUN},
 /*
  * Must be at end of list...
  */
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
--- v1.3.95/linux/drivers/scsi/wd33c93.c	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/wd33c93.c	Fri Apr 26 12:13:24 1996
@@ -28,18 +28,23 @@
  *
  *    -  Target Disconnection/Reconnection  is now supported. Any
  *          system with more than one device active on the SCSI bus
- *          will benefit from this.
+ *          will benefit from this. The driver defaults to what I'm
+ *          'adaptive disconnect' - meaning that each command is
+ *          evaluated individually as to whether or not it should
+ *          be run with the option to disconnect/reslect (if the
+ *          device chooses), or as a "SCSI-bus-hog".
  *
- *    -  Synchronous data transfers are now supported. The driver
- *          automatically uses this faster protocol with any device
- *          able to handle it.
+ *    -  Synchronous data transfers are now supported. Because of
+ *          a few devices that choke after telling the driver that
+ *          they can do sync transfers, we don't automatically use
+ *          this faster protocol - it can be enabled via the command-
+ *          line on a device-by-device basis.
  *
  *    -  Runtime operating parameters can now be specified through
- *       either the 'amiboot' or the LILO command line. Something
- *       like:
- *          "wd33c93=0x0000"
- *       The value 0x0000 results in the defaults being used; bits
- *       are defined in wd33c93.h.
+ *       the 'amiboot' or the 'insmod' command line. For amiboot do:
+ *          "amiboot [usual stuff] wd33c93=blah,blah,blah"
+ *       The defaults should be good for most people. See the comment
+ *       for 'setup_strings' below for more details.
  *
  *    -  The old driver relied exclusively on what the Western Digital
  *          docs call "Combination Level 2 Commands", which are a great
@@ -52,7 +57,7 @@
  *
  *
  * TODO:
- *       more speed. tagged queuing.
+ *       more speed. linked commands.
  *
  *
  * People with bug reports, wish-lists, complaints, comments,
@@ -67,18 +72,33 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
+#else
+#include "../block/blk.h"
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "wd33c93.h"
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
 
-#define SYNC_DEBUG
+/* Leave this undefined for now - need to make some changes in the
+ * a3000/a2019/gvp11 files to get it working right
+ */
+/*#define PROC_INTERFACE*/     /* add code for /proc/scsi/wd33c93/xxx interface */
 
-#define DEBUGGING_ON
+#define SYNC_DEBUG         /* extra info on sync negotiation printed */
+#define DEBUGGING_ON       /* enable command-line debugging bitmask */
+#define DEBUG_DEFAULTS 0   /* default debugging bitmask */
 
-#define WD33C93_VERSION    "1.17"
-#define WD33C93_DATE       "06/Feb/1996"
+#define WD33C93_VERSION    "1.21"
+#define WD33C93_DATE       "20/Apr/1996"
 
 #ifdef DEBUGGING_ON
 #define DB(f,a) if (hostdata->args & (f)) a;
@@ -92,15 +112,59 @@
 
 
 /*
- * setup_default is a bunch of bits that define some of the operating
- * parameters and settings for this driver. It is used unless a LILO
- * or insmod command line has been specified, in which case setup_default
- * is _completely_ ignored. Take a look at the "defines for hostdata->args"
- * section in wd33c93.h - that stuff is what you'd use here if you want
- * to change the defaults.
+ * setup_strings is an array of strings that define some of the operating
+ * parameters and settings for this driver. It is used unless an amiboot
+ * or insmod command line has been specified, in which case those settings
+ * are combined with the ones here. The driver recognizes the following
+ * keywords (lower case required) and arguments:
+ *
+ * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
+ *                    the 7 possible SCSI devices. Set a bit to prevent sync
+ *                    negotiation on that device. To maintain backwards
+ *                    compatability, a command-line such as "wd33c93=255" will
+ *                    be automatically translated to "wd33c93=nosync:0xff".
+ * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
+ *                    period. Default is 500; acceptable values are 250 - 1000.
+ * -  disconnect:x   -x = 0 to never allow disconnects, 2 to always allow them.
+ *                    x = 1 does 'adaptive' disconnects, which is the default
+ *                    and generally the best choice.
+ * -  debug:x        -If 'DEBUGGING_ON' is defined, x is a bit mask that causes
+ *                    various types of debug output to printed - see the DB_xxx
+ *                    defines in wd33c93.h
+ * -  clock:x        -x = clock input in MHz for WD33c93 chip. Normal values
+ *                    would be from 8 through 20. Default is 8.
+ * -  next           -No argument. Used to separate blocks of keywords when
+ *                    there's more than one host adapter in the system.
+ *
+ * Syntax Notes:
+ * -  Numeric arguments can be decimal or the '0x' form of hex notation. There
+ *    _must_ be a colon between a keyword and its numeric argument, with no
+ *    spaces.
+ * -  Keywords are separated by commas, no spaces, in the standard kernel
+ *    command-line manner, except in the case of 'setup_strings[]' (see
+ *    below), which is simply a C array of pointers to char. Each element
+ *    in the array is a string comprising one keyword & argument.
+ * -  A keyword in the 'nth' comma-separated command-line member will overwrite
+ *    the 'nth' element of setup_strings[]. A blank command-line member (in
+ *    other words, a comma with no preceding keyword) will _not_ overwrite
+ *    the corresponding setup_strings[] element.
+ * -  If a keyword is used more than once, the first one applies to the first
+ *    SCSI host found, the second to the second card, etc, unless the 'next'
+ *    keyword is used to change the order.
+ *
+ * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'):
+ * -  wd33c93=nosync:255
+ * -  wd33c93=disconnect:2,nosync:0x08,period:250
+ * -  wd33c93=debug:0x1c
  */
 
-static unsigned int setup_default = 0;
+static char *setup_strings[] =
+      {"","","","","","","","","","","",""};
+
+#ifdef PROC_INTERFACE
+unsigned long disc_allowed_total;
+unsigned long disc_taken_total;
+#endif
 
 
 inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
@@ -176,27 +240,32 @@
    {1000,0x00},
    {0,   0} };
 
-uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+int round_period(unsigned int period)
 {
-uchar result;
 int x;
 
-   period *= 4;   /* convert SDTR code to ns */
-   result = 0x00;
    for (x=1; sx_table[x].period_ns; x++) {
       if ((period <= sx_table[x-0].period_ns) &&
           (period >  sx_table[x-1].period_ns)) {
-         result = sx_table[x].reg_value;
-         break;
+         return x;
          }
       }
+   return 7;
+}
+
+uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+uchar result;
+
+   period *= 4;   /* convert SDTR code to ns */
+   result = sx_table[round_period(period)].reg_value;
    result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
    return result;
 }
 
 
 
-static void wd33c93_execute(struct Scsi_Host *instance);
+void wd33c93_execute(struct Scsi_Host *instance);
 
 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
@@ -204,13 +273,14 @@
 Scsi_Cmnd *tmp;
 unsigned long flags;
 
+
+   save_flags(flags);
+   cli();
    hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
 
 DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
 
-
-/*
- * Set up a few fields in the Scsi_Cmnd structure for our own use:
+/* Set up a few fields in the Scsi_Cmnd structure for our own use:
  *  - host_scribble is the pointer to the next cmd in the input queue
  *  - scsi_done points to the routine we call when a cmd is finished
  *  - result is what you'd expect
@@ -230,6 +300,9 @@
  *  - SCp.this_residual is the size of that buffer
  *  - SCp.buffer points to the current scatter-gather buffer
  *  - SCp.buffers_residual tells us how many S.G. buffers there are
+ *  - SCp.have_data_in is not used
+ *  - SCp.sent_command is not used
+ *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
    if (cmd->use_sg) {
@@ -255,19 +328,16 @@
     * sense data is not lost before REQUEST_SENSE executes.
     */
 
-   save_flags(flags);
-   cli();
    if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
       cmd->host_scribble = (uchar *)hostdata->input_Q;
       hostdata->input_Q = cmd;
       }
-   else {
+   else {   /* find the end of the queue */
       for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
             tmp=(Scsi_Cmnd *)tmp->host_scribble)
          ;
       tmp->host_scribble = (uchar *)cmd;
       }
-   restore_flags(flags);
 
 /* We know that there's at least one command in 'input_Q' now.
  * Go see if any of them are runnable!
@@ -275,7 +345,9 @@
 
    wd33c93_execute(cmd->host);
 
-DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid))
+DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
+
+   restore_flags(flags);
    return 0;
 }
 
@@ -287,7 +359,7 @@
  * the input_Q, using the first command we find that's intended
  * for a currently non-busy target/lun.
  */
-static void wd33c93_execute (struct Scsi_Host *instance)
+void wd33c93_execute (struct Scsi_Host *instance)
 {
 struct WD33C93_hostdata *hostdata;
 wd33c93_regs *regp;
@@ -301,10 +373,12 @@
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
    regp = hostdata->regp;
 
-DB(DB_EXECUTE,printk("EX( "))
+DB(DB_EXECUTE,printk("EX("))
 
    if (hostdata->selecting || hostdata->connected) {
+
 DB(DB_EXECUTE,printk(")EX-0 "))
+
       restore_flags(flags);
       return;
       }
@@ -326,18 +400,19 @@
    /* quit if queue empty or all possible targets are busy */
 
    if (!cmd) {
+
 DB(DB_EXECUTE,printk(")EX-1 "))
+
       restore_flags(flags);
       return;
       }
 
-   /*  remove command from queue, put it in selecting */
+   /*  remove command from queue */
    
    if (prev)
       prev->host_scribble = cmd->host_scribble;
    else
       hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
-   hostdata->selecting = cmd;
 
    /*
     * Start the selection process
@@ -348,22 +423,78 @@
    else
       write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
 
+/* Now we need to figure out whether or not this command is a good
+ * candidate for disconnect/reselect. We guess to the best of our
+ * ability, based on a set of hierarchical rules. When several
+ * devices are operating simultaneously, disconnects are usually
+ * an advantage. In a single device system, or if only 1 device
+ * is being accessed, transfers usually go faster if disconnects
+ * are not allowed:
+ *
+ * + Commands should NEVER disconnect if hostdata->disconnect =
+ *   DIS_NEVER (this holds for tape drives also), and ALWAYS
+ *   disconnect if hostdata->disconnect = DIS_ALWAYS.
+ * + Tape drive commands should always be allowed to disconnect.
+ * + Disconnect should be allowed if disconnected_Q isn't empty.
+ * + Commands should NOT disconnect if input_Q is empty.
+ * + Disconnect should be allowed if there are commands in input_Q
+ *   for a different target/lun. In this case, the other commands
+ *   should be made disconnect-able, if not already.
+ *
+ * I know, I know - this code would flunk me out of any
+ * "C Programming 101" class ever offered. But it's easy
+ * to change around and experiment with for now.
+ */
+
+   cmd->SCp.phase = 0;  /* assume no disconnect */
+   if (hostdata->disconnect == DIS_NEVER)
+      goto no;
+   if (hostdata->disconnect == DIS_ALWAYS)
+      goto yes;
+   if (cmd->device->type == 1)   /* tape drive? */
+      goto yes;
+   if (hostdata->disconnected_Q) /* other commands disconnected? */
+      goto yes;
+   if (!(hostdata->input_Q))     /* input_Q empty? */
+      goto no;
+   for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
+         prev=(Scsi_Cmnd *)prev->host_scribble) {
+      if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {
+         for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
+               prev=(Scsi_Cmnd *)prev->host_scribble)
+            prev->SCp.phase = 1;
+         goto yes;
+         }
+      }
+   goto no;
+
+yes:
+   cmd->SCp.phase = 1;
+
+#ifdef PROC_INTERFACE
+   disc_allowed_total++;
+#endif
+
+no:
+   write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0));
+
    write_wd33c93(regp, WD_TARGET_LUN, cmd->lun);
-   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write_wd33c93_count(regp, 0); /* this guarantees a DATA_PHASE interrupt */
+   write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
    hostdata->busy[cmd->target] |= (1 << cmd->lun);
 
    if ((hostdata->level2 == L2_NONE) ||
        (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
 
          /*
-          * Now do a 'Select-With-ATN' command. This will end with
+          * Do a 'Select-With-ATN' command. This will end with
           * one of the following interrupts:
           *    CSR_RESEL_AM:  failure - can try again later.
           *    CSR_TIMEOUT:   failure - give up.
           *    CSR_SELECT:    success - proceed.
           */
 
+      hostdata->selecting = cmd;
+
 /* Every target has its own synchronous transfer setting, kept in the
  * sync_xfer array, and a corresponding status byte in sync_stat[].
  * Each target's sync_stat[] entry is initialized to SX_UNSET, and its
@@ -376,19 +507,20 @@
  * make the defaults final.
  */
       if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
-         if (hostdata->args & (1 << cmd->target))
+         if (hostdata->no_sync & (1 << cmd->target))
             hostdata->sync_stat[cmd->target] = SS_SET;
          else
             hostdata->sync_stat[cmd->target] = SS_FIRST;
          }
       hostdata->state = S_SELECTING;
+      write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
       write_wd33c93_cmd(regp, WD_CMD_SEL_ATN);
       }
 
    else {
 
          /*
-          * Now do a 'Select-With-ATN-Xfer' command. This will end with
+          * Do a 'Select-With-ATN-Xfer' command. This will end with
           * one of the following interrupts:
           *    CSR_RESEL_AM:  failure - can try again later.
           *    CSR_TIMEOUT:   failure - give up.
@@ -396,13 +528,15 @@
           */
 
       hostdata->connected = cmd;
-      hostdata->selecting = NULL;
       write_wd33c93(regp, WD_COMMAND_PHASE, 0);
 
-   /* copy command_descriptor_block into WD chip */
+   /* copy command_descriptor_block into WD chip
+    * (take advantage of auto-incrementing)
+    */
 
+      regp->SASR = WD_CDB_1;
       for (i=0; i<cmd->cmd_len; i++)
-         write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]);
+         regp->SCMD = cmd->cmnd[i];
 
    /* The wd33c93 only knows about Group 0, 1, and 5 commands when
     * it's doing a 'select-and-transfer'. To be safe, we write the
@@ -412,6 +546,23 @@
 
       write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len);
 
+   /* When doing a non-disconnect command, we can save ourselves a DATA
+    * phase interrupt later by setting everything up now.
+    */
+
+      if (cmd->SCp.phase == 0) {
+         if (hostdata->dma_setup(cmd,
+                     (IS_DIR_OUT(cmd))?DATA_OUT_DIR:DATA_IN_DIR))
+            write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
+         else {
+            write_wd33c93_count(regp, cmd->SCp.this_residual);
+            write_wd33c93(regp,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
+            hostdata->dma = D_DMA_RUNNING;
+            }
+         }
+      else
+         write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */
+
       hostdata->state = S_RUNNING_LEVEL2;
       write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
       }
@@ -423,47 +574,38 @@
     * to search the input_Q again...
     */
       
-DB(DB_EXECUTE,printk(")EX-2 "))
+DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
+
    restore_flags(flags);
 }
 
 
 
-void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt,
+void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
                   int data_in_dir, struct WD33C93_hostdata *hostdata)
 {
-uchar *b, asr;
-int c;
+uchar asr;
+
+DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out"))
 
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   b = *buf;
-   c = *cnt;
-DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c))
-   write_wd33c93_count(regp,c);
+   write_wd33c93_count(regp,cnt);
    write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
    if (data_in_dir) {
       do {
          asr = READ_AUX_STAT();
          if (asr & ASR_DBR)
-            *b++ = read_wd33c93(regp, WD_DATA);
+            *buf++ = read_wd33c93(regp, WD_DATA);
          } while (!(asr & ASR_INT));
       }
    else {
       do {
          asr = READ_AUX_STAT();
          if (asr & ASR_DBR)
-            write_wd33c93(regp, WD_DATA, *b++);
+            write_wd33c93(regp, WD_DATA, *buf++);
          } while (!(asr & ASR_INT));
       }
 
-/* update original buffer pointer and original count */
-
-   *cnt = read_wd33c93_count(regp);
-   if (data_in_dir)
-      *buf = b;
-   else
-      *buf += (c - *cnt);
-
    /* Note: we are returning with the interrupt UN-cleared.
    * Since (presumably) an entire I/O operation has
    * completed, the bus phase is probably different, and
@@ -501,7 +643,7 @@
 /* 'dma_setup()' will return TRUE if we can't do DMA. */
 
    if (hostdata->dma_setup(cmd, data_in_dir)) {
-      transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual,
+      transfer_pio(regp, (uchar *)&cmd->SCp.ptr, cmd->SCp.this_residual,
                          data_in_dir, hostdata);
       }
 
@@ -516,11 +658,10 @@
 
    else {
       write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
-DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
       write_wd33c93_count(regp,cmd->SCp.this_residual);
 
-      if (hostdata->level2 >= L2_DATA) {
-         write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
+      if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) {
+         write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
          write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
          hostdata->state = S_RUNNING_LEVEL2;
          }
@@ -538,9 +679,9 @@
 struct WD33C93_hostdata *hostdata;
 Scsi_Cmnd *patch, *cmd;
 wd33c93_regs *regp;
+unsigned long flags;
 uchar asr, sr, phs, id, lun, *ucp, msg;
 unsigned long length;
-int i;
 
 
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
@@ -550,6 +691,11 @@
    if (!(asr & ASR_INT) || (asr & ASR_BSY))
       return;
 
+/* OK - it should be safe to re-enable system interrupts */
+
+   save_flags(flags);
+   sti();
+
    cmd = (Scsi_Cmnd *)hostdata->connected;   /* assume we're connected */
    sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear the interrupt */
    phs = read_wd33c93(regp, WD_COMMAND_PHASE);
@@ -572,13 +718,13 @@
  */
 
    if (hostdata->dma == D_DMA_RUNNING) {
-DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
+DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
       hostdata->dma_stop(cmd->host, cmd, 1);
       hostdata->dma = D_DMA_OFF;
       length = cmd->SCp.this_residual;
       cmd->SCp.this_residual = read_wd33c93_count(regp);
       cmd->SCp.ptr += (length - cmd->SCp.this_residual);
-DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
+DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
       }
 
 /* Respond to the specific WD3393 interrupt - there are quite a few! */
@@ -586,26 +732,26 @@
    switch (sr) {
 
       case CSR_TIMEOUT:
-         cli();
 DB(DB_INTR,printk("TIMEOUT"))
-         if (hostdata->state == S_RUNNING_LEVEL2) {
+
+         cli();
+         if (hostdata->state == S_RUNNING_LEVEL2)
             hostdata->connected = NULL;
-            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-            }
          else {
             cmd = (Scsi_Cmnd *)hostdata->selecting;   /* get a valid cmd */
             hostdata->selecting = NULL;
             }
 
          cmd->result = DID_NO_CONNECT << 16;
-         hostdata->selecting = NULL;
+         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
          hostdata->state = S_UNCONNECTED;
-         cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+         cmd->scsi_done(cmd);
 
 /* We are not connected to a target - check to see if there
  * are commands waiting to be executed.
  */
 
+         sti();
          wd33c93_execute(instance);
          break;
 
@@ -620,10 +766,9 @@
 
       /* construct an IDENTIFY message with correct disconnect bit */
 
-         if (hostdata->args & A_NO_DISCONNECT)
-            hostdata->outgoing_msg[0] = (0x80 | cmd->lun);
-         else
-            hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun);
+         hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun);
+         if (cmd->SCp.phase)
+            hostdata->outgoing_msg[0] |= 0x40;
 
          if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
 #ifdef SYNC_DEBUG
@@ -671,11 +816,10 @@
 /* Note: this interrupt should not occur in a LEVEL2 command */
 
       case CSR_XFER_DONE|PHS_COMMAND:
+      case CSR_UNEXP    |PHS_COMMAND:
       case CSR_SRV_REQ  |PHS_COMMAND:
 DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
-         ucp = cmd->cmnd;
-         i = cmd->cmd_len;
-         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+         transfer_pio(regp, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
          hostdata->state = S_CONNECTED;
          break;
 
@@ -704,6 +848,7 @@
       case CSR_SRV_REQ  |PHS_MESS_IN:
 DB(DB_INTR,printk("MSG_IN="))
 
+         cli();
          msg = read_1_byte(regp);
          sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear interrupt */
 
@@ -730,7 +875,6 @@
 
             case RESTORE_POINTERS:
 DB(DB_INTR,printk("RDP"))
-
                if (hostdata->level2 >= L2_BASIC) {
                   write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
                   write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
@@ -777,24 +921,50 @@
                      case EXTENDED_SDTR:
                         id = calc_sync_xfer(ucp[3],ucp[4]);
                         if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
-                           printk("Rejecting target's SDTR message ");
+
+/* A device has sent an unsolicited SDTR message; rather than go
+ * through the effort of decoding it and then figuring out what
+ * our reply should be, we're just gonna say that we have a
+ * synchronous fifo depth of 0. This will result in asynchronous
+ * transfers - not ideal but so much easier.
+ * Actually, this is OK because it assures us that if we don't
+ * specifically ask for sync transfers, we won't do any.
+ */
+
                            write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-                           hostdata->outgoing_msg[0] = MESSAGE_REJECT;
-                           hostdata->outgoing_len = 1;
+                           hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+                           hostdata->outgoing_msg[1] = 3;
+                           hostdata->outgoing_msg[2] = EXTENDED_SDTR;
+                           hostdata->outgoing_msg[3] = hostdata->default_sx_per/4;
+                           hostdata->outgoing_msg[4] = 0;
+                           hostdata->outgoing_len = 5;
+                           hostdata->sync_xfer[cmd->target] =
+                                       calc_sync_xfer(hostdata->default_sx_per/4,0);
                            }
                         else {
                            hostdata->sync_xfer[cmd->target] = id;
-                           hostdata->sync_stat[cmd->target] = SS_SET;
                            }
 #ifdef SYNC_DEBUG
-printk("sync_xfer=%02x",id);
+printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
 #endif
+                        hostdata->sync_stat[cmd->target] = SS_SET;
+                        write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+                        hostdata->state = S_CONNECTED;
+                        break;
+                     case EXTENDED_WDTR:
+                        write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                        printk("sending WDTR ");
+                        hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+                        hostdata->outgoing_msg[1] = 2;
+                        hostdata->outgoing_msg[2] = EXTENDED_WDTR;
+                        hostdata->outgoing_msg[3] = 0;   /* 8 bit transfer width */
+                        hostdata->outgoing_len = 4;
                         write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
                         hostdata->state = S_CONNECTED;
                         break;
                      default:
-                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
                         write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
                         hostdata->outgoing_msg[0] = MESSAGE_REJECT;
                         hostdata->outgoing_len = 1;
                         write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
@@ -814,7 +984,7 @@
                break;
 
             default:
-               printk("Rejecting Unknown Message(%02x) ",ucp[0]);
+               printk("Rejecting Unknown Message(%02x) ",msg);
                write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
                hostdata->outgoing_msg[0] = MESSAGE_REJECT;
                hostdata->outgoing_len = 1;
@@ -828,6 +998,12 @@
 
       case CSR_SEL_XFER_DONE:
          cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
          if (phs == 0x60) {
 DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
             cmd->SCp.Message = COMMAND_COMPLETE;
@@ -841,7 +1017,7 @@
                cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
             hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
             hostdata->state = S_UNCONNECTED;
-            cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+            cmd->scsi_done(cmd);
 
 /* We are no longer  connected to a target - check to see if
  * there are commands waiting to be executed.
@@ -877,8 +1053,8 @@
  * it - like when our SDTR message is rejected by a target. Some
  * targets send the REJECT before receiving all of the extended
  * message, and then seem to go back to MESSAGE_OUT for a byte
- * or two. Not sure why, ot if I'm doing something wrong to
- * casue this to happen. Regardless, it seems that sending
+ * or two. Not sure why, or if I'm doing something wrong to
+ * cause this to happen. Regardless, it seems that sending
  * NOP messages in these situations results in no harm and
  * makes everyone happy.
  */
@@ -887,22 +1063,67 @@
             hostdata->outgoing_len = 1;
             hostdata->outgoing_msg[0] = NOP;
             }
-         ucp = hostdata->outgoing_msg;
-         i = hostdata->outgoing_len;
-         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+         transfer_pio(regp, hostdata->outgoing_msg, hostdata->outgoing_len,
+                            DATA_OUT_DIR, hostdata);
 DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
          hostdata->outgoing_len = 0;
          hostdata->state = S_CONNECTED;
          break;
 
 
-      case CSR_DISC:
-DB(DB_INTR,printk("DISC"))
+      case CSR_UNEXP_DISC:
+
+/* I think I've seen this after a request-sense that was in response
+ * to an error condition, but not sure. We certainly need to do
+ * something when we get this interrupt - the question is 'what?'.
+ * Let's think positively, and assume some command has finished
+ * in a legal manner (like a command that provokes a request-sense),
+ * so we treat it as a normal command-complete-disconnect.
+ */
+
+         cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
          if (cmd == NULL) {
             printk(" - Already disconnected! ");
             hostdata->state = S_UNCONNECTED;
             return;
             }
+DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
+         hostdata->connected = NULL;
+         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+         hostdata->state = S_UNCONNECTED;
+         if (cmd->cmnd[0] != REQUEST_SENSE)
+            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+         else if (cmd->SCp.Status != GOOD)
+            cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+         cmd->scsi_done(cmd);
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+         wd33c93_execute(instance);
+         break;
+
+
+      case CSR_DISC:
+         cli();
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+         write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER);
+DB(DB_INTR,printk("DISC-%ld",cmd->pid))
+         if (cmd == NULL) {
+            printk(" - Already disconnected! ");
+            hostdata->state = S_UNCONNECTED;
+            }
          switch (hostdata->state) {
             case S_PRE_CMP_DISC:
                hostdata->connected = NULL;
@@ -912,7 +1133,7 @@
                   cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
                else if (cmd->SCp.Status != GOOD)
                   cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-               cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+               cmd->scsi_done(cmd);
                break;
             case S_PRE_TMP_DISC:
             case S_RUNNING_LEVEL2:
@@ -920,6 +1141,11 @@
                hostdata->disconnected_Q = cmd;
                hostdata->connected = NULL;
                hostdata->state = S_UNCONNECTED;
+
+#ifdef PROC_INTERFACE
+               disc_taken_total++;
+#endif
+
                break;
             default:
                printk("*** Unexpected DISCONNECT interrupt! ***");
@@ -943,7 +1169,7 @@
    /* happen during Arbitration/Selection of some other device. */
    /* If yes, put losing command back on top of input_Q. */
 
-         if (hostdata->level2 == L2_NONE) {
+         if (hostdata->level2 <= L2_NONE) {
 
             if (hostdata->selecting) {
                cmd = (Scsi_Cmnd *)hostdata->selecting;
@@ -971,7 +1197,7 @@
 
             }
 
-   /* OK - find out which device reslected us. */
+   /* OK - find out which device reselected us. */
 
          id = read_wd33c93(regp, WD_SOURCE_ID);
          id &= SRCID_MASK;
@@ -1034,9 +1260,11 @@
          break;
          
       default:
-         printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs);
+         printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
       }
 
+   restore_flags(flags);
+
 DB(DB_INTR,printk("} "))
 
 }
@@ -1056,7 +1284,7 @@
                  instance->this_id | hostdata->clock_freq);
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
    write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER,
-                 calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF));
+                 calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF));
    write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET);
 
    while (!(READ_AUX_STAT() & ASR_INT))
@@ -1080,26 +1308,44 @@
       hostdata->chip = C_UNKNOWN_CHIP;
 
    write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
-   if (hostdata->args & A_NO_DISCONNECT)
-      write_wd33c93(regp, WD_SOURCE_ID, 0);
-   else
-      write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER);
    write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
 }
 
 
 
+#if LINUX_VERSION_CODE >= 0x010300
+int wd33c93_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+#else
 int wd33c93_reset(Scsi_Cmnd *SCpnt)
+#endif
 {
 unsigned long flags;
 struct Scsi_Host *instance;
+struct WD33C93_hostdata *hostdata;
+int i;
 
    instance = SCpnt->host;
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
    printk("scsi%d: reset. ", instance->host_no);
    save_flags(flags);
    cli();
+
    ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0);
+   for (i = 0; i < 8; i++) {
+      hostdata->busy[i] = 0;
+      hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
+      hostdata->sync_stat[i] = SS_UNSET;  /* using default sync values */
+      }
+   hostdata->input_Q = NULL;
+   hostdata->selecting = NULL;
+   hostdata->connected = NULL;
+   hostdata->disconnected_Q = NULL;
+   hostdata->state = S_UNCONNECTED;
+   hostdata->dma = D_DMA_OFF;
+   hostdata->incoming_ptr = 0;
+   hostdata->outgoing_len = 0;
+
    reset_wd33c93(instance);
    SCpnt->result = DID_RESET << 16;
    restore_flags(flags);
@@ -1113,38 +1359,41 @@
 struct Scsi_Host *instance;
 struct WD33C93_hostdata *hostdata;
 wd33c93_regs *regp;
-Scsi_Cmnd *tmp, **prev;
+Scsi_Cmnd *tmp, *prev;
 unsigned long flags;
 
+   save_flags (flags);
+   cli();
+
    instance = cmd->host;
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
    regp = hostdata->regp;
 
-   printk ("scsi%d: abort. ", instance->host_no);
-
-   save_flags (flags);
-   cli();
-
 /*
  * Case 1 : If the command hasn't been issued yet, we simply remove it
- *     from the issue queue.
+ *     from the input_Q.
  */
-   for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q;
-         tmp;
-         prev=(Scsi_Cmnd **)&(tmp->host_scribble),tmp=(Scsi_Cmnd *)tmp->host_scribble)
-      if (cmd == tmp) {
-         (*prev) = (Scsi_Cmnd *)tmp->host_scribble;
-         tmp->host_scribble = NULL;
-         tmp->result = DID_ABORT << 16;
+
+   tmp = (Scsi_Cmnd *)hostdata->input_Q;
+   prev = 0;
+   while (tmp) {
+      if (tmp == cmd) {
+         if (prev)
+            prev->host_scribble = cmd->host_scribble;
+         cmd->host_scribble = NULL;
+         cmd->result = DID_ABORT << 16;
+         printk("scsi%d: Abort - removing command %ld from input_Q. ",
+           instance->host_no, cmd->pid);
+         cmd->scsi_done(cmd);
          restore_flags(flags);
-         printk("scsi%d : abort removed command from issue queue. ",
-           instance->host_no);
-         tmp->scsi_done(tmp);
          return SCSI_ABORT_SUCCESS;
          }
+      prev = tmp;
+      tmp = (Scsi_Cmnd *)tmp->host_scribble;
+      }
 
 /*
- * Case 2 : If any commands are connected, we're going to fail the abort
+ * Case 2 : If the command is connected, we're going to fail the abort
  *     and let the high level SCSI driver retry at a later time or
  *     issue a reset.
  *
@@ -1158,20 +1407,22 @@
       uchar sr, asr;
       unsigned long timeout;
 
-      printk("scsi%d : aborting connected command. ", instance->host_no);
+      printk("scsi%d: Aborting connected command %ld - ",
+              instance->host_no, cmd->pid);
 
+      printk("stopping DMA - ");
       if (hostdata->dma == D_DMA_RUNNING) {
          hostdata->dma_stop(instance, cmd, 0);
          hostdata->dma = D_DMA_OFF;
          }
 
-         printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT());
-
+      printk("sending wd33c93 ABORT command - ");
       write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
       write_wd33c93_cmd(regp, WD_CMD_ABORT);
 
 /* Now we have to attempt to flush out the FIFO... */
 
+      printk("flushing fifo - ");
       timeout = 1000000;
       do {
          asr = READ_AUX_STAT();
@@ -1179,46 +1430,34 @@
             read_wd33c93(regp, WD_DATA);
          } while (!(asr & ASR_INT) && timeout-- > 0);
       sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : wd33c93 sr is %x. ", instance->host_no,
-         read_wd33c93(regp, WD_SCSI_STATUS));
+      printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
+             asr, sr, read_wd33c93_count(regp), timeout);
 
-      if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) {
    /*
     * Abort command processed.
     * Still connected.
     * We must disconnect.
     */
-         printk("scsi%d : count was %ld. ", instance->host_no,
-            read_wd33c93_count(regp));
 
-         timeout = 1000000;
-         while ((asr & ASR_CIP) && timeout-- > 0)
-            asr = READ_AUX_STAT();
-         write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
-         asr = READ_AUX_STAT();
-         if (asr & ASR_LCI)
-            printk ("scsi%d: disconnect command ignored. ",
-               instance->host_no);
-         timeout = 1000000;
-         while ((asr & ASR_CIP) && timeout-- > 0)
-            asr = READ_AUX_STAT();
-         }
-      asr = READ_AUX_STAT();
-      sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
+      printk("sending wd33c93 DISCONNECT command - ");
       write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
+
       timeout = 1000000;
+      asr = READ_AUX_STAT();
       while ((asr & ASR_CIP) && timeout-- > 0)
          asr = READ_AUX_STAT();
       sr = read_wd33c93(regp, WD_SCSI_STATUS);
-      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
-      reset_wd33c93(instance);
-      cmd->result = DID_ABORT << 16;
-      cmd->scsi_done(cmd);
+      printk("asr=%02x, sr=%02x.",asr,sr);
+
       hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
       hostdata->connected = NULL;
       hostdata->state = S_UNCONNECTED;
+      cmd->result = DID_ABORT << 16;
+      cmd->scsi_done(cmd);
+
+/*      sti();*/
       wd33c93_execute (instance);
+
       restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
@@ -1229,12 +1468,17 @@
  * an ABORT_SNOOZE and hope for the best...
  */
 
-   for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
-         tmp=(Scsi_Cmnd *)tmp->host_scribble)
-      if (cmd == tmp) {
+   tmp = (Scsi_Cmnd *)hostdata->disconnected_Q;
+   while (tmp) {
+      if (tmp == cmd) {
+         printk("scsi%d: Abort - command %ld found on disconnected_Q - ",
+                 instance->host_no, cmd->pid);
+         printk("returning ABORT_SNOOZE. ");
          restore_flags(flags);
          return SCSI_ABORT_SNOOZE;
          }
+      tmp = (Scsi_Cmnd *)tmp->host_scribble;
+      }
 
 /*
  * Case 4 : If we reached this point, the command was not found in any of
@@ -1242,29 +1486,101 @@
  *
  * We probably reached this point because of an unlikely race condition
  * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case somethign really
+ * so we won't panic, but we will notify the user in case something really
  * broke.
  */
 
+/*   sti();*/
+   wd33c93_execute (instance);
+
    restore_flags(flags);
-   printk("scsi%d : warning : SCSI command probably completed successfully\n"
+   printk("scsi%d: warning : SCSI command probably completed successfully"
       "         before abortion. ", instance->host_no);
    return SCSI_ABORT_NOT_RUNNING;
 }
 
 
 
-#define MAX_WD33C93_HOSTS 8
-static unsigned int setup_args_array[MAX_WD33C93_HOSTS];
-static int setup_args_array_x = 0;
+#define MAX_WD33C93_HOSTS 4
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
 
 void wd33c93_setup (char *str, int *ints)
 {
-int i;
+int i,x;
+char *p1,*p2;
+
+   /* The kernel does some processing of the command-line before calling
+    * this function: If it begins with any decimal or hex number arguments,
+    * ints[0] = how many numbers found and ints[1] through [n] are the values
+    * themselves. str points to where the non-numeric arguments (if any)
+    * start: We do our own parsing of those. We construct synthetic 'nosync'
+    * keywords out of numeric args (to maintain compatibility with older
+    * versions) and then add the rest of the arguments.
+    */
+
+   p1 = setup_buffer;
+   *p1 = '\0';
+   if (ints[0]) {
+      for (i=0; i<ints[0]; i++) {
+         x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1]));
+         p1 += x;
+         }
+      }
+   if (str)
+      strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+   setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+   p1 = setup_buffer;
+   i = 0;
+   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+      p2 = strchr(p1, ',');
+      if (p2) {
+         *p2 = '\0';
+         if (p1 != p2)
+            setup_strings[i] = p1;
+         p1 = p2 + 1;
+         i++;
+         }
+      else {
+         setup_strings[i] = p1;
+         break;
+         }
+      }
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
 
-   for (i=0; i<ints[0]; i++) {
-      setup_args_array[i] = ints[i+1];
+   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+      if (setup_used[x])
+         continue;
+      if (!strncmp(setup_strings[x], key, strlen(key)))
+         break;
+      if (!strncmp(setup_strings[x], "next", strlen("next")))
+         return 0;
+      }
+   if (x == MAX_SETUP_STRINGS)
+      return 0;
+   setup_used[x] = 1;
+   cp = setup_strings[x] + strlen(key);
+   *val = -1;
+   if (*cp != ':')
+      return ++x;
+   cp++;
+   if ((*cp >= '0') && (*cp <= '9')) {
+      *val = simple_strtoul(cp,NULL,0);
       }
+   return ++x;
 }
 
 
@@ -1274,6 +1590,9 @@
 {
 struct WD33C93_hostdata *hostdata;
 int i;
+int flags;
+int val;
+char buf[32];
 
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
@@ -1294,46 +1613,226 @@
    hostdata->disconnected_Q = NULL;
    hostdata->state = S_UNCONNECTED;
    hostdata->dma = D_DMA_OFF;
+   hostdata->level2 = L2_BASIC;
+   hostdata->disconnect = DIS_ADAPTIVE;
+   hostdata->args = DEBUG_DEFAULTS;
    hostdata->incoming_ptr = 0;
    hostdata->outgoing_len = 0;
+   hostdata->default_sx_per = DEFAULT_SX_PER;
+   hostdata->no_sync = 0xff;     /* sync defaults to off */
+
+#ifdef PROC_INTERFACE
+   hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS|
+                    PR_CONNECTED|PR_INPUTQ|PR_DISCQ|
+                    PR_STOP;
+
+   disc_allowed_total = 0;
+   disc_taken_total = 0;
+#endif
+
+
+   if (check_setup_strings("nosync",&flags,&val,buf))
+      hostdata->no_sync = val;
+
+   if (check_setup_strings("period",&flags,&val,buf))
+      hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
+
+   if (check_setup_strings("disconnect",&flags,&val,buf)) {
+      if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
+         hostdata->disconnect = val;
+      else
+         hostdata->disconnect = DIS_ADAPTIVE;
+      }
+
+   if (check_setup_strings("debug",&flags,&val,buf))
+      hostdata->args = val & DB_MASK;
+
+   if (check_setup_strings("clock",&flags,&val,buf)) {
+      if (val>7 && val<11)
+         val = WD33C93_FS_8_10;
+      else if (val>11 && val<16)
+         val = WD33C93_FS_12_15;
+      else if (val>15 && val<21)
+         val = WD33C93_FS_16_20;
+      else
+         val = WD33C93_FS_8_10;
+      hostdata->clock_freq = val;
+      }
+
+   if ((i = check_setup_strings("next",&flags,&val,buf))) {
+      while (i)
+         setup_used[--i] = 1;
+      }
+
+#ifdef PROC_INTERFACE
+   if (check_setup_strings("proc",&flags,&val,buf))
+      hostdata->proc = val;
+#endif
 
-   hostdata->args = setup_default;
-   if ((setup_args_array_x < MAX_WD33C93_HOSTS) &&
-       (setup_args_array[setup_args_array_x]))
-      hostdata->args = setup_args_array[setup_args_array_x];
-   setup_args_array_x++;
-
-   i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2);
-   i >>= 8;
-   if (i == 0)
-      i = L2_DEFAULT;
-   hostdata->level2 = i;
 
    cli();
    reset_wd33c93(instance);
    sti();
 
-   printk("wd33c93-%d: ",instance->host_no);
-   switch (hostdata->chip) {
-      case C_WD33C93:
-         printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n");
-         break;
-      case C_WD33C93A:
-         printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode);
-         break;
-      case C_WD33C93B:
-         printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode);
-         break;
-      default:
-         printk("Unknown 3393 chip!\n");
-      }
-   printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no,
-            (hostdata->level2 == L2_NONE)?"disabled":"enabled",
-            hostdata->level2);
+   printk("wd33c93-%d: chip=%s microcode=%02x\n",instance->host_no,
+         (hostdata->chip==C_WD33C93)?"WD33c93":
+         (hostdata->chip==C_WD33C93A)?"WD33c93A":
+         (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
+         hostdata->microcode);
+
 #ifdef DEBUGGING_ON
+   printk("wd33c93-%d: setup_strings=",instance->host_no);
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      printk("%s,",setup_strings[i]);
+   printk("\n");
    printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args);
 #endif
    printk("wd33c93-%d: driver version %s - %s\n",instance->host_no,
                      WD33C93_VERSION,WD33C93_DATE);
+   printk("wd33c93-%d: compiled on %s at %s\n",instance->host_no,
+                     __DATE__,__TIME__);
+}
+
+
+int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
+{
+
+#ifdef PROC_INTERFACE
+
+char *bp;
+char tbuf[128];
+unsigned long flags;
+struct Scsi_Host *instance;
+struct WD33C93_hostdata *hd;
+Scsi_Cmnd *cmd;
+int x,i;
+static int stop = 0;
+
+   for (instance=instance_list; instance; instance=instance->next) {
+      if (instance->host_no == hn)
+         break;
+      }
+   if (!instance) {
+      printk("*** Hmm... Can't find host #%d!\n",hn);
+      return (-ESRCH);
+      }
+   hd = (struct WD33C93_hostdata *)instance->hostdata;
+
+/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
+ * keywords (same format as command-line, but only ONE per read):
+ *    debug
+ *    disconnect
+ *    period
+ *    resync
+ *    proc
+ */
+
+   if (in) {
+      buf[len] = '\0';
+      bp = buf;
+      if (!strncmp(bp,"debug:",6)) {
+         bp += 6;
+         hd->args = simple_strtoul(bp,NULL,0) & DB_MASK;
+         }
+      else if (!strncmp(bp,"disconnect:",11)) {
+         bp += 11;
+         x = simple_strtoul(bp,NULL,0);
+         if (x < DIS_NEVER || x > DIS_ALWAYS)
+            x = DIS_ADAPTIVE;
+         hd->disconnect = x;
+         }
+      else if (!strncmp(bp,"period:",7)) {
+         bp += 7;
+         x = simple_strtoul(bp,NULL,0);
+         hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns;
+         }
+      else if (!strncmp(bp,"resync:",7)) {
+         bp += 7;
+         x = simple_strtoul(bp,NULL,0);
+         for (i=0; i<7; i++)
+            if (x & (1<<i))
+               hd->sync_stat[i] = SS_UNSET;
+         }
+      else if (!strncmp(bp,"proc:",5)) {
+         bp += 5;
+         hd->proc = simple_strtoul(bp,NULL,0);
+         }
+      return len;
+      }
+
+   save_flags(flags);
+   cli();
+   bp = buf;
+   *bp = '\0';
+   if (hd->proc & PR_VERSION) {
+      sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s",
+            WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__);
+      strcat(bp,tbuf);
+      }
+   if (hd->proc & PR_INFO) {
+      ;
+      }
+   if (hd->proc & PR_TOTALS) {
+      sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken",
+            disc_allowed_total,disc_taken_total);
+      strcat(bp,tbuf);
+      }
+   if (hd->proc & PR_CONNECTED) {
+      strcat(bp,"\nconnected:     ");
+      if (hd->connected) {
+         cmd = (Scsi_Cmnd *)hd->connected;
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         }
+      }
+   if (hd->proc & PR_INPUTQ) {
+      strcat(bp,"\ninput_Q:       ");
+      cmd = (Scsi_Cmnd *)hd->input_Q;
+      while (cmd) {
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         cmd = (Scsi_Cmnd *)cmd->host_scribble;
+         }
+      }
+   if (hd->proc & PR_DISCQ) {
+      strcat(bp,"\ndisconnected_Q:");
+      cmd = (Scsi_Cmnd *)hd->disconnected_Q;
+      while (cmd) {
+         sprintf(tbuf," %ld-%d:%d(%02x)",
+               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+         strcat(bp,tbuf);
+         cmd = (Scsi_Cmnd *)cmd->host_scribble;
+         }
+      }
+   strcat(bp,"\n");
+   restore_flags(flags);
+   *start = buf;
+   if (stop) {
+      stop = 0;
+      return 0;
+      }
+   if (off > 0x40000)   /* ALWAYS stop after 256k bytes have been read */
+      stop = 1;;
+   if (hd->proc & PR_STOP)    /* stop every other time */
+      stop = 1;
+   return strlen(bp);
+
+#else    /* PROC_INTERFACE */
+
+   return 0;
+
+#endif   /* PROC_INTERFACE */
+
 }
+
+
+#ifdef MODULE
+
+Scsi_Host_Template driver_template = WD33C93;
+
+#include "scsi_module.c"
+
+#endif
 
diff -u --recursive --new-file v1.3.95/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h
--- v1.3.95/linux/drivers/scsi/wd33c93.h	Tue Apr 23 13:57:10 1996
+++ linux/drivers/scsi/wd33c93.h	Fri Apr 26 12:12:33 1996
@@ -1,10 +1,9 @@
-#ifndef WD33C93_H
-#define WD33C93_H
-
 /*
  *    wd33c93.h -  Linux device driver definitions for the
  *                 Commodore Amiga A2091/590 SCSI controller card
  *
+ *    IMPORTANT: This file is for version 1.21 - 20/Mar/1996
+ *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
  *    jshiffle@netcom.com
@@ -21,6 +20,8 @@
  *
  */
 
+#ifndef WD33C93_H
+#define WD33C93_H
 
 
 #define uchar unsigned char
@@ -151,7 +152,7 @@
 #define CTRL_DMA     0x80
 
    /* Timeout Period register */
-#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
+#define TIMEOUT_PERIOD_VALUE  20    /* 20 = 200 ms */
 
    /* Synchronous Transfer Register */
 #define STR_FSS      0x80
@@ -193,18 +194,23 @@
    uchar          reg_value;
    };
 
+/* FEF: defines for hostdata->dma_buffer_pool */
+
+#define BUF_CHIP_ALLOCED 0
+#define BUF_SCSI_ALLOCED 1
 
 struct WD33C93_hostdata {
     struct Scsi_Host *next;
     wd33c93_regs     *regp;
     uchar            clock_freq;
     uchar            chip;             /* what kind of wd33c93? */
-    uchar            microcode;        /* microcode rev if 'B' */
+    uchar            microcode;        /* microcode rev */
     int              dma_dir;          /* data transfer dir. */
     dma_setup_t      dma_setup;
     dma_stop_t       dma_stop;
     uchar            *dma_bounce_buffer;
     unsigned int     dma_bounce_len;
+    uchar            dma_buffer_pool;  /* FEF: buffer from chip_ram? */
     volatile uchar   busy[8];          /* index = target, bit = lun */
     volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
     volatile Scsi_Cmnd *selecting;     /* trying to select this command */
@@ -213,13 +219,19 @@
     uchar            state;            /* what we are currently doing */
     uchar            dma;              /* current state of DMA (on/off) */
     uchar            level2;           /* extent to which Level-2 commands are used */
+    uchar            disconnect;       /* disconnect/reselect policy */
     unsigned int     args;             /* set from command-line argument */
     uchar            incoming_msg[8];  /* filled during message_in phase */
     int              incoming_ptr;     /* mainly used with EXTENDED messages */
     uchar            outgoing_msg[8];  /* send this during next message_out */
     int              outgoing_len;     /* length of outgoing message */
+    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
     uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
     uchar            sync_stat[8];     /* status of sync negotiation per target */
+    uchar            no_sync;          /* bitmask: don't do sync on these targets */
+#if 0
+    uchar            proc;             /* bitmask: what's in proc output */
+#endif
     };
 
 
@@ -245,34 +257,31 @@
 #define D_DMA_RUNNING      1
 
 /* defines for hostdata->level2 */
-/* NOTE: only the first 3 are implemented so far - having trouble
- * when more than 1 device is reading/writing at the same time...
- */
+/* NOTE: only the first 3 are implemented so far */
 
-#define L2_NONE      1  /* no combination commands - we get lots of ints */
+/*  (The first 8 bits are reserved for compatibility. They function
 #define L2_SELECT    2  /* start with SEL_ATN_XFER, but never resume it */
 #define L2_BASIC     3  /* resume after STATUS ints & RDP messages */
 #define L2_DATA      4  /* resume after DATA_IN/OUT ints */
 #define L2_MOST      5  /* resume after anything except a RESELECT int */
 #define L2_RESELECT  6  /* resume after everything, including RESELECT ints */
 #define L2_ALL       7  /* always resume */
-#define L2_DEFAULT   L2_BASIC
+
+/* defines for hostdata->disconnect */
+
+#define DIS_NEVER    0
+#define DIS_ADAPTIVE 1
+#define DIS_ALWAYS   2
 
 /* defines for hostdata->args */
-/*  (The first 8 bits are reserved for compatability. They function
- *   as they did in the old driver - note that turning off sync_xfer
- *   on a target affects all LUNs at that SCSI id.)
- */
 
-#define A_LEVEL2_0            1<<8
-#define A_LEVEL2_1            1<<9
-#define A_LEVEL2_2            1<<10
-#define A_NO_DISCONNECT       1<<11
-
-#define DB_QUEUE_COMMAND      1<<12
-#define DB_EXECUTE            1<<13
-#define DB_INTR               1<<14
-#define DB_TRANSFER_DATA      1<<15
+#define DB_TEST1              1<<0
+#define DB_TEST2              1<<1
+#define DB_QUEUE_COMMAND      1<<2
+#define DB_EXECUTE            1<<3
+#define DB_INTR               1<<4
+#define DB_TRANSFER           1<<5
+#define DB_MASK               0x3f
 
 /* defines for hostdata->sync_stat[] */
 
@@ -281,12 +290,33 @@
 #define SS_WAITING   2
 #define SS_SET       3
 
+/* defines for hostdata->proc */
+
+#define PR_VERSION   1<<0
+#define PR_INFO      1<<1
+#define PR_TOTALS    1<<2
+#define PR_CONNECTED 1<<3
+#define PR_INPUTQ    1<<4
+#define PR_DISCQ     1<<5
+#define PR_TEST      1<<6
+#define PR_STOP      1<<7
+
 
 void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
          dma_setup_t setup, dma_stop_t stop, int clock_freq);
 int wd33c93_abort (Scsi_Cmnd *cmd);
-int wd33c93_reset (Scsi_Cmnd *);
 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 void wd33c93_intr (struct Scsi_Host *instance);
+int wd33c93_proc_info(char *, char **, off_t, int, int, int);
+
+#if LINUX_VERSION_CODE >= 0x010300
+int wd33c93_reset (Scsi_Cmnd *, unsigned int);
+#else
+int wd33c93_reset (Scsi_Cmnd *);
+#endif
+
+#if 0
+struct proc_dir_entry proc_scsi_wd33c93;
+#endif
 
 #endif /* WD33C93_H */
diff -u --recursive --new-file v1.3.95/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v1.3.95/linux/drivers/sound/dmasound.c	Tue Apr 23 13:57:11 1996
+++ linux/drivers/sound/dmasound.c	Fri Apr 26 12:12:34 1996
@@ -475,7 +475,7 @@
 } TRANS;
 
 struct sound_settings {
-    MACHINE mach;	/* machine dependend things */
+    MACHINE mach;	/* machine dependent things */
     SETTINGS hard;	/* hardware settings */
     SETTINGS soft;	/* software settings */
     SETTINGS dsp;	/* /dev/dsp default settings */
@@ -676,11 +676,11 @@
  * I think I've optimized anything as far as one can do in plain C, all
  * variables should fit in registers and the loops are really short. There's
  * one loop for every possible situation. Writing a more generalized and thus
- * parametrized loop would only produce slower code. Feel free to optimize
+ * parameterized loop would only produce slower code. Feel free to optimize
  * this in assembler if you like. :)
  *
  * I think these routines belong here because they're not yet really hardware
- * independend, especially the fact that the Falcon can play 16bit samples
+ * independent, especially the fact that the Falcon can play 16bit samples
  * only in stereo is hardcoded in both of them!
  *
  * ++geert: split in even more functions (one per format)
@@ -1872,7 +1872,7 @@
      * 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
-     * whereever possible: There's no need to reload the DMA at the exact
+     * 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!
      */
@@ -2755,7 +2755,7 @@
     while (sq.playing) {
 	SLEEP(sq.sync_queue, ONE_SECOND);
 	if (SIGNAL_RECEIVED) {
-	    /* While waiting for audio output to drain, an interrupt occured.
+	    /* While waiting for audio output to drain, an interrupt occurred.
 	       Stop audio output immediately and clear the queue. */
 	    sq_reset();
 	    rc = -EINTR;
@@ -2775,7 +2775,7 @@
 	rc = sq_sync();
 	sq.busy = 0;
 	WAKE_UP(sq.open_queue);
-	/* Wake up a process waiting for the queue beeing released.
+	/* Wake up a process waiting for the queue being released.
 	   Note: There may be several processes waiting for a call to open()
 		 returning. */
     }
diff -u --recursive --new-file v1.3.95/linux/fs/Config.in linux/fs/Config.in
--- v1.3.95/linux/fs/Config.in	Tue Apr 23 13:57:11 1996
+++ linux/fs/Config.in	Fri Apr 26 12:16:09 1996
@@ -34,6 +34,10 @@
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-bool 'AFFS filesystem support' CONFIG_AFFS_FS
-bool 'UFS filesystem support (read only)' CONFIG_UFS_FS
+tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS
+tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
+if [ "$CONFIG_UFS_FS" != "n" ]; then
+  bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL
+  bool "SMD disklabel (Sun partition tables) support" CONFIG_SMD_DISKLABEL
+fi
 endmenu
diff -u --recursive --new-file v1.3.95/linux/fs/Makefile linux/fs/Makefile
--- v1.3.95/linux/fs/Makefile	Tue Apr 23 13:57:11 1996
+++ linux/fs/Makefile	Fri Apr 26 12:16:09 1996
@@ -143,10 +143,18 @@
 
 ifeq ($(CONFIG_UFS_FS),y)
 SUB_DIRS += ufs
+else
+  ifeq ($(CONFIG_UFS_FS),m)
+  MOD_SUB_DIRS += ufs
+  endif
 endif
 
 ifeq ($(CONFIG_AFFS_FS),y)
 SUB_DIRS += affs
+else
+  ifeq ($(CONFIG_AFFS_FS),m)
+  MOD_SUB_DIRS += affs
+  endif
 endif
 
 ifeq ($(CONFIG_BINFMT_ELF),y)
diff -u --recursive --new-file v1.3.95/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v1.3.95/linux/fs/affs/amigaffs.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/affs/amigaffs.c	Fri Apr 26 12:12:24 1996
@@ -1,10 +1,15 @@
 /*
  *  linux/fs/affs/amigaffs.c
  *
+ *  (C) 1996  Stefan Reinauer - Modified to compile as Module
+ *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
  */
 
+
+#include <linux/module.h>
+
 #include <linux/fs.h>
 #include <linux/affs_fs.h>
 #include <linux/mm.h>
@@ -91,7 +96,7 @@
         return file_end->file_name[0];
 }
 
-/* Get the key number of the first extention block for the file
+/* Get the key number of the first extension block for the file
    header pointed to by FH_DATA. */
 
 int affs_get_extension (int bsize, void *fh_data)
@@ -127,4 +132,21 @@
 {
         return register_filesystem(&affs_fs_type);
 }
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_affs_fs()) == 0)
+	        register_symtab(0);
+	return status;
+}
+
+void cleanup_module(void)
+{
+	unregister_filesystem(&affs_fs_type);
+}
+
+#endif
 
diff -u --recursive --new-file v1.3.95/linux/fs/affs/amigaffs.h linux/fs/affs/amigaffs.h
--- v1.3.95/linux/fs/affs/amigaffs.h	Tue Apr 23 13:57:11 1996
+++ linux/fs/affs/amigaffs.h	Fri Apr 26 12:12:24 1996
@@ -180,7 +180,7 @@
   LONG primary_type;
   ULONG own_key;
   LONG unused[3];
-  ULONG checkksum;
+  ULONG checksum;
 };
 
 struct hardlink_end
diff -u --recursive --new-file v1.3.95/linux/fs/affs/file.c linux/fs/affs/file.c
--- v1.3.95/linux/fs/affs/file.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/affs/file.c	Fri Apr 26 12:12:24 1996
@@ -115,7 +115,7 @@
 /*
  * affs_file_read() is also needed by the directory read-routine,
  * so it's not static. NOTE! reading directories directly is a bad idea,
- * but has to be supported for now for compatability reasons with older
+ * but has to be supported for now for compatibility reasons with older
  * versions.
  */
 int affs_file_read(struct inode * inode, struct file * filp,
diff -u --recursive --new-file v1.3.95/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v1.3.95/linux/fs/affs/inode.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/affs/inode.c	Fri Apr 26 12:12:24 1996
@@ -294,7 +294,7 @@
 		}
 
 		file_front = (struct file_front *) fh_data;
-		file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as  dir_end */
+		file_end = GET_END_PTR (struct file_end, fh_data, /* coincidently the same as  dir_end */
 					AFFS_I2BSIZE (inode));
 
 		/* don't use bitmap data for mode, uid & gid of the rootblock */
@@ -305,7 +305,7 @@
 			inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ;  /* drwxrwxrwt */
 			inode->i_nlink = 2; /* at least ..... */
 
-			inode->i_size = 0;  /* some differrent idea ? */
+			inode->i_size = 0;  /* some different idea ? */
 
 			inode->i_uid = 0;
 			inode->i_gid = 0;
@@ -340,7 +340,7 @@
 				     probably spend some time on this */
 					link_end = (struct hardlink_end *)file_end;
 					inode->i_ino = link_end->original;
-					inode->i_nlink += 2; /* It's hard to say whats correct */
+					inode->i_nlink += 2; /* It's hard to say what's correct */
 					brelse(bh);
 					link = 1;
 				break;
diff -u --recursive --new-file v1.3.95/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v1.3.95/linux/fs/binfmt_aout.c	Fri Mar 15 15:22:59 1996
+++ linux/fs/binfmt_aout.c	Fri Apr 26 10:30:51 1996
@@ -227,7 +227,7 @@
 	envp = sp;
 	sp -= argc+1;
 	argv = sp;
-#ifdef __i386__
+#if defined(__i386__) || defined(__mc68000__)
 	put_user(envp,--sp);
 	put_user(argv,--sp);
 #endif
diff -u --recursive --new-file v1.3.95/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.95/linux/fs/buffer.c	Wed Apr 24 17:00:41 1996
+++ linux/fs/buffer.c	Thu Apr 25 13:45:53 1996
@@ -211,7 +211,7 @@
 				 printk("[%d %s %ld] ", nlist,
 					kdevname(bh->b_dev), bh->b_blocknr);
 				 ncount++;
-			 };
+			 }
 			 bh->b_count--;
 			 retry = 1;
 		 }
@@ -373,7 +373,7 @@
 		remove_from_free_list(bh); /* Free list entries should not be
 					      in the hash queue */
 		return;
-	};
+	}
 	nr_buffers_type[bh->b_list]--;
 	nr_buffers_st[BUFSIZE_INDEX(bh->b_size)][bh->b_list]--;
 	remove_from_hash_queue(bh);
@@ -420,7 +420,7 @@
 	if(!free_list[isize]) {
 		free_list[isize] = bh;
 		bh->b_prev_free = bh;
-	};
+	}
 
 	nr_free[isize]++;
 	bh->b_next_free = free_list[isize];
@@ -919,15 +919,19 @@
 	index = BUFSIZE_INDEX(bh->b_size);
 
 	if (buffer_uptodate(bh))
-		return bh;
+	        return(bh);   
+	else ll_rw_block(READ, 1, &bh);
 
-	blocks = ((filesize & (bufsize - 1)) - (pos & (bufsize - 1))) >> (9+index);
+	blocks = (filesize - pos) >> (9+index);
 
-	if (blocks > (read_ahead[MAJOR(dev)] >> index))
+	if (blocks < (read_ahead[MAJOR(dev)] >> index))
 		blocks = read_ahead[MAJOR(dev)] >> index;
-	if (blocks > NBUF)
+	if (blocks > NBUF) 
 		blocks = NBUF;
-	
+
+/*	if (blocks) printk("breada (new) %d blocks\n",blocks); */
+
+
 	bhlist[0] = bh;
 	j = 1;
 	for(i=1; i<blocks; i++) {
@@ -936,14 +940,14 @@
 			brelse(bh);
 			break;
 		}
-		bhlist[j++] = bh;
+		else bhlist[j++] = bh;
 	}
 
 	/* Request the read for these buffers, and then release them */
-	ll_rw_block(READ, j, bhlist);
-
+	if (j>1)  
+		ll_rw_block(READA, (j-1), bhlist+1); 
 	for(i=1; i<j; i++)
-		brelse(bhlist[i]);
+	        brelse(bhlist[i]);
 
 	/* Wait for this buffer, and then continue on */
 	bh = bhlist[0];
@@ -1928,7 +1932,7 @@
 	for(isize = 0; isize<NR_SIZES; isize++){
 		CALC_LOAD(buffers_lav[isize], bdf_prm.b_un.lav_const, buffer_usage[isize]);
 		buffer_usage[isize] = 0;
-	};
+	}
 	return 0;
 }
 
@@ -1964,7 +1968,7 @@
 			return -EINVAL;
 		bdf_prm.data[i] = data;
 		return 0;
-	}
+	};
 
 	/* Having func 0 used to launch the actual bdflush and then never
 	return (unless explicitly killed). We return zero here to 
diff -u --recursive --new-file v1.3.95/linux/fs/fat/buffer.c linux/fs/fat/buffer.c
--- v1.3.95/linux/fs/fat/buffer.c	Fri Feb  9 07:47:16 1996
+++ linux/fs/fat/buffer.c	Thu Apr 25 12:29:39 1996
@@ -16,9 +16,11 @@
 {
 	struct buffer_head *ret = NULL;
 	if (sb->s_blocksize == 512){
-		ret = bread (sb->s_dev,block,512);
+/*		ret = bread (sb->s_dev,block,512); */
+		ret = breada (sb->s_dev,block,512,0,18*1024); 
 	}else{
-		struct buffer_head *real = bread (sb->s_dev,block>>1,1024);
+/*		struct buffer_head *real = bread (sb->s_dev,block>>1,1024); */
+		struct buffer_head *real = breada (sb->s_dev,block>>1,1024,0,18*1024); 
 		if (real != NULL){
 			ret = (struct buffer_head *)kmalloc (sizeof(struct buffer_head)
 				,GFP_KERNEL);
diff -u --recursive --new-file v1.3.95/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v1.3.95/linux/fs/fat/cache.c	Fri Feb  9 07:47:16 1996
+++ linux/fs/fat/cache.c	Thu Apr 25 12:29:39 1996
@@ -12,6 +12,7 @@
 
 #include "msbuffer.h"
 
+
 static struct fat_cache *fat_cache,cache[FAT_CACHE];
 
 /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
@@ -29,18 +30,18 @@
 		first = nr*3/2;
 		last = first+1;
 	}
-	if (!(bh = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
-	    SECTOR_BITS),SECTOR_SIZE))) {
-		printk("bread in fat_access failed\n");
+	if (!(bh = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
+	    SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) {
+		printk("breada in fat_access failed\n");
 		return 0;
 	}
 	if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
 		bh2 = bh;
 	else {
-		if (!(bh2 = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
-		    >> SECTOR_BITS),SECTOR_SIZE))) {
+		if (!(bh2 = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
+		    >> SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) {
 			brelse(bh);
-			printk("bread in fat_access failed\n");
+			printk("breada in fat_access failed\n");
 			return 0;
 		}
 	}
@@ -75,16 +76,16 @@
 		}
 		mark_buffer_dirty(bh, 1);
 		for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
-			if (!(c_bh = bread(sb->s_dev,MSDOS_SB(sb)->
+			if (!(c_bh = breada(sb->s_dev,MSDOS_SB(sb)->
 			    fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
-			    fat_length*copy,SECTOR_SIZE))) break;
+			    fat_length*copy,SECTOR_SIZE,0,FAT_READAHEAD))) break;
 			memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
 			mark_buffer_dirty(c_bh, 1);
 			if (bh != bh2) {
-				if (!(c_bh2 = bread(sb->s_dev,
+				if (!(c_bh2 = breada(sb->s_dev,
 				    MSDOS_SB(sb)->fat_start+(first >>
 				    SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
-				    +1,SECTOR_SIZE))) {
+				    +1,SECTOR_SIZE,0,FAT_READAHEAD))) {
 					brelse(c_bh);
 					break;
 				}
diff -u --recursive --new-file v1.3.95/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v1.3.95/linux/fs/fat/misc.c	Fri Feb  9 07:47:16 1996
+++ linux/fs/fat/misc.c	Thu Apr 25 12:29:39 1996
@@ -298,7 +298,7 @@
 		if (*bh)
 			brelse(*bh);
 		PRINTK (("get_entry sector apres brelse\n"));
-		if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
+		if (!(*bh = breada(dir->i_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) {
 			printk("Directory sread (sector %d) failed\n",sector);
 			continue;
 		}
@@ -372,7 +372,7 @@
 	struct inode *inode;
 	int entry,start,done;
 
-	if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
+	if (!(bh = breada(sb->s_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) return -EIO;
 	data = (struct msdos_dir_entry *) bh->b_data;
 	for (entry = 0; entry < MSDOS_DPS; entry++) {
 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
diff -u --recursive --new-file v1.3.95/linux/fs/fat/msbuffer.h linux/fs/fat/msbuffer.h
--- v1.3.95/linux/fs/fat/msbuffer.h	Wed Feb  7 09:39:28 1996
+++ linux/fs/fat/msbuffer.h	Thu Apr 25 12:29:39 1996
@@ -1,3 +1,5 @@
+/* Number of bytes to readahead on disc access */
+#define FAT_READAHEAD (18*1024)
 
 struct buffer_head *fat_bread (struct super_block *sb, int block);
 struct buffer_head *fat_getblk (struct super_block *sb, int block);
diff -u --recursive --new-file v1.3.95/linux/fs/fcntl.c linux/fs/fcntl.c
--- v1.3.95/linux/fs/fcntl.c	Mon Apr  8 19:01:44 1996
+++ linux/fs/fcntl.c	Thu Apr 25 13:32:41 1996
@@ -85,6 +85,10 @@
 			if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
 			    filp->f_op->fasync)
 				filp->f_op->fasync(filp->f_inode, filp, 0);
+			/* requiered for SunOS emulation */
+			if (O_NONBLOCK != O_NDELAY)
+			       if (arg & O_NDELAY)
+				   arg |= O_NONBLOCK;
 			filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC);
 			filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
 						FASYNC);
diff -u --recursive --new-file v1.3.95/linux/fs/filesystems.c linux/fs/filesystems.c
--- v1.3.95/linux/fs/filesystems.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/filesystems.c	Thu Apr 25 12:32:39 1996
@@ -22,6 +22,7 @@
 #include <linux/hpfs_fs.h>
 #include <linux/smb_fs.h>
 #include <linux/ncp_fs.h>
+#include <linux/affs_fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/major.h>
 
@@ -99,6 +100,10 @@
 
 #ifdef CONFIG_HPFS_FS
 	init_hpfs_fs();
+#endif
+
+#ifdef CONFIG_AFFS_FS
+	init_affs_fs();
 #endif
 
 #ifdef CONFIG_UFS_FS
diff -u --recursive --new-file v1.3.95/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.3.95/linux/fs/isofs/inode.c	Sun Apr 21 12:39:02 1996
+++ linux/fs/isofs/inode.c	Fri Apr 26 18:05:32 1996
@@ -25,6 +25,7 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 
+#define MULTI_VOLUME
 #ifdef LEAK_CHECK
 static int check_malloc = 0;
 static int check_bread = 0;
@@ -306,8 +307,10 @@
 	if(high_sierra){
 	  rootp = (struct iso_directory_record *) h_pri->root_directory_record;
 	  if (isonum_723 (h_pri->volume_set_size) != 1) {
+#ifndef  MULTI_VOLUME 
 	    printk("Multi-volume disks not (yet) supported.\n");
 	    goto out;
+#endif
 	  };
 	  s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size);
 	  s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size);
@@ -315,8 +318,10 @@
 	} else {
 	  rootp = (struct iso_directory_record *) pri->root_directory_record;
 	  if (isonum_723 (pri->volume_set_size) != 1) {
+#ifndef MULTI_VOLUME
 	    printk("Multi-volume disks not (yet) supported.\n");
 	    goto out;
+#endif
 	  };
 	  s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size);
 	  s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size);
@@ -614,10 +619,13 @@
 	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
 
+#ifndef MULTI_VOLUME
 	if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && 
 	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
 		printk("Multi volume CD somehow got mounted.\n");
-	} else {
+	} else
+#endif	
+	{
 	  if (S_ISREG(inode->i_mode))
 	    inode->i_op = &isofs_file_inode_operations;
 	  else if (S_ISDIR(inode->i_mode))
diff -u --recursive --new-file v1.3.95/linux/fs/locks.c linux/fs/locks.c
--- v1.3.95/linux/fs/locks.c	Wed Apr 24 17:00:41 1996
+++ linux/fs/locks.c	Fri Apr 26 18:56:57 1996
@@ -273,9 +273,18 @@
 		break;
 	case F_SHLCK :
 	case F_EXLCK :
+#if 1
+/* warn a bit for now, but don't overdo it */
+{
+	static int count = 0;
+	if (count < 5) {
+		count++;
 		printk(KERN_WARNING
 		       "fcntl_setlk() called by process %d with broken flock() emulation\n",
 		       current->pid);
+	}
+}
+#endif
 		if (!(filp->f_mode & 3))
 			return (-EBADF);
 		break;
diff -u --recursive --new-file v1.3.95/linux/fs/nfs/README linux/fs/nfs/README
--- v1.3.95/linux/fs/nfs/README	Fri Apr 12 15:52:04 1996
+++ linux/fs/nfs/README	Thu Apr 25 15:04:50 1996
@@ -13,7 +13,7 @@
     HOW TO USE
 
     This stuff compiles as a loadable module (I developed it on 1.3.77).
-    Simply type mkmodule, and insmod nfs.o. This will start for nfsiod's
+    Simply type mkmodule, and insmod nfs.o. This will start four nfsiod's
     at the same time (which will show up under the pseudonym of insmod in
     ps-style listings).
 
diff -u --recursive --new-file v1.3.95/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v1.3.95/linux/fs/nfs/dir.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/nfs/dir.c	Fri Apr 26 18:40:22 1996
@@ -20,25 +20,19 @@
 
 #include <asm/segment.h>	/* for fs functions */
 
-static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
-			int count);
+static int nfs_dir_open(struct inode * inode, struct file * file);
+static int nfs_dir_read(struct inode *, struct file *, char *, int);
 static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *dir, const char *name, int len,
-		      struct inode **result);
-static int nfs_create(struct inode *dir, const char *name, int len, int mode,
-		      struct inode **result);
-static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode);
-static int nfs_rmdir(struct inode *dir, const char *name, int len);
-static int nfs_unlink(struct inode *dir, const char *name, int len);
-static int nfs_symlink(struct inode *inode, const char *name, int len,
-		       const char *symname);
-static int nfs_link(struct inode *oldinode, struct inode *dir,
-		    const char *name, int len);
-static int nfs_mknod(struct inode *dir, const char *name, int len, int mode,
-		     int rdev);
-static int nfs_rename(struct inode *old_dir, const char *old_name,
-		      int old_len, struct inode *new_dir, const char *new_name,
-		      int new_len);
+static int nfs_lookup(struct inode *, const char *, int, struct inode **);
+static int nfs_create(struct inode *, const char *, int, int, struct inode **);
+static int nfs_mkdir(struct inode *, const char *, int, int);
+static int nfs_rmdir(struct inode *, const char *, int);
+static int nfs_unlink(struct inode *, const char *, int);
+static int nfs_symlink(struct inode *, const char *, int, const char *);
+static int nfs_link(struct inode *, struct inode *, const char *, int);
+static int nfs_mknod(struct inode *, const char *, int, int, int);
+static int nfs_rename(struct inode *, const char *, int,
+		      struct inode *, const char *, int);
 
 static struct file_operations nfs_dir_operations = {
 	NULL,			/* lseek - default */
@@ -48,7 +42,7 @@
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
-	NULL,			/* no special open code */
+	nfs_dir_open,		/* open - revalidate */
 	NULL,			/* no special release code */
 	NULL			/* fsync */
 };
@@ -73,6 +67,29 @@
 	NULL			/* permission */
 };
 
+static inline void revalidate_dir(struct nfs_server * server, struct inode * dir)
+{
+	struct nfs_fattr fattr;
+
+	if (jiffies - NFS_READTIME(dir) < server->acdirmax)
+		return;
+
+	NFS_READTIME(dir) = jiffies;
+	if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) {
+		nfs_refresh_inode(dir, &fattr);
+		if (fattr.mtime.seconds == NFS_OLDMTIME(dir))
+			return;
+		NFS_OLDMTIME(dir) = fattr.mtime.seconds;
+	}
+	/* invalidate directory cache here when we _really_ start caching */
+}
+
+static int nfs_dir_open(struct inode * dir, struct file * file)
+{
+	revalidate_dir(NFS_SERVER(dir), dir);
+	return 0;
+}
+
 static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf,
 			int count)
 {
@@ -105,6 +122,8 @@
 		return -EBADF;
 	}
 
+	revalidate_dir(NFS_SERVER(inode), inode);
+
 	/* initialize cache memory if it hasn't been used before */
 
 	if (c_entry == NULL) {
@@ -190,7 +209,7 @@
 
 void nfs_kfree_cache(void)
 {
-        int i;
+	int i;
 
 	if (c_entry == NULL)
 		return;
diff -u --recursive --new-file v1.3.95/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.95/linux/fs/nfs/inode.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/nfs/inode.c	Thu Apr 25 15:09:39 1996
@@ -340,6 +340,7 @@
 #endif
 
 	MOD_INC_USE_COUNT;
+	exit_mm(current);
 	current->session = 1;
 	current->pgrp = 1;
 	sprintf(current->comm, "nfsiod");
diff -u --recursive --new-file v1.3.95/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.95/linux/fs/proc/array.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/proc/array.c	Thu Apr 25 13:32:41 1996
@@ -470,6 +470,11 @@
 				 + (long)&((struct pt_regs *)0)->reg)
 # define KSTK_EIP(tsk)	(*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
 # define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__sparc__)
+# define PT_REG(reg)            (PAGE_SIZE - sizeof(struct pt_regs)     \
+                                 + (long)&((struct pt_regs *)0)->reg)
+# define KSTK_EIP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
+# define KSTK_ESP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP])))
 #endif
 
 /* Gcc optimizes away "strlen(x)" for constant x */
@@ -607,7 +612,7 @@
 			bit <<= 1;
 			action++;
 		}
-		
+
 		buffer += sprintf(buffer,
 			"SigIgn:\t%08lx\n"
 			"SigCgt:\t%08lx\n",
diff -u --recursive --new-file v1.3.95/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.3.95/linux/fs/proc/inode.c	Wed Feb 21 10:30:09 1996
+++ linux/fs/proc/inode.c	Thu Apr 25 16:32:45 1996
@@ -74,7 +74,7 @@
 struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
 {
 	struct inode * inode = iget(s, ino);
-	if (inode) {
+	if (inode && inode->i_sb == s) {
 		inode->u.generic_ip = (void *) de;
 		if (de) {
 			if (de->mode) {
diff -u --recursive --new-file v1.3.95/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v1.3.95/linux/fs/proc/mem.c	Wed Apr  3 16:06:56 1996
+++ linux/fs/proc/mem.c	Fri Apr 26 12:48:01 1996
@@ -65,14 +65,9 @@
 		return -EINVAL;
 	pid = inode->i_ino;
 	pid >>= 16;
-	tsk = NULL;
-	for (i = 1 ; i < NR_TASKS ; i++)
-		if (task[i] && task[i]->pid == pid) {
-			tsk = task[i];
-			break;
-		}
-	if (!tsk)
+	if (pid != current->pid)
 		return -EACCES;
+	tsk = current;
 	addr = file->f_pos;
 	count = check_range(tsk, addr, count);
 	if (count < 0)
@@ -131,14 +126,9 @@
 	addr = file->f_pos;
 	pid = inode->i_ino;
 	pid >>= 16;
-	tsk = NULL;
-	for (i = 1 ; i < NR_TASKS ; i++)
-		if (task[i] && task[i]->pid == pid) {
-			tsk = task[i];
-			break;
-		}
-	if (!tsk)
+	if (pid != current->pid)
 		return -EACCES;
+	tsk = current;
 	tmp = buf;
 	while (count > 0) {
 		if (current->signal & ~current->blocked)
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v1.3.95/linux/fs/ufs/ufs_dir.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/ufs/ufs_dir.c	Thu Apr 25 13:37:31 1996
@@ -6,22 +6,16 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $
+ * $Id: ufs_dir.c,v 1.3 1996/04/25 09:12:00 davem Exp $
  *
  */
 
 #include <linux/fs.h>
 
 /* XXX */
-extern int ufs_lookup();
-extern int ufs_bmap();
-
-static int ufs_dir_read (struct inode * inode, struct file * filp,
-	                 char * buf, int count)
-{
-	/* XXX - probably allow this for root, EISDIR for normal users */
-	return -EISDIR;
-}
+extern int ufs_lookup (struct inode *, const char *, int, struct inode **);
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_print_inode (struct inode *);
 
 /*
  * This is blatantly stolen from ext2fs
@@ -43,7 +37,7 @@
 
 	if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
 	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
-	               inode->i_ino, filp->f_pos);
+	               inode->i_ino, (unsigned long) filp->f_pos);
 	        ufs_print_inode(inode);
 	}
 
@@ -95,7 +89,7 @@
 			de = (struct direct *) (bh->b_data + offset);
 	                /* XXX - put in a real ufs_check_dir_entry() */
 	                if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
-	                        filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize;
+	                        filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
 	                        brelse(bh);
 	                        return stored;
 	                }
@@ -123,7 +117,7 @@
 	                                   de->d_ino);
 				version = inode->i_version;
 	                        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-	                                printk("ufs_readdir: filldir(%s,%lu)\n",
+	                                printk("ufs_readdir: filldir(%s,%u)\n",
 	                                       de->d_name, de->d_ino);
 	                        }
 				error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino);
@@ -147,18 +141,17 @@
 	return 0;
 }
 
-
 static struct file_operations ufs_dir_operations = {
 	NULL,			/* lseek */
-	&ufs_dir_read,		/* read */
+	NULL,			/* read */
 	NULL,			/* write */
-	&ufs_readdir,		/* readdir */
+	ufs_readdir,		/* readdir */
 	NULL,			/* select */
 	NULL,			/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* open */
 	NULL,			/* release */
-	&file_fsync,		/* fsync */
+	file_fsync,		/* fsync */
 	NULL,			/* fasync */
 	NULL,			/* check_media_change */
 	NULL,			/* revalidate */
@@ -167,7 +160,7 @@
 struct inode_operations ufs_dir_inode_operations = {
 	&ufs_dir_operations,	/* default directory file operations */
 	NULL,			/* create */
-	&ufs_lookup,		/* lookup */
+	ufs_lookup,		/* lookup */
 	NULL,			/* link */
 	NULL,			/* unlink */
 	NULL,			/* symlink */
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v1.3.95/linux/fs/ufs/ufs_file.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/ufs/ufs_file.c	Thu Apr 25 13:37:31 1996
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_file.c,v 1.1 1996/04/21 14:41:08 davem Exp $
+ * $Id: ufs_file.c,v 1.3 1996/04/25 09:12:02 davem Exp $
  *
  */
 
@@ -75,13 +75,13 @@
 	                bh = bread(inode->i_dev, inode->u.ufs_i.ui_ib[0],
 	                           BLOCK_SIZE);
 	                if (bh == NULL) {
-	                        printk("ufs_bmap: can't map block %lu, ino %lu\n",
+	                        printk("ufs_bmap: can't map block %u, ino %lu\n",
 	                               block + UFS_NDADDR, inode->i_ino);
 	                        return(0);
 	                }
 	                phys_block = ((__u32 *)bh->b_data)[block];
 	                brelse(bh);
-	                printk("ufs_bmap: imap ino %lu block %lu phys %lu\n",
+	                printk("ufs_bmap: imap ino %lu block %u phys %lu\n",
 	                       inode->i_ino, block + UFS_NDADDR, phys_block);
 	                return(phys_block);
 	        } else {
@@ -94,18 +94,17 @@
 	return(0);
 }
 
-
 static struct file_operations ufs_file_operations = {
 	NULL,			/* lseek */
-	&generic_file_read,	/* read */
+	generic_file_read,	/* read */
 	NULL,			/* write */
 	NULL,			/* readdir */
 	NULL,			/* select */
 	NULL,			/* ioctl */
-	&generic_file_mmap,	/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* open */
 	NULL,			/* release */
-	&file_fsync,		/* fsync */  /* XXX - is this ok? */
+	file_fsync,		/* fsync */
 	NULL,			/* fasync */
 	NULL,			/* check_media_change */
 	NULL,			/* revalidate */
@@ -124,9 +123,9 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	&generic_readpage,	/* readpage */
+	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
-	&ufs_bmap,		/* bmap */
+	ufs_bmap,		/* bmap */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v1.3.95/linux/fs/ufs/ufs_inode.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/ufs/ufs_inode.c	Thu Apr 25 13:37:31 1996
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_inode.c,v 1.1 1996/04/21 14:41:12 davem Exp $
+ * $Id: ufs_inode.c,v 1.3 1996/04/25 09:12:05 davem Exp $
  *
  */
 
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v1.3.95/linux/fs/ufs/ufs_namei.c	Tue Apr 23 13:57:11 1996
+++ linux/fs/ufs/ufs_namei.c	Thu Apr 25 13:37:31 1996
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_namei.c,v 1.1 1996/04/21 14:41:15 davem Exp $
+ * $Id: ufs_namei.c,v 1.3 1996/04/25 09:12:07 davem Exp $
  *
  */
 
@@ -103,7 +103,7 @@
 	        }
 	        bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
 	        if (bh == NULL) {
-	                printk("ufs_lookup: bread failed: ino %lu, lfragno %u",
+	                printk("ufs_lookup: bread failed: ino %lu, lfragno %lu",
 	                       dir->i_ino, lfragno);
 	                return(-EIO);
 	        }
@@ -119,7 +119,7 @@
 	                        break;
 	                }
 	                if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-	                        printk("lfragno 0x%x  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
+	                        printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
 	                               lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name);
 	                }
 	                if ((d->d_namlen == len) &&
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v1.3.95/linux/fs/ufs/ufs_super.c	Wed Apr 24 17:00:41 1996
+++ linux/fs/ufs/ufs_super.c	Fri Apr 26 12:16:09 1996
@@ -6,10 +6,17 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_super.c,v 1.1 1996/04/21 14:41:19 davem Exp $
+ * $Id: ufs_super.c,v 1.3 1996/04/25 09:12:09 davem Exp $
  *
  */
 
+/*
+ * Kernel module support added on 96/04/26 by
+ * Stefan Reinauer <stepan@home.culture.mipt.ru>
+ */
+
+#include <linux/module.h>
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
@@ -26,18 +33,18 @@
 extern void ufs_put_inode(struct inode * inode);
 
 static struct super_operations ufs_super_ops = {
-	&ufs_read_inode,
+	ufs_read_inode,
 	NULL,			/* notify_change() */
 	NULL,			/* XXX - ufs_write_inode() */
-	&ufs_put_inode,
-	&ufs_put_super,
+	ufs_put_inode,
+	ufs_put_super,
 	NULL,			/* XXX - ufs_write_super() */
-	&ufs_statfs,
+	ufs_statfs,
 	NULL,			/* XXX - ufs_remount() */
 };
 
 static struct file_system_type ufs_fs_type = {
-	&ufs_read_super, "ufs", 1, NULL
+	ufs_read_super, "ufs", 1, NULL
 };
 
 int
@@ -46,6 +53,23 @@
 	return(register_filesystem(&ufs_fs_type));
 }
 
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_ufs_fs()) == 0)
+		register_symtab(0);
+	return status;
+}
+
+void cleanup_module(void)
+{
+	unregister_filesystem(&ufs_fs_type);
+}
+#endif
+
+#if 0 /* unused */
 static void
 ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
 {
@@ -65,6 +89,7 @@
 
 	return;
 }
+#endif
 
 struct super_block *
 ufs_read_super(struct super_block * sb, void * data, int silent)
@@ -203,7 +228,7 @@
 	sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
 	sb->s_mounted = iget(sb, UFS_ROOTINO);
 
-	printk("ufs_read_super: inopb %lu\n", sb->u.ufs_sb.s_inopb);
+	printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
 	/*
 	 * XXX - read cg structs?
 	 */
diff -u --recursive --new-file v1.3.95/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v1.3.95/linux/fs/ufs/ufs_symlink.c	Wed Apr 24 17:00:41 1996
+++ linux/fs/ufs/ufs_symlink.c	Thu Apr 25 13:37:31 1996
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_symlink.c,v 1.1 1996/04/21 14:41:23 davem Exp $
+ * $Id: ufs_symlink.c,v 1.3 1996/04/25 09:12:11 davem Exp $
  *
  */
 
@@ -15,13 +15,15 @@
 
 #include <asm/segment.h>
 
+extern int ufs_bmap (struct inode *, int);
+
 static int
 ufs_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	unsigned long int block;
 	struct buffer_head * bh = NULL;
 	char * link;
-	int i, err;
+	int i;
 	char c;
 
 	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
@@ -64,8 +66,6 @@
 	if (bh)
 		brelse (bh);
 	return i;
-
-	return(0);
 }
 
 /*
diff -u --recursive --new-file v1.3.95/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v1.3.95/linux/include/asm-i386/smp.h	Fri Apr 12 15:52:05 1996
+++ linux/include/asm-i386/smp.h	Fri Apr 26 10:37:21 1996
@@ -19,7 +19,7 @@
  *	information is. 
  */
  
-#define SMP_MAGIC_IDENT	('_'<<24)|('P'<<16)|('M'<<8)|'_'
+#define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
 struct intel_mp_floating
 {
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h
--- v1.3.95/linux/include/asm-m68k/atarihw.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/atarihw.h	Fri Apr 26 12:12:24 1996
@@ -18,7 +18,7 @@
 
 #include <linux/types.h>
 
-/* Reading the MFP port register gives a machine independant delay, since the
+/* Reading the MFP port register gives a machine independent delay, since the
  * MFP always has a 8 MHz clock. This avoids problems with the varying length
  * of nops on various machines. Somebody claimed that the tstb takes 600 ns.
  */
@@ -42,7 +42,7 @@
 #include <linux/mm.h>
 #include <asm/pgtable.h>
 
-static inline void dma_cache_maintainance( unsigned long paddr,
+static inline void dma_cache_maintenance( unsigned long paddr,
 					  unsigned long len,
 					  int writeflag )
 
@@ -293,7 +293,7 @@
   u_short endmask3;
   u_short dst_x_inc;
   u_short dst_y_inc;
-  u_long dst_adress;
+  u_long dst_address;
   u_short wd_per_line;
   u_short ln_per_bb;
   u_short hlf_op_reg;
@@ -448,7 +448,7 @@
  */
 /* constants for the ACIA registers */
 
-/* baudrate selection and reset (Baudrte = clock/factor) */
+/* baudrate selection and reset (Baudrate = clock/factor) */
 #define ACIA_DIV1  0
 #define ACIA_DIV16 1
 #define ACIA_DIV64 2
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/atariints.h linux/include/asm-m68k/atariints.h
--- v1.3.95/linux/include/asm-m68k/atariints.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/atariints.h	Fri Apr 26 12:12:24 1996
@@ -4,7 +4,7 @@
 ** Copyright 1994 by Bj”rn Brauel
 **
 ** 5/2/94 Roman Hodek:
-**   TT interupt definitions added.
+**   TT interrupt definitions added.
 **
 ** 12/02/96: (Roman)
 **   Adapted to new int handling scheme (see ataints.c); revised numbering
@@ -45,7 +45,7 @@
 #define IRQ_TYPE_FAST     1
 #define IRQ_TYPE_PRIO     2
 
-#define	IRQ_SUPRIOUS      (IRQ_MACHSPEC | 0)
+#define	IRQ_SPURIOUS      (IRQ_MACHSPEC | 0)
 
 /* auto-vector interrupts */
 #define IRQ_AUTO_1        (IRQ_MACHSPEC | 1)
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h
--- v1.3.95/linux/include/asm-m68k/atomic.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/atomic.h	Fri Apr 26 10:30:51 1996
@@ -24,7 +24,7 @@
 	__asm__ __volatile__(
 		"addl %1,%0"
 		:"=m" (__atomic_fool_gcc(v))
-		:"ir" (i), "m" (__atomic_fool_gcc(v)));
+		:"ir" (i), "0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
@@ -32,7 +32,7 @@
 	__asm__ __volatile__(
 		"subl  %1,%0"
 		:"=m" (__atomic_fool_gcc(v))
-		:"ir" (i), "m" (__atomic_fool_gcc(v)));
+		:"ir" (i), "0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_inc(atomic_t *v)
@@ -40,7 +40,7 @@
 	__asm__ __volatile__(
 		"addql #1,%0"
 		:"=m" (__atomic_fool_gcc(v))
-		:"m" (__atomic_fool_gcc(v)));
+		:"0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ void atomic_dec(atomic_t *v)
@@ -48,16 +48,17 @@
 	__asm__ __volatile__(
 		"subql #1,%0"
 		:"=m" (__atomic_fool_gcc(v))
-		:"m" (__atomic_fool_gcc(v)));
+		:"0" (__atomic_fool_gcc(v)));
 }
 
 static __inline__ int atomic_dec_and_test(atomic_t *v)
 {
+	char c;
 	__asm__ __volatile__(
-		"subql #1,%0"
-		:"=m" (__atomic_fool_gcc(v))
-		:"m" (__atomic_fool_gcc(v)));
-	return (*v <= 0);
+		"subql #1,%0; seq %1"
+		:"=m" (__atomic_fool_gcc(v)), "=d" (c)
+		:"0" (__atomic_fool_gcc(v)));
+	return c != 0;
 }
 
 #endif /* __ARCH_M68K_ATOMIC __ */
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v1.3.95/linux/include/asm-m68k/bitops.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/bitops.h	Fri Apr 26 10:30:51 1996
@@ -46,12 +46,7 @@
 
 extern __inline__ int test_bit(int nr, const void * vaddr)
 {
-	char retval;
-
-	__asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
-
-	return retval;
+	return ((1UL << (nr & 31)) & (((const unsigned int *) vaddr)[nr >> 5])) != 0;
 }
 
 extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size)
@@ -166,12 +161,7 @@
 extern __inline__ int
 minix_test_bit (int nr, const void *vaddr)
 {
-	char retval;
-
-	__asm__ __volatile__ ("bftst %2{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^15), "m" (*(const char *) vaddr));
-
-	return retval;
+	return ((1U << (nr & 15)) & (((const unsigned short *) vaddr)[nr >> 4])) != 0;
 }
 
 /* Bitmap functions for the ext2 filesystem. */
@@ -201,12 +191,7 @@
 extern __inline__ int
 ext2_test_bit (int nr, const void *vaddr)
 {
-	char retval;
-
-	__asm__ __volatile__ ("bftst %2{%1,#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "m" (*(const char *) vaddr));
-
-	return retval;
+	return ((1U << (nr & 7)) & (((const unsigned char *) vaddr)[nr >> 3])) != 0;
 }
 
 extern __inline__ int
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v1.3.95/linux/include/asm-m68k/bootinfo.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/bootinfo.h	Fri Apr 26 12:12:24 1996
@@ -10,7 +10,7 @@
 ** Created 09/29/92 by Greg Harp
 **
 ** 5/2/94 Roman Hodek:
-**   Added bi_atari part of the machine dependant union bi_un; for now it
+**   Added bi_atari part of the machine dependent union bi_un; for now it
 **	 contains just a model field to distinguish between TT and Falcon.
 */
 
@@ -98,7 +98,7 @@
   struct {
     /* video hardware */
     ATARIHW_DECLARE(STND_SHIFTER);	/* ST-Shifter - no base low ! */
-    ATARIHW_DECLARE(EXTD_SHIFTER);	/* STe-Shifter - 24 bit adress */
+    ATARIHW_DECLARE(EXTD_SHIFTER);	/* STe-Shifter - 24 bit address */
     ATARIHW_DECLARE(TT_SHIFTER);	/* TT-Shifter */
     ATARIHW_DECLARE(VIDEL_SHIFTER);	/* Falcon-Shifter */
     /* sound hardware */
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/dma.h linux/include/asm-m68k/dma.h
--- v1.3.95/linux/include/asm-m68k/dma.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/dma.h	Fri Apr 26 12:12:24 1996
@@ -2,7 +2,7 @@
 #define _M68K_DMA_H 1
 
 /* Don't define MAX_DMA_ADDRESS; it's useless on the m68k and any
-   occurence should be flagged as an error.  */
+   occurrence should be flagged as an error.  */
 
 #define MAX_DMA_CHANNELS 8
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/font.h linux/include/asm-m68k/font.h
--- v1.3.95/linux/include/asm-m68k/font.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/font.h	Fri Apr 26 12:12:24 1996
@@ -18,7 +18,7 @@
     *    Find a font with a specific name
     */
 
-extern int findsoftfont(char *name, int *width, int *heigth, u_char *data[]);
+extern int findsoftfont(char *name, int *width, int *height, u_char *data[]);
 
 
    /*
@@ -28,5 +28,8 @@
 extern void getdefaultfont(int xres, int yres, char *name[], int *width,
                            int *height, u_char *data[]);
 
+
+/* Max. length for the name of a predefined font */
+#define MAX_FONT_NAME	32
 
 #endif /* _ASM_M68K_FONT_H_ */
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v1.3.95/linux/include/asm-m68k/pgtable.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/pgtable.h	Fri Apr 26 12:12:24 1996
@@ -141,7 +141,7 @@
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
-/* zero page used for unitialized stuff */
+/* zero page used for uninitialized stuff */
 extern unsigned long empty_zero_page;
 
 /*
@@ -525,22 +525,14 @@
  */
 extern void cache_push_v (unsigned long vaddr, int len);
 
-#if 0
-#define flush_cache_all()		    do { \
-                   if (m68k_is040or060 >= 4) \
-                     __asm__ __volatile__ (".word 0xf478\n" ::); \
-                                            } while (0)
+/*
+ * Could someone take a look at these?
+ */
+extern void flush_cache_all(void);
 #define flush_cache_mm(mm)		   flush_cache_all()
 #define flush_cache_range(mm, start, end)  flush_cache_all()
-#define flush_cache_page(vma, vmaddr)	   flush_cache_all()
-#define flush_page_to_ram(page)		   flush_cache_all()
-#else
-#define flush_cache_all()			do { } while (0)
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr)		do { } while (0)
-#define flush_page_to_ram(page)			do { } while (0)
-#endif
+#define flush_cache_page(vma, addr)	   flush_cache_all()
+extern void flush_page_to_ram(unsigned long addr);
 
 /* cache code */
 #define FLUSH_I_AND_D	(0x00000808)
@@ -579,8 +571,19 @@
 {
 }
 
+/*
+ * I don't know what is going on here, but since these were changed,
+ * swapping haven't been working on the 68040.
+ */
+
+#if 0
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 9)
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+#else
+#define SWP_TYPE(entry)  (((entry) & 0x1fc) >> 2)
+#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT))
+#endif
 
 #endif /* _M68K_PGTABLE_H */
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v1.3.95/linux/include/asm-m68k/system.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/system.h	Fri Apr 26 12:12:24 1996
@@ -32,7 +32,7 @@
  * and so we might get see unexpected behaviors when a task returns
  * with unexpected register values.
  *
- * syscall stores these regsiters itself and none of them are used
+ * syscall stores these registers itself and none of them are used
  * by syscall after the function in the syscall has been called.
  *
  * Beware that resume now expects *next to be in d1 and the offset of
diff -u --recursive --new-file v1.3.95/linux/include/asm-m68k/traps.h linux/include/asm-m68k/traps.h
--- v1.3.95/linux/include/asm-m68k/traps.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/traps.h	Fri Apr 26 12:12:24 1996
@@ -148,7 +148,7 @@
 #define	MMU060_SIZ	(0x00600000)	/* transfer size */
 #define	MMU060_TT	(0x00180000)	/* transfer type (TT) bits */
 #define	MMU060_TM	(0x00070000)	/* transfer modifier (TM) bits */
-#define	MMU060_IO	(0x00008000)	/* intruction or operand */
+#define	MMU060_IO	(0x00008000)	/* instruction or operand */
 #define	MMU060_PBE	(0x00004000)	/* push buffer bus error */
 #define	MMU060_SBE	(0x00002000)	/* store buffer bus error */
 #define	MMU060_PTA	(0x00001000)	/* pointer A fault */
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/asi.h linux/include/asm-sparc/asi.h
--- v1.3.95/linux/include/asm-sparc/asi.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/asi.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.15 1996/04/17 22:45:52 davem Exp $ */
+/* $Id: asi.h,v 1.16 1996/04/25 06:12:43 davem Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h
--- v1.3.95/linux/include/asm-sparc/auxio.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/auxio.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $
+/* $Id: auxio.h,v 1.11 1996/04/25 06:12:45 davem Exp $
  * auxio.h:  Definitions and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/bsderrno.h linux/include/asm-sparc/bsderrno.h
--- v1.3.95/linux/include/asm-sparc/bsderrno.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/bsderrno.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: bsderrno.h,v 1.2 1995/11/25 02:31:17 davem Exp $
+/* $Id: bsderrno.h,v 1.3 1996/04/25 06:12:47 davem Exp $
  * bsderrno.h: Error numbers for NetBSD binary compatibility
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/cache.h linux/include/asm-sparc/cache.h
--- v1.3.95/linux/include/asm-sparc/cache.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/cache.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: cache.h,v 1.3 1995/11/25 02:31:22 davem Exp $
+/* $Id: cache.h,v 1.4 1996/04/25 06:12:49 davem Exp $
  * cache.h:  Cache specific code for the Sparc.  These include flushing
  *           and direct tag/data line access.
  *
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/cypress.h linux/include/asm-sparc/cypress.h
--- v1.3.95/linux/include/asm-sparc/cypress.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/cypress.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: cypress.h,v 1.4 1996/03/12 17:48:12 davem Exp $
+/* $Id: cypress.h,v 1.5 1996/04/25 06:12:51 davem Exp $
  * cypress.h: Cypress module specific definitions and defines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v1.3.95/linux/include/asm-sparc/dma.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/dma.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.15 1996/03/23 02:40:00 davem Exp $
+/* $Id: dma.h,v 1.16 1996/04/25 06:12:54 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/ecc.h linux/include/asm-sparc/ecc.h
--- v1.3.95/linux/include/asm-sparc/ecc.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/ecc.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: ecc.h,v 1.2 1995/11/25 02:31:37 davem Exp $
+/* $Id: ecc.h,v 1.3 1996/04/25 06:12:57 davem Exp $
  * ecc.h: Definitions and defines for the external cache/memory
  *        controller on the sun4m.
  *
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/elf.h linux/include/asm-sparc/elf.h
--- v1.3.95/linux/include/asm-sparc/elf.h	Sat Nov 25 04:31:41 1995
+++ linux/include/asm-sparc/elf.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.2 1995/11/25 02:31:40 davem Exp $ */
+/* $Id: elf.h,v 1.3 1996/04/22 15:48:48 miguel Exp $ */
 #ifndef __ASMSPARC_ELF_H
 #define __ASMSPARC_ELF_H
 
@@ -15,4 +15,6 @@
 
 typedef unsigned long elf_fpregset_t;
 
+#define elf_check_arch(x) ((x) == EM_SPARC)
+#define ELF_ARCH EM_SPARC
 #endif
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h
--- v1.3.95/linux/include/asm-sparc/head.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/head.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.26 1996/03/25 20:21:08 davem Exp $ */
+/* $Id: head.h,v 1.27 1996/04/25 06:13:06 davem Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h
--- v1.3.95/linux/include/asm-sparc/irq.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/irq.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.12 1996/04/03 02:17:34 davem Exp $
+/* $Id: irq.h,v 1.13 1996/04/25 06:13:09 davem Exp $
  * irq.h: IRQ registers on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mbus.h linux/include/asm-sparc/mbus.h
--- v1.3.95/linux/include/asm-sparc/mbus.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/mbus.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: mbus.h,v 1.6 1996/04/16 09:34:31 zaitcev Exp $
+/* $Id: mbus.h,v 1.7 1996/04/25 06:13:12 davem Exp $
  * mbus.h:  Various defines for MBUS modules.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/memreg.h linux/include/asm-sparc/memreg.h
--- v1.3.95/linux/include/asm-sparc/memreg.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/memreg.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: memreg.h,v 1.5 1995/12/02 20:05:25 davem Exp $ */
+/* $Id: memreg.h,v 1.6 1996/04/25 06:13:13 davem Exp $ */
 #ifndef _SPARC_MEMREG_H
 #define _SPARC_MEMREG_H
 /* memreg.h:  Definitions of the values found in the synchronous
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mman.h linux/include/asm-sparc/mman.h
--- v1.3.95/linux/include/asm-sparc/mman.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/mman.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: mman.h,v 1.6 1996/01/03 03:53:05 davem Exp $ */
+/* $Id: mman.h,v 1.7 1996/04/25 06:13:15 davem Exp $ */
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mostek.h linux/include/asm-sparc/mostek.h
--- v1.3.95/linux/include/asm-sparc/mostek.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/mostek.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: mostek.h,v 1.4 1995/11/25 02:32:05 davem Exp $
+/* $Id: mostek.h,v 1.5 1996/04/25 06:13:17 davem Exp $
  * mostek.h:  Describes the various Mostek time of day clock registers.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mp.h linux/include/asm-sparc/mp.h
--- v1.3.95/linux/include/asm-sparc/mp.h	Sun Apr 21 19:22:12 1996
+++ linux/include/asm-sparc/mp.h	Thu Jan  1 02:00:00 1970
@@ -1,32 +0,0 @@
-/* $Id: mp.h,v 1.3 1996/03/25 20:21:09 davem Exp $
- * mp.h:  Multiprocessing definitions for the Sparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _SPARC_MP_H
-#define _SPARC_MP_H
-
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/vaddrs.h>
-
-struct sparc_percpu {
-	struct tt_entry *trap_table;
-	char *kernel_stack[PAGE_SIZE<<1];
-	int cpuid;          /* Who am I? */
-	int cpu_is_alive;   /* Linux has fired it up. */
-	int cpu_is_idling;  /* Is sitting in the idle loop. */
-	/* More to come... */
-	char filler[PERCPU_ENTSIZE-(PAGE_SIZE*2)-0xc];
-};
-
-extern struct sparc_percpu *percpu_table;
-
-struct prom_cpuinfo {
-	int prom_node;
-	int mid;
-};
-
-extern struct prom_cpuinfo linux_cpus[NCPUS];
-
-#endif /* !(_SPARC_MP_H) */
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mpmbox.h linux/include/asm-sparc/mpmbox.h
--- v1.3.95/linux/include/asm-sparc/mpmbox.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/mpmbox.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: mpmbox.h,v 1.3 1995/11/25 02:32:09 davem Exp $
+/* $Id: mpmbox.h,v 1.4 1996/04/25 06:13:19 davem Exp $
  * mpmbox.h:  Interface and defines for the OpenProm mailbox
  *               facilities for MP machines under Linux.
  *
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/mxcc.h linux/include/asm-sparc/mxcc.h
--- v1.3.95/linux/include/asm-sparc/mxcc.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/mxcc.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: mxcc.h,v 1.3 1996/04/20 10:15:44 davem Exp $
+/* $Id: mxcc.h,v 1.4 1996/04/25 06:13:21 davem Exp $
  * mxcc.h:  Definitions of the Viking MXCC registers
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h
--- v1.3.95/linux/include/asm-sparc/openprom.h	Fri Apr 12 15:52:06 1996
+++ linux/include/asm-sparc/openprom.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.15 1995/11/25 02:32:13 davem Exp $ */
+/* $Id: openprom.h,v 1.16 1996/04/23 01:54:46 davem Exp $ */
 #ifndef __SPARC_OPENPROM_H
 #define __SPARC_OPENPROM_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h
--- v1.3.95/linux/include/asm-sparc/oplib.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/oplib.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.7 1996/04/04 16:31:25 tridge Exp $
+/* $Id: oplib.h,v 1.8 1996/04/25 06:13:23 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/pconf.h linux/include/asm-sparc/pconf.h
--- v1.3.95/linux/include/asm-sparc/pconf.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/pconf.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: pconf.h,v 1.2 1995/11/25 02:32:20 davem Exp $
+/* $Id: pconf.h,v 1.3 1996/04/25 06:13:25 davem Exp $
  * pconf.h: pathconf() and fpathconf() defines for SunOS
  *          system call compatibility.
  *
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/pgtsrmmu.h linux/include/asm-sparc/pgtsrmmu.h
--- v1.3.95/linux/include/asm-sparc/pgtsrmmu.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/pgtsrmmu.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtsrmmu.h,v 1.16 1996/04/04 16:31:32 tridge Exp $
+/* $Id: pgtsrmmu.h,v 1.17 1996/04/25 06:13:26 davem Exp $
  * pgtsrmmu.h:  SRMMU page table defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v1.3.95/linux/include/asm-sparc/ptrace.h	Mon Mar  4 08:50:03 1996
+++ linux/include/asm-sparc/ptrace.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.19 1996/01/24 02:33:50 davem Exp $ */
+/* $Id: ptrace.h,v 1.20 1996/04/24 09:10:02 davem Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -171,12 +171,8 @@
 #define SF_XXARG  0x5c
 
 /* Stuff for the ptrace system call */
-#if 0 /* Need to fix the header files a bit... */
-#undef PTRACE_ATTACH
-#undef PTRACE_DETACH
-#define PTRACE_ATTACH		  10
-#define PTRACE_DETACH		  11
-#endif
+#define PTRACE_SUNATTACH	  10
+#define PTRACE_SUNDETACH	  11
 #define PTRACE_GETREGS            12
 #define PTRACE_SETREGS            13
 #define PTRACE_GETFPREGS          14
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/signal.h linux/include/asm-sparc/signal.h
--- v1.3.95/linux/include/asm-sparc/signal.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/signal.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: signal.h,v 1.20 1996/03/24 20:21:27 davem Exp $ */
+/* $Id: signal.h,v 1.21 1996/04/25 06:13:28 davem Exp $ */
 #ifndef _ASMSPARC_SIGNAL_H
 #define _ASMSPARC_SIGNAL_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/solerrno.h linux/include/asm-sparc/solerrno.h
--- v1.3.95/linux/include/asm-sparc/solerrno.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/solerrno.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: solerrno.h,v 1.4 1996/03/23 02:40:09 davem Exp $
+/* $Id: solerrno.h,v 1.5 1996/04/25 06:13:32 davem Exp $
  * solerrno.h: Solaris error return codes for compatibility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/traps.h linux/include/asm-sparc/traps.h
--- v1.3.95/linux/include/asm-sparc/traps.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/traps.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: traps.h,v 1.5 1995/11/25 02:33:05 davem Exp $
+/* $Id: traps.h,v 1.6 1996/04/25 06:13:33 davem Exp $
  * traps.h:  Format of entries for the Sparc trap table.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v1.3.95/linux/include/asm-sparc/unistd.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/unistd.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.20 1996/04/20 07:54:39 davem Exp $ */
+/* $Id: unistd.h,v 1.21 1996/04/25 06:13:35 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h
--- v1.3.95/linux/include/asm-sparc/vac-ops.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/vac-ops.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: vac-ops.h,v 1.10 1996/04/04 12:51:36 davem Exp $ */
+/* $Id: vac-ops.h,v 1.11 1996/04/25 06:13:38 davem Exp $ */
 #ifndef _SPARC_VAC_OPS_H
 #define _SPARC_VAC_OPS_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h
--- v1.3.95/linux/include/asm-sparc/vaddrs.h	Wed Apr 24 17:00:42 1996
+++ linux/include/asm-sparc/vaddrs.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.19 1996/03/26 06:51:58 miguel Exp $ */
+/* $Id: vaddrs.h,v 1.20 1996/04/25 06:13:40 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
diff -u --recursive --new-file v1.3.95/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h
--- v1.3.95/linux/include/asm-sparc/viking.h	Wed Apr 24 17:00:43 1996
+++ linux/include/asm-sparc/viking.h	Thu Apr 25 13:23:18 1996
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.12 1996/04/20 10:15:46 davem Exp $
+/* $Id: viking.h,v 1.13 1996/04/25 06:13:43 davem Exp $
  * viking.h:  Defines specific to the GNU/Viking MBUS module.
  *            This is SRMMU stuff.
  *
diff -u --recursive --new-file v1.3.95/linux/include/linux/blk.h linux/include/linux/blk.h
--- v1.3.95/linux/include/linux/blk.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/blk.h	Sat Apr 27 15:05:15 1996
@@ -318,7 +318,7 @@
 #define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
 
 #ifdef DEVICE_INTR
-void (*DEVICE_INTR)(void) = NULL;
+static void (*DEVICE_INTR)(void) = NULL;
 #endif
 #ifdef DEVICE_TIMEOUT
 
diff -u --recursive --new-file v1.3.95/linux/include/linux/config.h linux/include/linux/config.h
--- v1.3.95/linux/include/linux/config.h	Mon Apr 15 12:20:21 1996
+++ linux/include/linux/config.h	Sat Apr 27 15:05:15 1996
@@ -27,6 +27,8 @@
  * in linux/version.h, and should only be used by linux/version.c
  */
 
+/* Shouldn't these be defined somewhere in a i386 definition? */
+
 /* Don't touch these, unless you really know what you're doing. */
 #define DEF_INITSEG	0x9000
 #define DEF_SYSSEG	0x1000
diff -u --recursive --new-file v1.3.95/linux/include/linux/console.h linux/include/linux/console.h
--- v1.3.95/linux/include/linux/console.h	Tue Apr 23 13:57:13 1996
+++ linux/include/linux/console.h	Fri Apr 26 10:30:52 1996
@@ -101,6 +101,8 @@
     int    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
     int    (*con_switch)(struct vc_data *);
     int    (*con_blank)(int);
+    int    (*con_get_font)(struct vc_data *, int *, int *, char *);
+    int    (*con_set_font)(struct vc_data *, int, int, char *);
 };
 
 extern struct consw *conswitchp;
diff -u --recursive --new-file v1.3.95/linux/include/linux/fb.h linux/include/linux/fb.h
--- v1.3.95/linux/include/linux/fb.h	Tue Apr 23 13:57:13 1996
+++ linux/include/linux/fb.h	Fri Apr 26 12:12:24 1996
@@ -3,11 +3,6 @@
 
 /* Definitions of frame buffers						*/
 
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/fs.h>
-#endif
-
 /* ioctls
    0x46 is 'F'								*/
 #define FBIOGET_VSCREENINFO 	0x4600
@@ -39,7 +34,8 @@
 	u_short xpanstep;               /* zero if no hardware panning  */
         u_short ypanstep;               /* zero if no hardware panning  */
         u_short ywrapstep;              /* zero if no hardware ywrap    */
-        short reserved[11];             /* Reserved for future compatibility */
+        u_long line_length;             /* length of a line in bytes    */
+        short reserved[9];              /* Reserved for future compatibility */
 };
 
 struct fb_bitfield {
@@ -78,6 +74,8 @@
 #define FB_VMODE_MASK		255
 
 #define FB_VMODE_YWRAP		256	/* ywrap instead of panning     */
+#define FB_VMODE_SMOOTH_XPAN	512	/* smooth xpan possible (internally used) */
+#define FB_VMODE_CONUPDATE	512	/* don't update x/yoffset	*/
 
 struct fb_var_screeninfo {
 	int xres;			/* visible resolution		*/
@@ -128,12 +126,14 @@
 
 #ifdef __KERNEL__
 
+#include <linux/fs.h>
+
 struct fb_ops {
-	/* get non setable parameters	*/
+	/* get non settable parameters	*/
 	int (*fb_get_fix) (struct fb_fix_screeninfo *, int); 
-	/* get setable parameters	*/
+	/* get settable parameters	*/
 	int (*fb_get_var) (struct fb_var_screeninfo *, int);		
-	/* set setable parameters	*/
+	/* set settable parameters	*/
 	int (*fb_set_var) (struct fb_var_screeninfo *, int);		
 	/* get colormap			*/
 	int (*fb_get_cmap) (struct fb_cmap *, int, int);
@@ -156,43 +156,6 @@
     */
 
 struct display {
-/*
- * As long as the old Amiga screen driver is being used, we have to
- * include these old parameters.
- */
-#if defined(CONFIG_AMIGA)
-  ushort scr_max_height;	/* screen dimensions */
-  ushort scr_max_width;
-  ushort scr_height;
-  ushort scr_width;
-  ushort scr_depth;
-  int bytes_per_row;		/* offset to one line below */
-  
-  ulong crsrcol;
-
-  ushort scroll_latch;		/* Vblank support for hardware scroll */
-  ushort y_wrap;
-  ushort cursor_latch;		/* Hardware cursor */
-  ushort *cursor, *dummy;
-  ushort cursor_flash;
-  ushort cursor_visible;
-
-  /* Some chipreg values we need to rebuild copper lists */
-  ushort diwstrt_v, diwstrt_h;	/* display window control */
-  ushort diwstop_v, diwstop_h;
-  ushort bplcon0;		/* display mode */
-  ushort htotal;
-
-  u_char *bitplane[8];		/* pointers to display bitplanes */
-  ulong plane_size;
-
-  ushort *coplist1hdr;		/* List 1 static  component */
-  ushort *coplist1dyn;		/* List 1 dynamic component */
-  ushort *coplist2hdr;		/* List 2 static  component */
-  ushort *coplist2dyn;		/* List 2 dynamic component */
-
-#endif
-
    /* Filled in by the frame buffer device */
 
    struct fb_var_screeninfo var;    /* variable infos. yoffset and vmode */
@@ -204,6 +167,7 @@
    int type_aux;                    /* Interleave for interleaved Planes */
    u_short ypanstep;                /* zero if no hardware ypan */
    u_short ywrapstep;               /* zero if no hardware ywrap */
+   u_long line_length;              /* length of a line in bytes */
    u_short can_soft_blank;          /* zero if no hardware blanking */
    u_short inverse;                 /* != 0 text black on white as default */
 
@@ -216,6 +180,7 @@
    /* Filled in by the low-level console driver */
 
    struct vc_data *conp;            /* pointer to console data */
+   int vrows;                       /* number of virtual rows */
    int cursor_x;                    /* current cursor position */
    int cursor_y;
    int fgcol;                       /* text colors */
@@ -225,6 +190,7 @@
    u_char *fontdata;                /* Font associated to this display */
    int fontheight;
    int fontwidth;
+   int userfont;                    /* != 0 if fontdata kmalloc()ed */
    struct display_switch *dispsw;   /* low level operations */
    u_short scrollmode;              /* Scroll Method */
    short yscroll;                   /* Hardware scrolling */
@@ -274,7 +240,11 @@
 };
 
 struct fb_var_cursorinfo {
-	u_long data[256];	       /* max. 64x64 (ilbm, 2 planes)	*/
+        u_short width;
+        u_short height;
+        u_short xspot;
+        u_short yspot;
+        u_char data[1];                 /* field with [height][width]        */
 };
 
 struct fb_cursorstate {
@@ -286,6 +256,31 @@
 #define FB_CURSOR_OFF		0
 #define FB_CURSOR_ON		1
 #define FB_CURSOR_FLASH		2
+
+#define FBCMD_DRAWLINE		0x4621
+#define FBCMD_MOVE		0x4622
+
+#define FB_LINE_XOR	1
+#define FB_LINE_BOX	2
+#define FB_LINE_FILLED	4
+
+struct fb_line {
+	int start_x;
+	int start_y;
+	int end_x;
+	int end_y;
+	int color;
+	int option;
+};
+
+struct fb_move {
+	int src_x;
+	int src_y;
+	int dest_x;
+	int dest_y;
+	int height;
+	int width;
+};
 
 #endif /* Preliminary */
 
diff -u --recursive --new-file v1.3.95/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v1.3.95/linux/include/linux/genhd.h	Wed Feb 28 08:42:33 1996
+++ linux/include/linux/genhd.h	Sat Apr 27 15:05:15 1996
@@ -9,13 +9,15 @@
  *		<drew@colorado.edu>
  */
 
+#include <linux/config.h>
+
 #define CONFIG_MSDOS_PARTITION 1
 
 #ifdef __alpha__
 #define CONFIG_OSF_PARTITION 1
 #endif
 
-#ifdef __sparc__
+#if defined(__sparc__) || defined(CONFIG_SMD_DISKLABEL)
 #define CONFIG_SUN_PARTITION 1
 #endif
 
@@ -63,6 +65,61 @@
 	void *real_devices;		/* internal use */
 	struct gendisk *next;
 };
+
+#ifdef CONFIG_BSD_DISKLABEL
+/*
+ * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ */
+
+#define BSD_PARTITION		0xa5	/* Partition ID */
+
+#define BSD_DISKMAGIC	(0x82564557UL)	/* The disk magic number */
+#define BSD_MAXPARTITIONS	8
+#define BSD_FS_UNUSED		0	/* disklabel unused partition entry ID */
+struct bsd_disklabel {
+	__u32	d_magic;		/* the magic number */
+	__s16	d_type;			/* drive type */
+	__s16	d_subtype;		/* controller/d_type specific */
+	char	d_typename[16];		/* type name, e.g. "eagle" */
+	char	d_packname[16];			/* pack identifier */ 
+	__u32	d_secsize;		/* # of bytes per sector */
+	__u32	d_nsectors;		/* # of data sectors per track */
+	__u32	d_ntracks;		/* # of tracks per cylinder */
+	__u32	d_ncylinders;		/* # of data cylinders per unit */
+	__u32	d_secpercyl;		/* # of data sectors per cylinder */
+	__u32	d_secperunit;		/* # of data sectors per unit */
+	__u16	d_sparespertrack;	/* # of spare sectors per track */
+	__u16	d_sparespercyl;		/* # of spare sectors per cylinder */
+	__u32	d_acylinders;		/* # of alt. cylinders per unit */
+	__u16	d_rpm;			/* rotational speed */
+	__u16	d_interleave;		/* hardware sector interleave */
+	__u16	d_trackskew;		/* sector 0 skew, per track */
+	__u16	d_cylskew;		/* sector 0 skew, per cylinder */
+	__u32	d_headswitch;		/* head switch time, usec */
+	__u32	d_trkseek;		/* track-to-track seek, usec */
+	__u32	d_flags;		/* generic flags */
+#define NDDATA 5
+	__u32	d_drivedata[NDDATA];	/* drive-type specific information */
+#define NSPARE 5
+	__u32	d_spare[NSPARE];	/* reserved for future use */
+	__u32	d_magic2;		/* the magic number (again) */
+	__u16	d_checksum;		/* xor of data incl. partitions */
+
+			/* filesystem and partition information: */
+	__u16	d_npartitions;		/* number of partitions in following */
+	__u32	d_bbsize;		/* size of boot area at sn0, bytes */
+	__u32	d_sbsize;		/* max size of fs superblock, bytes */
+	struct	bsd_partition {		/* the partition table */
+		__u32	p_size;		/* number of sectors in partition */
+		__u32	p_offset;	/* starting sector */
+		__u32	p_fsize;	/* filesystem basic fragment size */
+		__u8	p_fstype;	/* filesystem type, see below */
+		__u8	p_frag;		/* filesystem fragments per block */
+		__u16	p_cpg;		/* filesystem cylinders per group */
+	} d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
+};
+
+#endif	/* CONFIG_BSD_DISKLABEL */
 
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
diff -u --recursive --new-file v1.3.95/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v1.3.95/linux/include/linux/if_arp.h	Tue Apr  2 13:32:22 1996
+++ linux/include/linux/if_arp.h	Fri Apr 26 12:00:56 1996
@@ -22,6 +22,7 @@
 #ifndef _LINUX_IF_ARP_H
 #define _LINUX_IF_ARP_H
 
+
 /* ARP protocol HARDWARE identifiers. */
 #define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/
 #define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/
diff -u --recursive --new-file v1.3.95/linux/include/linux/major.h linux/include/linux/major.h
--- v1.3.95/linux/include/linux/major.h	Tue Apr 23 13:57:13 1996
+++ linux/include/linux/major.h	Fri Apr 26 10:30:52 1996
@@ -33,6 +33,7 @@
 #define XT_DISK_MAJOR	13
 #define SOUND_MAJOR	14
 #define CDU31A_CDROM_MAJOR 15
+#define JOYSTICK_MAJOR	15
 #define GOLDSTAR_CDROM_MAJOR 16
 #define OPTICS_CDROM_MAJOR 17
 #define SANYO_CDROM_MAJOR 18
@@ -54,17 +55,20 @@
 #define MATSUSHITA_CDROM3_MAJOR 27
 #define MATSUSHITA_CDROM4_MAJOR 28
 #define STL_SIOMEMMAJOR 28
+#define ACSI_MAJOR	28
 #define AZTECH_CDROM_MAJOR 29
-#define GRAPHDEV_MAJOR 29	/* SparcLinux /dev/fb */
+#define GRAPHDEV_MAJOR	29	/* SparcLinux & Linux/68k /dev/fb */
 #define CM206_CDROM_MAJOR 32
 #define IDE2_MAJOR	33
 #define IDE3_MAJOR	34
 #define NETLINK_MAJOR	36
 #define IDETAPE_MAJOR	37
+#define Z2RAM_MAJOR	37
 #define RISCOM8_NORMAL_MAJOR 48
 #define RISCOM8_CALLOUT_MAJOR 49
 #define APBLOCK_MAJOR   60   /* AP1000 Block device */
 #define DDV_MAJOR       61   /* AP1000 DDV block device */
+
 /*
  * Tests for SCSI devices.
  */
diff -u --recursive --new-file v1.3.95/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v1.3.95/linux/include/linux/miscdevice.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/miscdevice.h	Fri Apr 26 10:30:52 1996
@@ -5,6 +5,8 @@
 #define PSMOUSE_MINOR  1
 #define MS_BUSMOUSE_MINOR 2
 #define ATIXL_BUSMOUSE_MINOR 3
+#define AMIGAMOUSE_MINOR 4
+#define ATARIMOUSE_MINOR 5
 #define SUN_MOUSE_MINOR 6
 #define MISC_DYNAMIC_MINOR 255
 
diff -u --recursive --new-file v1.3.95/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.95/linux/include/linux/mm.h	Tue Apr 23 13:57:13 1996
+++ linux/include/linux/mm.h	Sat Apr 27 15:05:15 1996
@@ -4,14 +4,15 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+
+#ifdef __KERNEL__
+
 #include <linux/string.h>
 
 extern unsigned long high_memory;
 
 #include <asm/page.h>
 #include <asm/atomic.h>
-
-#ifdef __KERNEL__
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
diff -u --recursive --new-file v1.3.95/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.95/linux/include/linux/proc_fs.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/proc_fs.h	Sat Apr 27 15:05:23 1996
@@ -131,6 +131,10 @@
 	PROC_SCSI_NCR53C406A,
 	PROC_SCSI_PPA,
 	PROC_SCSI_ESP,
+	PROC_SCSI_A3000,
+	PROC_SCSI_A2091,
+	PROC_SCSI_GVP11,
+	PROC_SCSI_ATARI,
 	PROC_SCSI_SCSI_DEBUG,	
 	PROC_SCSI_NOT_PRESENT,
 	PROC_SCSI_FILE,                        /* I'm assuming here that we */
diff -u --recursive --new-file v1.3.95/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.95/linux/include/linux/sched.h	Tue Apr 23 13:57:14 1996
+++ linux/include/linux/sched.h	Sat Apr 27 15:05:15 1996
@@ -269,6 +269,7 @@
 #define PF_EXITING	0x00000200	/* getting shut down */
 
 #define PF_USEDFPU	0x00100000	/* Process used the FPU this quantum (SMP only) */
+#define PF_DTRACE	0x00200000	/* delayed trace (used on m68k) */
 
 /*
  * Limit the stack by to some sane default: root can always
@@ -344,6 +345,7 @@
 extern void wake_up_process(struct task_struct * tsk);
 
 extern void notify_parent(struct task_struct * tsk);
+extern void force_sig(unsigned long sig,struct task_struct * p);
 extern int send_sig(unsigned long sig,struct task_struct * p,int priv);
 extern int in_group_p(gid_t grp);
 
@@ -373,6 +375,7 @@
 extern void flush_thread(void);
 extern void exit_thread(void);
 
+extern void exit_mm(struct task_struct *);
 extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
diff -u --recursive --new-file v1.3.95/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v1.3.95/linux/include/linux/skbuff.h	Wed Apr 10 17:02:26 1996
+++ linux/include/linux/skbuff.h	Sat Apr 27 15:05:23 1996
@@ -13,10 +13,9 @@
  
 #ifndef _LINUX_SKBUFF_H
 #define _LINUX_SKBUFF_H
-#include <linux/malloc.h>
-#include <linux/wait.h>
-#include <linux/time.h>
+
 #include <linux/config.h>
+#include <linux/time.h>
 
 #include <asm/atomic.h>
 
@@ -131,6 +130,7 @@
 /*
  *	Handling routines are only of interest to the kernel
  */
+#include <linux/malloc.h>
 
 #include <asm/system.h>
 
diff -u --recursive --new-file v1.3.95/linux/include/linux/timex.h linux/include/linux/timex.h
--- v1.3.95/linux/include/linux/timex.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/timex.h	Fri Apr 26 14:20:19 1996
@@ -17,12 +17,27 @@
 /*
  * Modification history timex.h
  *
+ * 26 Sep 94	David L. Mills
+ *	Added defines for hybrid phase/frequency-lock loop.
+ *
+ * 19 Mar 94	David L. Mills
+ *	Moved defines from kernel routines to header file and added new
+ *	defines for PPS phase-lock loop.
+ *
+ * 20 Feb 94	David L. Mills
+ *	Revised status codes and structures for external clock and PPS
+ *	signal discipline.
+ *
+ * 28 Nov 93	David L. Mills
+ *	Adjusted parameters to improve stability and increase poll
+ *	interval.
+ *
  * 17 Sep 93    David L. Mills
  *      Created file $NTP/include/sys/timex.h
  * 07 Oct 93    Torsten Duwe
  *      Derived linux/timex.h
  * 1995-08-13    Torsten Duwe
- *      kernel PLL updated to 1994-12-13 specs (rfc-1489)
+ *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
  */
 #ifndef _LINUX_TIMEX_H
 #define _LINUX_TIMEX_H
@@ -67,14 +82,16 @@
  * SHIFT_USEC defines the scaling (shift) of the time_freq and
  * time_tolerance variables, which represent the current frequency
  * offset and maximum frequency tolerance.
+ *
+ * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
  */
-#define SHIFT_SCALE 22		/* shift for phase scale factor */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */
+#define SHIFT_SCALE 22		/* phase scale (shift) */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
 #define SHIFT_USEC 16		/* frequency offset scale (shift) */
 #define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
 
 #define MAXPHASE 512000L        /* max phase error (us) */
-#define MAXFREQ (100L << SHIFT_USEC)  /* max frequency error (ppm) */
+#define MAXFREQ (512L << SHIFT_USEC)  /* max frequency error (ppm) */
 #define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
 #define MINSEC 16L              /* min interval between updates (s) */
 #define MAXSEC 1200L            /* max interval between updates (s) */
@@ -171,6 +188,9 @@
 #define MOD_ESTERROR	ADJ_ESTERROR
 #define MOD_STATUS	ADJ_STATUS
 #define MOD_TIMECONST	ADJ_TIMECONST
+#define MOD_CLKB	ADJ_TICK
+#define MOD_CLKA	ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
+
 
 /*
  * Status codes (timex.status)
@@ -198,17 +218,19 @@
 /*
  * Clock states (time_state)
  */
-#define TIME_OK		0	/* clock synchronized */
+#define TIME_OK		0	/* clock synchronized, no leap second */
 #define TIME_INS	1	/* insert leap second */
 #define TIME_DEL	2	/* delete leap second */
 #define TIME_OOP	3	/* leap second in progress */
-#define TIME_WAIT	4	/* leap second has occurred */
+#define TIME_WAIT	4	/* leap second has occured */
 #define TIME_ERROR	5	/* clock not synchronized */
 #define TIME_BAD	TIME_ERROR /* bw compat */
 
 #ifdef __KERNEL__
 /*
  * kernel variables
+ * Note: maximum error = NTP synch distance = dispersion + delay / 2;
+ * estimated error = NTP dispersion.
  */
 extern long tick;                      /* timer interrupt period */
 extern int tickadj;			/* amount of adjustment per tick */
diff -u --recursive --new-file v1.3.95/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v1.3.95/linux/include/linux/ufs_fs.h	Tue Apr 23 13:57:14 1996
+++ linux/include/linux/ufs_fs.h	Fri Apr 26 12:12:24 1996
@@ -153,7 +153,7 @@
 	ufsquad	fs_qbmask;		/* ~usb_bmask - for use with __s64 size */
 	ufsquad	fs_qfmask;		/* ~usb_fmask - for use with __s64 size */
 	__s32	fs_postblformat;	/* format of positional layout tables */
-	__s32	fs_nrpos;		/* number of rotaional positions */
+	__s32	fs_nrpos;		/* number of rotational positions */
 	__s32	fs_postbloff;		/* (__s16) rotation block list head */
 	__s32	fs_rotbloff;		/* (__u8) blocks for each rotation */
 	__s32	fs_magic;		/* magic number */
diff -u --recursive --new-file v1.3.95/linux/include/net/tcp.h linux/include/net/tcp.h
--- v1.3.95/linux/include/net/tcp.h	Sun Apr 21 12:39:03 1996
+++ linux/include/net/tcp.h	Sat Apr 27 15:10:26 1996
@@ -127,7 +127,6 @@
 
 extern struct proto tcp_prot;
 extern struct tcp_mib tcp_statistics;
-extern struct wait_queue *master_select_wakeup;
 
 extern void	tcp_err(int type, int code, unsigned char *header, __u32 daddr,
 			__u32, struct inet_protocol *protocol);
@@ -311,10 +310,6 @@
 	case TCP_ESTABLISHED:
 		if (oldstate != TCP_ESTABLISHED) {
 			tcp_statistics.TcpCurrEstab++;
-			/* This is a hack but it doesn't occur often and it's going to
-			   be a real        to fix nicely */
-			if (oldstate == TCP_SYN_RECV)
-				wake_up_interruptible(&master_select_wakeup);
 		}
 		break;
 
diff -u --recursive --new-file v1.3.95/linux/init/main.c linux/init/main.c
--- v1.3.95/linux/init/main.c	Tue Apr 23 13:57:14 1996
+++ linux/init/main.c	Sat Apr 27 11:07:18 1996
@@ -121,6 +121,7 @@
 static void ramdisk_start_setup(char *str, int *ints);
 static void load_ramdisk(char *str, int *ints);
 static void prompt_ramdisk(char *str, int *ints);
+static void ramdisk_size(char *str, int *ints);
 #ifdef CONFIG_BLK_DEV_INITRD
 static void no_initrd(char *s,int *ints);
 #endif
@@ -132,6 +133,18 @@
 extern void teles_setup(char *str, int *ints);
 #endif
 
+#ifdef CONFIG_ATARIMOUSE
+extern void atari_mouse_setup (char *str, int *ints);
+#endif
+#ifdef CONFIG_DMASOUND
+extern void dmasound_setup (char *str, int *ints);
+#endif
+#ifdef CONFIG_ATARI_SCSI
+extern void atari_scsi_setup (char *str, int *ints);
+#endif
+extern void wd33c93_setup (char *str, int *ints);
+extern void gvp11_setup (char *str, int *ints);
+
 #ifdef CONFIG_DIGI
 extern void pcxx_setup(char *str, int *ints);
 #endif
@@ -163,6 +176,7 @@
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_size;		/* Size of the ramdisk(s) */
 extern int rd_image_start;	/* starting block # of image */
 #ifdef CONFIG_BLK_DEV_INITRD
 kdev_t real_root_dev;
@@ -224,6 +238,8 @@
 	{ "ramdisk_start=", ramdisk_start_setup },
 	{ "load_ramdisk=", load_ramdisk },
 	{ "prompt_ramdisk=", prompt_ramdisk },
+	{ "ramdisk=", ramdisk_size },
+	{ "ramdisk_size=", ramdisk_size },
 #ifdef CONFIG_BLK_DEV_INITRD
 	{ "noinitrd", no_initrd },
 #endif
@@ -346,6 +362,22 @@
 #ifdef CONFIG_ISDN_DRV_PCBIT
 	{ "pcbit=", pcbit_setup },
 #endif
+#ifdef CONFIG_ATARIMOUSE
+	{ "atamouse=", atari_mouse_setup },
+#endif
+#ifdef CONFIG_DMASOUND
+	{ "dmasound=", dmasound_setup },
+#endif
+#ifdef CONFIG_ATARI_SCSI
+	{ "atascsi=", atari_scsi_setup },
+#endif
+#if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
+	    || defined(CONFIG_GVP11_SCSI)
+	{ "wd33c93=", wd33c93_setup },
+#endif
+#if defined(CONFIG_GVP11_SCSI)
+	{ "gvp11=", gvp11_setup },
+#endif
 #ifdef CONFIG_DIGI
 	{ "digi=", pcxx_setup },
 #endif
@@ -373,6 +405,13 @@
    if (ints[0] > 0 && ints[1] >= 0)
       rd_prompt = ints[1] & 1;
 }
+
+static void ramdisk_size(char *str, int *ints)
+{
+	if (ints[0] > 0 && ints[1] >= 0)
+		rd_size = ints[1];
+}
+
 #endif
 
 static int checksetup(char *line)
diff -u --recursive --new-file v1.3.95/linux/ipc/shm.c linux/ipc/shm.c
--- v1.3.95/linux/ipc/shm.c	Wed Apr 17 09:06:33 1996
+++ linux/ipc/shm.c	Fri Apr 26 10:08:50 1996
@@ -454,7 +454,7 @@
 		set_pte(page_table, __pte(shm_sgn));
 	}
 	flush_tlb_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
-	return 0;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v1.3.95/linux/kernel/exit.c linux/kernel/exit.c
--- v1.3.95/linux/kernel/exit.c	Wed Apr 24 17:00:43 1996
+++ linux/kernel/exit.c	Thu Apr 25 15:08:44 1996
@@ -49,6 +49,26 @@
 		wake_up_process(p);
 }
 
+/*
+ * Force a signal that the process can't ignore: if necessary
+ * we unblock the signal and change any SIG_IGN to SIG_DFL.
+ */
+void force_sig(unsigned long sig, struct task_struct * p)
+{
+	sig--;
+	if (p->sig) {
+		unsigned long mask = 1UL << sig;
+		struct sigaction *sa = p->sig->action + sig;
+		p->signal |= mask;
+		p->blocked &= ~mask;
+		if (sa->sa_handler == SIG_IGN)
+			sa->sa_handler = SIG_DFL;
+		if (p->state == TASK_INTERRUPTIBLE)
+			wake_up_process(p);
+	}
+}
+		
+
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
 {
 	if (!p || sig > 32)
@@ -428,17 +448,17 @@
 	__exit_sighand(tsk);
 }
 
-static inline void exit_mm(void)
+static inline void __exit_mm(struct task_struct * tsk)
 {
-	struct mm_struct * mm = current->mm;
+	struct mm_struct * mm = tsk->mm;
 
 	/* Set us up to use the kernel mm state */
 	if (mm != &init_mm) {
 		flush_cache_mm(mm);
 		flush_tlb_mm(mm);
-		current->mm = &init_mm;
-		current->swappable = 0;
-		SET_PAGE_DIR(current, swapper_pg_dir);
+		tsk->mm = &init_mm;
+		tsk->swappable = 0;
+		SET_PAGE_DIR(tsk, swapper_pg_dir);
 
 		/* free the old state - not used any more */
 		if (!--mm->count) {
@@ -449,6 +469,11 @@
 	}
 }
 
+void exit_mm(struct task_struct *tsk)
+{
+	__exit_mm(tsk);
+}
+
 /* 
  * Send signals to all our closest relatives so that they know
  * to properly mourn us..
@@ -528,7 +553,7 @@
 	del_timer(&current->real_timer);
 	sem_exit();
 	kerneld_exit();
-	exit_mm();
+	__exit_mm(current);
 	__exit_files(current);
 	__exit_fs(current);
 	__exit_sighand(current);
diff -u --recursive --new-file v1.3.95/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.95/linux/kernel/sched.c	Wed Apr 24 17:00:43 1996
+++ linux/kernel/sched.c	Fri Apr 26 10:42:04 1996
@@ -2,6 +2,8 @@
  *  linux/kernel/sched.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  1996-04-21	Modified by Ulrich Windl to make NTP work
  */
 
 /*
@@ -52,14 +54,15 @@
 /*
  * phase-lock loop variables
  */
-int time_state = TIME_BAD;	/* clock synchronization status */
-int time_status = STA_UNSYNC | STA_PLL;	/* clock status bits */
+/* TIME_ERROR prevents overwriting the CMOS clock */
+int time_state = TIME_ERROR;	/* clock synchronization status */
+int time_status = STA_UNSYNC;	/* clock status bits */
 long time_offset = 0;		/* time adjustment (us) */
 long time_constant = 2;		/* pll time constant */
 long time_tolerance = MAXFREQ;	/* frequency tolerance (ppm) */
 long time_precision = 1;	/* clock precision (us) */
-long time_maxerror = 0x70000000;/* maximum error */
-long time_esterror = 0x70000000;/* estimated error */
+long time_maxerror = MAXPHASE;	/* maximum error (us) */
+long time_esterror = MAXPHASE;	/* estimated error (us) */
 long time_phase = 0;		/* phase offset (scaled us) */
 long time_freq = 0;		/* frequency offset (scaled ppm) */
 long time_adj = 0;		/* tick adjust (scaled 1 / HZ) */
@@ -396,7 +399,8 @@
 	return;
 
 scheduling_in_interrupt:
-	printk("Aiee: scheduling in interrupt\n");
+	printk("Aiee: scheduling in interrupt %p\n",
+		__builtin_return_address(0));
 }
 
 #ifndef __alpha__
@@ -665,9 +669,9 @@
     long ltemp;
 
     /* Bump the maxerror field */
-    time_maxerror = (0x70000000-time_maxerror <
-		     time_tolerance >> SHIFT_USEC) ?
-	0x70000000 : (time_maxerror + (time_tolerance >> SHIFT_USEC));
+    time_maxerror += time_tolerance >> SHIFT_USEC;
+    if ( time_maxerror > MAXPHASE )
+        time_maxerror = MAXPHASE;
 
     /*
      * Leap second processing. If in leap-insert state at
@@ -704,7 +708,6 @@
 	break;
 
     case TIME_OOP:
-
 	time_state = TIME_WAIT;
 	break;
 
@@ -727,21 +730,17 @@
 	if (!(time_status & STA_FLL))
 	    ltemp >>= SHIFT_KG + time_constant;
 	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-	    ltemp = (MAXPHASE / MINSEC) <<
-		SHIFT_UPDATE;
+	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
 	time_offset += ltemp;
-	time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ -
-			      SHIFT_UPDATE);
+	time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     } else {
 	ltemp = time_offset;
 	if (!(time_status & STA_FLL))
 	    ltemp >>= SHIFT_KG + time_constant;
 	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-	    ltemp = (MAXPHASE / MINSEC) <<
-		SHIFT_UPDATE;
+	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
 	time_offset -= ltemp;
-	time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ -
-			     SHIFT_UPDATE);
+	time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     }
 
     /*
@@ -775,6 +774,7 @@
 #endif
 }
 
+/* in the NTP reference this is called "hardclock()" */
 static void update_wall_time_one_tick(void)
 {
 	/*
diff -u --recursive --new-file v1.3.95/linux/kernel/time.c linux/kernel/time.c
--- v1.3.95/linux/kernel/time.c	Sat Feb 17 09:19:43 1996
+++ linux/kernel/time.c	Thu Apr 25 09:59:33 1996
@@ -75,9 +75,9 @@
 	cli();
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
-	time_state = TIME_BAD;
-	time_maxerror = 0x70000000;
-	time_esterror = 0x70000000;
+	time_state = TIME_ERROR;
+	time_maxerror = MAXPHASE;
+	time_esterror = MAXPHASE;
 	sti();
 	return 0;
 }
@@ -317,7 +317,7 @@
 		    time_freq = time_tolerance;
 		  else if (time_freq < -time_tolerance)
 		    time_freq = -time_tolerance;
-		}
+		} /* STA_PLL || STA_PPSTIME */
 	    if (txc.modes & ADJ_TICK)
 	      tick = txc.tick;
 
diff -u --recursive --new-file v1.3.95/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.95/linux/mm/filemap.c	Wed Apr 24 17:00:43 1996
+++ linux/mm/filemap.c	Sat Apr 27 12:31:27 1996
@@ -424,8 +424,8 @@
  *   We try to have a limit of MAX_READWINDOW = 48K.
  */
 
-#define MAX_READWINDOW (PAGE_SIZE*32)
-#define MAX_READAHEAD (PAGE_SIZE*16)
+#define MAX_READWINDOW (PAGE_SIZE*12)
+#define MAX_READAHEAD (PAGE_SIZE*7)
 #define MIN_READAHEAD (PAGE_SIZE)
 
 static inline unsigned long generic_file_readahead(struct file * filp, struct inode * inode,
@@ -987,7 +987,7 @@
 	unsigned long end = address + size;
 	int error = 0;
 
-	dir = pgd_offset(current->mm, address);
+	dir = pgd_offset(vma->vm_mm, address);
 	flush_cache_range(vma->vm_mm, end - size, end);
 	while (address < end) {
 		error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags);
diff -u --recursive --new-file v1.3.95/linux/mm/memory.c linux/mm/memory.c
--- v1.3.95/linux/mm/memory.c	Tue Apr 23 13:57:14 1996
+++ linux/mm/memory.c	Thu Apr 25 08:42:34 1996
@@ -931,7 +931,7 @@
 	 */
 	page = vma->vm_ops->nopage(vma, address, write_access && !(vma->vm_flags & VM_SHARED));
 	if (!page) {
-		send_sig(SIGBUS, current, 1);
+		force_sig(SIGBUS, current);
 		flush_cache_page(vma, address);
 		put_page(page_table, BAD_PAGE);
 		flush_tlb_page(vma, address);
diff -u --recursive --new-file v1.3.95/linux/net/README linux/net/README
--- v1.3.95/linux/net/README	Fri Sep  1 14:31:57 1995
+++ linux/net/README	Fri Apr 26 10:42:04 1996
@@ -6,12 +6,12 @@
 802 [other	]	alan@cymru.net	
     [token ring	]	needs a maintainer/debugger
 appletalk		alan@cymru.net and netatalk@umich.edu
-ax25			g4klx@g4klx.demon.co.uk
+ax25			jsn@cs.nott.ac.uk
 core			alan@cymru.net
 ethernet		alan@cymru.net
 ipv4			alan@cymru.net
 ipx			alan@cymru.net,greg@caldera.com
-netrom			g4klx@g4klx.demon.co.uk
+netrom			jsn@cs.nott.ac.uk
 unix			alan@cymru.net
 
 
diff -u --recursive --new-file v1.3.95/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.95/linux/net/ax25/af_ax25.c	Fri Apr 19 10:08:02 1996
+++ linux/net/ax25/af_ax25.c	Fri Apr 26 10:42:04 1996
@@ -614,7 +614,7 @@
 	  		break;
 
 	  	case AX25_T3:
-	  		if (ax25_ctl.arg < 1) 
+	  		if (ax25_ctl.arg < 0) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
 	  		ax25->t3 = ax25_ctl.arg * PR_SLOWHZ;
@@ -624,10 +624,8 @@
 	  		break;
 
 	  	case AX25_IDLE:
-	  		if (ax25_ctl.arg < 1) 
+	  		if (ax25_ctl.arg < 0) 
 	  			return -EINVAL;
-	  		if (ax25->idle == 0)
-	  			return 0;
 			save_flags(flags); cli();
 	  		ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60;
 	  		if (ax25->idletimer != 0)
@@ -682,7 +680,7 @@
 	ax25->n2      = AX25_DEF_N2;
 	ax25->paclen  = AX25_DEF_PACLEN;
 	ax25->maxqueue= AX25_DEF_IPMAXQUEUE;
-	ax25->idle    = 0;
+	ax25->idle    = AX25_DEF_IDLE;
 
 	ax25->modulus   = AX25_DEF_AXDEFMODE;
 	ax25->fragno    = 0;
@@ -753,9 +751,9 @@
 	ax25->n2       = ax25_dev_get_value(dev, AX25_VALUES_N2);
 	ax25->paclen   = ax25_dev_get_value(dev, AX25_VALUES_PACLEN);
 	ax25->maxqueue = ax25_dev_get_value(dev, AX25_VALUES_IPMAXQUEUE);
+	ax25->idle     = ax25_dev_get_value(dev, AX25_VALUES_IDLE);
 
 	ax25->dama_slave = 0;
-	ax25->idle = 0;
 
 	ax25->modulus = ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE);
 
@@ -819,7 +817,7 @@
 
 	/* idle timeouts only for mode vc connections */
 
-	ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
+	ax25->idletimer = ax25->idle;
 		
 	ax25_insert_socket(ax25);
 
@@ -1196,7 +1194,8 @@
 	ax25->idle    = osk->ax25->idle;
 	ax25->paclen  = osk->ax25->paclen;
 
-	ax25->window  = osk->ax25->window;
+	ax25->window   = osk->ax25->window;
+	ax25->maxqueue = osk->ax25->maxqueue;
 
 	ax25->source_addr = osk->ax25->source_addr;
 	
@@ -1823,7 +1822,7 @@
 		}
 
 		ax25_fillin_cb(ax25, dev);
-		ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
+		ax25->idletimer = ax25->idle;
 #else
 		if (mine) {
 			ax25_rt_rx_frame(&src, dev, &dp);
@@ -2272,7 +2271,6 @@
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
-	int idletimer;
 
 	cli();
 
@@ -2283,9 +2281,6 @@
 			devname = "???";
 		else
 			devname = dev->name;
-			
-		idletimer = ax25->idletimer / (PR_SLOWHZ * 60);
-		idletimer += (ax25->idletimer && ax25->idletimer < ax25->idle)? 1:0;
 
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&ax25->dest_addr));
@@ -2299,8 +2294,8 @@
 			ax25->t2      / PR_SLOWHZ,
 			ax25->t3timer / PR_SLOWHZ,
 			ax25->t3      / PR_SLOWHZ,
-			idletimer,
-			ax25->idle      / (PR_SLOWHZ*60),
+			ax25->idletimer / (PR_SLOWHZ * 60),
+			ax25->idle      / (PR_SLOWHZ * 60),
 			ax25->n2count, ax25->n2,
 			ax25->rtt     / PR_SLOWHZ,
 			ax25->window,
diff -u --recursive --new-file v1.3.95/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v1.3.95/linux/net/ax25/ax25_in.c	Fri Apr 12 15:52:11 1996
+++ linux/net/ax25/ax25_in.c	Fri Apr 26 10:42:04 1996
@@ -163,13 +163,14 @@
 	unsigned char pid;
 	
 	if (skb == NULL) return 0;
+
+	ax25->idletimer = ax25->idle;
 	
 	pid = *skb->data;
 
 	switch (pid) {
 #ifdef CONFIG_NETROM
 		case AX25_P_NETROM:
-			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			if (ax25_dev_get_value(ax25->device, AX25_VALUES_NETROM)) {
 				skb_pull(skb, 1);	/* Remove PID */
 				queued = nr_route_frame(skb, ax25);
@@ -178,23 +179,19 @@
 #endif
 #ifdef CONFIG_INET
 		case AX25_P_IP:
-			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			skb_pull(skb, 1);	/* Remove PID */
 			skb->h.raw = skb->data;
 			ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V');
 			ip_rcv(skb, ax25->device, NULL);	/* Wrong ptype */
 			queued = 1;
-			
 			break;
 #endif
 		case AX25_P_SEGMENT:
-			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			skb_pull(skb, 1);	/* Remove PID */
 			queued = ax25_rx_fragment(ax25, skb);
 			break;
 
 		default:
-			ax25->idletimer = ax25->idle = 0;
 			if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) {
 				if (sock_queue_rcv_skb(ax25->sk, skb) == 0) {
 					queued = 1;
diff -u --recursive --new-file v1.3.95/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v1.3.95/linux/net/ax25/ax25_out.c	Fri Apr 12 15:52:11 1996
+++ linux/net/ax25/ax25_out.c	Fri Apr 26 10:42:04 1996
@@ -77,21 +77,12 @@
 	mtu = ax25->paclen;
 	
 	if ((skb->len - 1) > mtu) {
-		switch (*skb->data) {
-			case AX25_P_SEGMENT:
-				/* this is an error, but... */
-				printk("ax25_output(): woops, fragmentation of fragment?!\n");
-				/* okay, let's fragment it further (tss, tss...) */
-			case AX25_P_NETROM:	/* err, is this a good idea? */
-			case AX25_P_IP:
-				mtu -= 2;	/* Allow for fragment control info */
-				ka9qfrag = 1;
-				break;
-			default:
-				ka9qfrag = 0;
-				skb_pull(skb, 1); /* skip PID */
-				break;
-
+		if (*skb->data == AX25_P_TEXT) {
+			skb_pull(skb, 1); /* skip PID */
+			ka9qfrag = 0;
+		} else {
+			mtu -= 2;	/* Allow for fragment control info */
+			ka9qfrag = 1;
 		}
 		
 		fragno = skb->len / mtu;
@@ -105,11 +96,10 @@
 			/* 
 			 * do _not_ use sock_alloc_send_skb, our socket may have
 			 * sk->shutdown set...
-			 *
 			 */
 			if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
 				restore_flags(flags);
-				printk("ax25_output(): alloc_skb returned NULL\n");
+				printk("ax25_output: alloc_skb returned NULL\n");
 				if (skb_device_locked(skb))
 					skb_device_unlock(skb);
 				return;
diff -u --recursive --new-file v1.3.95/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v1.3.95/linux/net/ax25/ax25_timer.c	Fri Apr 12 15:52:11 1996
+++ linux/net/ax25/ax25_timer.c	Fri Apr 26 10:42:04 1996
@@ -197,8 +197,7 @@
 
 		ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 
-		if (ax25->sk != NULL)
-		{
+		if (ax25->sk != NULL) {
 			ax25->sk->state = TCP_CLOSE;
 			ax25->sk->err = 0;
 			if (!ax25->sk->dead)
@@ -208,7 +207,6 @@
 		}
 	}
 		                                                                                                                                                                                                                                                                                                                                        
-
 	/* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
 	/* 		  nevertheless we have to re-enqueue the timer struct...   */
 	
diff -u --recursive --new-file v1.3.95/linux/net/bridge/br.c linux/net/bridge/br.c
--- v1.3.95/linux/net/bridge/br.c	Sun Apr 21 12:39:03 1996
+++ linux/net/bridge/br.c	Fri Apr 26 10:42:04 1996
@@ -1065,6 +1065,8 @@
 		return(0);
 
 	port = find_port(skb->dev);
+	
+	skb->arp = 1;		/* Received frame so it is resolved */
 	skb->h.raw = skb->mac.raw;
 	if (br_stats.flags & BR_DEBUG)
 		printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
diff -u --recursive --new-file v1.3.95/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.95/linux/net/core/dev.c	Wed Apr 10 17:02:27 1996
+++ linux/net/core/dev.c	Fri Apr 26 10:42:05 1996
@@ -605,9 +605,21 @@
 		 
 		if (br_stats.flags & BR_UP)
 		{
+			/*
+			 *	We pass the bridge a complete frame. This means
+			 *	recovering the MAC header first.
+			 */
+			 
+			int offset=skb->data-skb->mac.raw;
 			cli();
+			skb_push(skb,offset);	/* Put header back on for bridge */
 			if(br_receive_frame(skb))
 				continue;
+			/*
+			 *	Pull the MAC header off for the copy going to
+			 *	the upper layers.
+			 */
+			skb_pull(skb,offset);
 			sti();
 		}
 #endif
@@ -621,9 +633,9 @@
 
 		skb->h.raw = skb->data;
 
-	       /*
-		* 	Fetch the packet protocol ID. 
-		*/
+		/*
+		 * 	Fetch the packet protocol ID. 
+		 */
 		
 		type = skb->protocol;
 
diff -u --recursive --new-file v1.3.95/linux/net/core/iovec.c linux/net/core/iovec.c
--- v1.3.95/linux/net/core/iovec.c	Tue Feb 13 16:57:42 1996
+++ linux/net/core/iovec.c	Sat Apr 27 14:02:45 1996
@@ -35,11 +35,11 @@
 	{
 		if(mode==VERIFY_READ) {
 			err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-			m->msg_name = address;
 		} else
 			err=verify_area(mode, m->msg_name, m->msg_namelen);
 		if(err<0)
 			return err;
+		m->msg_name = address;
 	}
 	if(m->msg_accrights!=NULL)
 	{
diff -u --recursive --new-file v1.3.95/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v1.3.95/linux/net/core/skbuff.c	Wed Apr 10 17:02:27 1996
+++ linux/net/core/skbuff.c	Fri Apr 26 09:41:18 1996
@@ -36,22 +36,24 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+
 #include <net/ip.h>
 #include <net/protocol.h>
-#include <linux/string.h>
 #include <net/route.h>
 #include <net/tcp.h>
 #include <net/udp.h>
-#include <linux/skbuff.h>
 #include <net/sock.h>
 
+#include <asm/segment.h>
+#include <asm/system.h>
 
 /*
  *	Resource tracking variables
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v1.3.95/linux/net/ipv4/Config.in	Mon Mar 25 08:58:24 1996
+++ linux/net/ipv4/Config.in	Thu Apr 25 13:52:17 1996
@@ -22,7 +22,7 @@
 	tristate 'IP: aliasing support' CONFIG_IP_ALIAS
 fi
 if [ "$CONFIG_KERNELD" = "y" ]; then
-	bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD
+#	bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD
 fi
 comment '(it is safe to leave these untouched)'
 bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v1.3.95/linux/net/ipv4/icmp.c	Fri Apr 12 15:52:12 1996
+++ linux/net/ipv4/icmp.c	Fri Apr 26 10:42:05 1996
@@ -18,16 +18,23 @@
  *		Alan Cox	:	Multicast ping reply as self.
  *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit call
  *		Alan Cox	:	Added 216,128 byte paths to the MTU code.
+ *		Martin Mares	:	RFC1812 checks.
+ *		Martin Mares	:	Can be configured to follow redirects if acting
+ *					as a router _without_ a routing protocol (RFC 1812).
+ *		Martin Mares	:	Echo requests may be configured to be ignored (RFC 1812).
+ *		Martin Mares	:	Limitation of ICMP error message transmit rate (RFC 1812).
+ *		Martin Mares	:	TOS and Precedence set correctly (RFC 1812).
  *
  *
  *
- * RFC1122 Status: (boy, are there a lot of rules for ICMP)
+ * RFC1122 (Host Requirements -- Comm. Layer) Status:
+ * (boy, are there a lot of rules for ICMP)
  *  3.2.2 (Generic ICMP stuff)
  *   MUST discard messages of unknown type. (OK)
  *   MUST copy at least the first 8 bytes from the offending packet
- *     when sending ICMP errors. (OK)
+ *     when sending ICMP errors. (OBSOLETE -- see RFC1812)
  *   MUST pass received ICMP errors up to protocol level. (OK)
- *   SHOULD send ICMP errors with TOS == 0. (OK)
+ *   SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812)
  *   MUST NOT send ICMP errors in reply to:
  *     ICMP errors (OK)
  *     Broadcast/multicast datagrams (OK)
@@ -38,8 +45,8 @@
  *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
  *  3.2.2.2 (Redirect)
  *   Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
- *   MUST update routing table in response to host or network redirects. 
- *     (host OK, network NOT YET) [Intentionally -- AC]
+ *   MUST update routing table in response to host or network redirects.
+ *     (host OK, network OBSOLETE)
  *   SHOULD drop redirects if they're not from directly connected gateway
  *     (OK -- we drop it if it's not from our old gateway, which is close
  *      enough)
@@ -50,7 +57,7 @@
  *   MUST pass TIME_EXCEEDED to transport layer (OK)
  *   Other requirements dealt with at IP (generating TIME_EXCEEDED).
  * 3.2.2.5 (Parameter Problem)
- *   SHOULD generate these, but it doesn't say for what.  So we're OK. =)
+ *   SHOULD generate these (OK)
  *   MUST pass received PARAMPROBLEM to transport layer (NOT YET)
  *   	[Solaris 2.X seems to assert EPROTO when this occurs] -- AC
  * 3.2.2.6 (Echo Request/Reply)
@@ -60,7 +67,7 @@
  *     We're OK for unicast ECHOs, and it doesn't say anything about
  *     how to handle broadcast ones, since it's optional.
  *   MUST copy data from REQUEST to REPLY (OK)
- *     unless it would require illegal fragmentation (N/A)
+ *     unless it would require illegal fragmentation (OK)
  *   MUST pass REPLYs to transport/user layer (OK)
  *   MUST use any provided source route (reversed) for REPLY. (NOT YET)
  * 3.2.2.7 (Information Request/Reply)
@@ -81,6 +88,130 @@
  *   MUST discard received REPLYs if not using this system (OK)
  *   MUST NOT send replies unless specifically made agent for this sort
  *     of thing. (OK)
+ *
+ *
+ * RFC 1812 (IPv4 Router Requirements) Status (even longer):
+ *  4.3.2.1 (Unknown Message Types)
+ *   MUST pass messages of unknown type to ICMP user iface or silently discard
+ *     them (OK)
+ *  4.3.2.2 (ICMP Message TTL)
+ *   MUST initialize TTL when originating an ICMP message (OK)
+ *  4.3.2.3 (Original Message Header)
+ *   SHOULD copy as much data from the offending packet as possible without
+ *     the length of the ICMP datagram exceeding 576 bytes (NOT YET)
+ *   MUST leave original IP header of the offending packet, but we're not
+ *     required to undo modifications made (OK)
+ *  4.3.2.4 (Original Message Source Address)
+ *   MUST use one of addresses for the interface the orig. packet arrived as
+ *     source address (OK)
+ *  4.3.2.5 (TOS and Precedence)
+ *   SHOULD leave TOS set to the same value unless the packet would be discarded
+ *     for that reason (OK)
+ *   MUST use TOS=0 if not possible to leave original value (OK)
+ *   MUST leave IP Precedence for Source Quench messages (OK -- not sent at all)
+ *   SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control)
+ *     for all other error messages (OK, we use 6)
+ *   MAY allow configuration of IP Precedence (OK -- not done)
+ *   MUST leave IP Precedence and TOS for reply messages (OK)
+ *  4.3.2.6 (Source Route)
+ *   SHOULD use reverse source route UNLESS sending Parameter Problem on source
+ *     routing and UNLESS the packet would be immediately discarded (NOT YET)
+ *  4.3.2.7 (When Not to Send ICMP Errors)
+ *   MUST NOT send ICMP errors in reply to:
+ *     ICMP errors (OK)
+ *     Packets failing IP header validation tests unless otherwise noted (OK)
+ *     Broadcast/multicast datagrams (OK)
+ *     MAC broadcasts (OK)
+ *     Non-initial fragments (OK)
+ *     Datagram with a source address that isn't a single host. (OK)
+ *  4.3.2.8 (Rate Limiting)
+ *   SHOULD be able to limit error message rate (OK)
+ *   SHOULD allow setting of rate limits (OK, in the source)
+ *  4.3.3.1 (Destination Unreachable)
+ *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
+ *  4.3.3.2 (Redirect)
+ *   MAY ignore ICMP Redirects if running a routing protocol or if forwarding
+ *     is enabled on the interface (OK -- ignores)
+ *  4.3.3.3 (Source Quench)
+ *   SHOULD NOT originate SQ messages (OK)
+ *   MUST be able to limit SQ rate if originates them (OK as we don't send them)
+ *   MAY ignore SQ messages it receives (OK -- we don't)
+ *  4.3.3.4 (Time Exceeded)
+ *   Requirements dealt with at IP (generating TIME_EXCEEDED).
+ *  4.3.3.5 (Parameter Problem)
+ *   MUST generate these for all errors not covered by other messages (OK)
+ *   MUST include original value of the value pointed by (OK)
+ *  4.3.3.6 (Echo Request)
+ *   MUST implement echo server function (OK)
+ *   MUST process at ER of at least max(576, MTU) (OK)
+ *   MAY reject broadcast/multicast ER's (We don't, but that's OK)
+ *   SHOULD have a config option for silently ignoring ER's (OK)
+ *   MUST have a default value for the above switch = NO (OK)
+ *   MUST have application layer interface for Echo Request/Reply (OK)
+ *   MUST reply using same source address as the request was sent to.
+ *     We're OK for unicast ECHOs, and it doesn't say anything about
+ *     how to handle broadcast ones, since it's optional.
+ *   MUST copy data from Request to Reply (OK)
+ *   SHOULD update Record Route / Timestamp options (??)
+ *   MUST use reversed Source Route for Reply if possible (NOT YET)
+ *  4.3.3.7 (Information Request/Reply)
+ *   SHOULD NOT originate or respond to these (OK)
+ *  4.3.3.8 (Timestamp / Timestamp Reply)
+ *   MAY implement (OK)
+ *   MUST reply to every Timestamp message received (OK)
+ *   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
+ *   MUST reply using same source address as the request was sent to. (OK)
+ *   MUST use reversed Source Route if possible (NOT YET)
+ *   SHOULD update Record Route / Timestamp options (??)
+ *   MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK)
+ *   MUST update clock for timestamp at least 16 times/sec (OK)
+ *   MUST be "correct within a few minutes" (OK)
+ * 4.3.3.9 (Address Mask Request/Reply)
+ *   MUST have support for receiving AMRq and responding with AMRe (OK, but only as a
+ *     compile-time option)
+ *   SHOULD have option for each interface for AMRe's, MUST default to NO (NOT YET)
+ *   MUST NOT reply to AMRq before knows the correct AM (OK)
+ *   MUST NOT respond to AMRq with source address 0.0.0.0 and the AM's for
+ *     logical i-faces for the physical i-face are not the same (NOT YET)
+ *   SHOULD examine all AMRe's it receives and check them (NOT YET)
+ *   SHOULD log invalid AMRe's (AM+sender) (NOT YET)
+ *   MUST NOT use contents of AMRe to determine correct AM (OK)
+ *   MAY broadcast AMRe's after having configured address masks (OK -- doesn't)
+ *   MUST NOT do broadcast AMRe's if not set by extra option (OK, no option)
+ *   MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK)
+ * 4.3.3.10 (Router Advertisement and Solicitations)
+ *   MUST support router part of Router Discovery Protocol on all networks we
+ *     support broadcast or multicast addressing. (OK -- done by gated)
+ *   MUST have all config parameters with the respective defaults (OK)
+ * 5.2.7.1 (Destination Unreachable)
+ *   MUST generate DU's (OK)
+ *   SHOULD choose a best-match response code (OK)
+ *   SHOULD NOT generate Host Isolated codes (OK)
+ *   SHOULD use Communication Administratively Prohibited when administratively
+ *     filtering packets (NOT YET)
+ *   MAY include config option for not generating the above and silently discard
+ *     the packets instead (OK)
+ *   MAY include config option for not generating Precedence Violation and
+ *     Precedence Cutoff messages (OK as we don't generate them at all)
+ *   MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts
+ *     on the same network might be reachable (OK -- no net unreach's at all)
+ *   MUST use new form of Fragmentation Needed and DF Set messages (OK)
+ * 5.2.7.2 (Redirect)
+ *   MUST NOT generate network redirects (OK)
+ *   MUST be able to generate host redirects (OK)
+ *   SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS)
+ *   MUST have an option to use Host redirects instead of Host+TOS ones (OK as
+ *     no Host+TOS Redirects are used)
+ *   MUST NOT generate redirects unless forwarding to the same i-face and the
+ *     dest. address is on the same subnet as the src. address and no source
+ *     routing is in use. (OK)
+ *   MUST NOT follow redirects when using a routing protocol (OK)
+ *   MAY use redirects if not using a routing protocol (OK, compile-time option)
+ *   MUST comply to Host Requirements when not acting as a router (OK)
+ *  5.2.7.3 (Time Exceeded)
+ *   MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK)
+ *   MAY have a per-interface option to disable origination of TE messages, but
+ *     it MUST default to "originate" (OK -- we don't support it)
  */
 
 #include <linux/config.h>
@@ -142,6 +273,34 @@
 unsigned long dummy;
 
 /*
+ *	ICMP transmit rate limit control structures. We use a relatively simple
+ *	approach to the problem: For each type of ICMP message with rate limit
+ *	we count the number of messages sent during some time quantum. If this
+ *	count exceeds given maximal value, we ignore all messages not separated
+ *	from the last message sent at least by specified time.
+ */
+
+#define XRLIM_CACHE_SIZE 16		/* How many destination hosts do we cache */
+
+struct icmp_xrl_cache			/* One entry of the ICMP rate cache */
+{
+	__u32 daddr;			/* Destination address */
+	unsigned long counter;		/* Message counter */
+	unsigned long next_reset;	/* Time of next reset of the counter */
+	unsigned long last_access;	/* Time of last access to this entry (LRU) */
+	unsigned int restricted;	/* Set if we're in restricted mode */
+	unsigned long next_packet;	/* When we'll allow a next packet if restricted */
+};
+
+struct icmp_xrlim
+{
+	unsigned long timeout;		/* Time quantum for rate measuring */
+	unsigned long limit;		/* Maximal number of messages per time quantum allowed */
+	unsigned long delay;		/* How long we wait between packets when restricting */
+	struct icmp_xrl_cache cache[XRLIM_CACHE_SIZE];	/* Rate cache */
+};
+
+/*
  *	ICMP control array. This specifies what to do with each ICMP.
  */
  
@@ -150,7 +309,8 @@
 	unsigned long *output;		/* Address to increment on output */
 	unsigned long *input;		/* Address to increment on input */
 	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len);
-	unsigned long error;		/* This ICMP is classed as an error message */	
+	unsigned long error;		/* This ICMP is classed as an error message */
+	struct icmp_xrlim *xrlim;	/* Transmit rate limit control structure or NULL for no limits */
 };
 
 static struct icmp_control icmp_pointers[19];
@@ -183,6 +343,97 @@
  
 
 /*
+ *	Initialize the transmit rate limitation mechanism.
+ */
+
+#ifndef CONFIG_NO_ICMP_LIMIT
+
+static void xrlim_init(void)
+{
+	int type, entry;
+	struct icmp_xrlim *xr;
+
+	for (type=0; type<=18; type++) {
+		xr = icmp_pointers[type].xrlim;
+		if (xr) {
+			for (entry=0; entry<XRLIM_CACHE_SIZE; entry++)
+				xr->cache[entry].daddr = INADDR_NONE;
+		}
+	}
+}
+
+/*
+ *	Check transmit rate limitation for given message.
+ *
+ *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
+ *			  SHOULD allow setting of rate limits (we allow in the source)
+ */
+
+static int xrlim_allow(int type, __u32 addr)
+{
+	struct icmp_xrlim *r;
+	struct icmp_xrl_cache *c;
+	unsigned long now;
+
+	if (type > 18)			/* No time limit present */
+		return 1;
+	r = icmp_pointers[type].xrlim;
+	if (!r)
+		return 1;
+
+	for (c = r->cache; c < &r->cache[XRLIM_CACHE_SIZE]; c++)	/* Cache lookup */
+		if (c->daddr == addr)
+			break;
+
+	now = jiffies;		/* Cache current time (saves accesses to volatile variable) */
+
+	if (c == &r->cache[XRLIM_CACHE_SIZE]) {		/* Cache miss */
+		unsigned long oldest = now;		/* Find the oldest entry to replace */
+		struct icmp_xrl_cache *d;
+		c = r->cache;
+		for (d = r->cache; d < &r->cache[XRLIM_CACHE_SIZE]; d++)
+			if (!d->daddr) {		/* Unused entry */
+				c = d;
+				break;
+			} else if (d->last_access < oldest) {
+				oldest = d->last_access;
+				c = d;
+			}
+		c->last_access = now;			/* Fill the entry with new data */
+		c->daddr = addr;
+		c->counter = 1;
+		c->next_reset = now + r->timeout;
+		c->restricted = 0;
+		return 1;
+	}
+
+	c->last_access = now;
+	if (c->next_reset > now) {			/* Let's increment the counter */
+		c->counter++;
+		if (c->counter == r->limit) {		/* Limit exceeded, start restrictions */
+			c->restricted = 1;
+			c->next_packet = now + r->delay;
+			return 0;
+		}
+		if (c->restricted) {			/* Any restrictions pending? */
+			if (c->next_packet > now)
+				return 0;
+			c->next_packet = now + r->delay;
+			return 1;
+		}
+	} else {					/* Reset the counter */
+		if (c->counter < r->limit)		/* Switch off all restrictions */
+			c->restricted = 0;
+		c->next_reset = now + r->timeout;
+		c->counter = 0;
+	}
+
+	return 1;					/* Send the packet */
+}
+
+#endif /* CONFIG_NO_ICMP_LIMIT */
+
+/*
  *	Maintain the counters used in the SNMP statistics for outgoing ICMP
  */
  
@@ -229,12 +480,13 @@
  *	Driving logic for building and sending ICMP messages.
  */
 
-static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr)
+static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr, __u8 tos)
 {
 	struct sock *sk=icmp_socket.data;
 	icmp_param->icmph.checksum=0;
 	icmp_param->csum=0;
 	icmp_out_count(icmp_param->icmph.type);
+	sk->ip_tos = tos;
 	ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
 		icmp_param->data_len+sizeof(struct icmphdr),
 		daddr, saddr, &icmp_param->replyopts, 0, IPPROTO_ICMP, 1);
@@ -309,7 +561,16 @@
 				return;
 		}
 	}
-	
+
+	/*
+	 *	Check the rate limit
+	 */
+
+#ifndef CONFIG_NO_ICMP_LIMIT
+	if (!xrlim_allow(type, iph->saddr))
+		return;
+#endif	
+
 	/*
 	 *	Tell our driver what to send
 	 */
@@ -329,7 +590,7 @@
 	 */
 
 	if (ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in) == 0)
-	  icmp_build_xmit(&icmp_param, saddr, iph->saddr);
+	  icmp_build_xmit(&icmp_param, saddr, iph->saddr, ((iph->tos & 0x38) | 6));
 }
 
 
@@ -491,10 +752,12 @@
 	iph = (struct iphdr *) (icmph + 1);
 	ip = iph->daddr;
 
-#ifdef CONFIG_IP_FORWARD
 	/*
-	 *	We are a router. Routers should not respond to ICMP_REDIRECT messages.
+	 *	If we are a router and we run a routing protocol, we MUST NOT follow redirects.
+	 *	When using no routing protocol, we MAY follow redirects. (RFC 1812, 5.2.7.2)
 	 */
+
+#if defined(CONFIG_IP_FORWARD) && !defined(CONFIG_IP_DUMB_ROUTER)
 	printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %s, "
 	       "orig gw = %s, \"new\" gw = %s, device = %s.\n", in_ntoa(ip),
 		in_ntoa(source), in_ntoa(icmph->un.gateway), dev->name);
@@ -505,7 +768,8 @@
 			/*
 			 *	This causes a problem with subnetted networks. What we should do
 			 *	is use ICMP_ADDRESS to get the subnet mask of the problem route
-			 *	and set both. But we don't..
+			 *	and set both. But we don't.. [RFC1812 says routers MUST NOT
+			 *	generate Network Redirects]
 			 */
 #ifdef not_a_good_idea
 			ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
@@ -548,18 +812,21 @@
  *
  *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests.
  *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply.
+ *	RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT.
  *	See also WRT handling of options once they are done and working.
  */
  
 static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
+#ifndef CONFIG_IP_IGNORE_ECHO_REQUESTS
 	struct icmp_bxm icmp_param;
 	icmp_param.icmph=*icmph;
 	icmp_param.icmph.type=ICMP_ECHOREPLY;
 	icmp_param.data_ptr=(icmph+1);
 	icmp_param.data_len=len;
 	if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-		icmp_build_xmit(&icmp_param, daddr, saddr);
+		icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos);
+#endif
 	kfree_skb(skb, FREE_READ);
 }
 
@@ -604,7 +871,7 @@
 	icmp_param.data_ptr=&times;
 	icmp_param.data_len=12;
 	if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-		icmp_build_xmit(&icmp_param, daddr, saddr);
+		icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos);
 	kfree_skb(skb,FREE_READ);
 }
 
@@ -623,8 +890,7 @@
  
 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
-#ifdef CONFIG_IP_ADDR_AGENT
-	__u32 answer;
+#ifdef CONFIG_IP_ADDR_AGENT	/* Don't use, broken */
 	struct icmp_bxm icmp_param;
 	icmp_param.icmph.type=ICMP_ADDRESSREPLY;
 	icmp_param.icmph.code=0;
@@ -633,7 +899,7 @@
 	icmp_param.data_ptr=&dev->pa_mask;
 	icmp_param.data_len=4;
 	if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0)
-		icmp_build_xmit(&icmp_param, daddr, saddr);
+		icmp_build_xmit(&icmp_param, daddr, saddr, skb->iph->tos);
 #endif	
 	kfree_skb(skb, FREE_READ);	
 }
@@ -668,7 +934,7 @@
 	}
 	
 	/*
-	 *	18 is the highest 'known' icmp type. Anything else is a mystery
+	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
 	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
 	 */
@@ -712,43 +978,52 @@
 }
 
 /*
+ *	This table defined limits of ICMP sending rate for various ICMP messages.
+ */
+
+static struct icmp_xrlim
+	xrl_unreach = { 4*HZ, 80, HZ/4 },		/* Host Unreachable */
+	xrl_redirect = { 2*HZ, 10, HZ/2 },		/* Redirect */
+	xrl_generic = { 3*HZ, 30, HZ/4 };		/* All other errors */
+
+/*
  *	This table is the definition of how we handle ICMP.
  */
  
 static struct icmp_control icmp_pointers[19] = {
 /* ECHO REPLY (0) */
- { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* DEST UNREACH (3) */
- { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &xrl_unreach },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, NULL },
 /* REDIRECT (5) */
- { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, &xrl_redirect },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* ECHO (8) */
- { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
 /* TIME EXCEEDED (11) */
- { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1 },
+ { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &xrl_generic },
 /* PARAMETER PROBLEM (12) */
 /* FIXME: RFC1122 3.2.2.5 - MUST pass PARAM_PROB messages to transport layer */
- { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1 },
+ { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1, &xrl_generic },
 /* TIMESTAMP (13) */
- { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0 },
+ { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0, NULL },
 /* TIMESTAMP REPLY (14) */
- { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0 },
+ { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, NULL },
 /* INFO (15) */
- { &dummy, &dummy, icmp_discard, 0 },
+ { &dummy, &dummy, icmp_discard, 0, NULL },
 /* INFO REPLY (16) */
- { &dummy, &dummy, icmp_discard, 0 },
+ { &dummy, &dummy, icmp_discard, 0, NULL },
 /* ADDR MASK (17) */
- { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0 },
+ { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0, NULL },
 /* ADDR MASK REPLY (18) */
- { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0 }
+ { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0, NULL }
 };
 
 void icmp_init(struct proto_ops *ops)
@@ -762,5 +1037,8 @@
 	sk=icmp_socket.data;
 	sk->allocation=GFP_ATOMIC;
 	sk->num = 256;			/* Don't receive any data */
+#ifndef CONFIG_NO_ICMP_LIMIT
+	xrlim_init();
+#endif
 }
 
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v1.3.95/linux/net/ipv4/ip_fragment.c	Mon Mar 25 08:58:25 1996
+++ linux/net/ipv4/ip_fragment.c	Fri Apr 26 10:42:05 1996
@@ -248,7 +248,6 @@
 	{
 		NETDEBUG(printk("IP: create: no memory left !\n"));
 		return(NULL);
-		skb->dev = qp->dev;
 	}
 	memset(qp, 0, sizeof(struct ipq));
 
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v1.3.95/linux/net/ipv4/ip_sockglue.c	Wed Apr 10 17:02:28 1996
+++ linux/net/ipv4/ip_sockglue.c	Fri Apr 26 10:42:05 1996
@@ -9,6 +9,9 @@
  *
  * Fixes:
  *		Many		:	Split from ip.c , see ip.c for history.
+ *		Martin Mares	:	TOS setting fixed.
+ *		Alan Cox	:	Fixed a couple of oopses in Martins 
+ *					TOS tweaks.
  */
 
 #include <linux/config.h>
@@ -89,8 +92,6 @@
  *	an IP socket.
  *
  *	We implement IP_TOS (type of service), IP_TTL (time to live).
- *
- *	Next release we will sort out IP_OPTIONS since for some people are kind of important.
  */
 
 static struct device *ip_mc_find_devfor(unsigned long addr)
@@ -177,14 +178,23 @@
 			  	kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen);
 			  return 0;
 		  }
-		case IP_TOS:
-			if(val<0||val>255)
+		case IP_TOS:		/* This sets both TOS and Precedence */
+			if (val<0 || val>63)	/* Reject setting of unused bits */
 				return -EINVAL;
+			if ((val&3) > 4 && !suser())	/* Only root can set Prec>4 */
+				return -EPERM;
 			sk->ip_tos=val;
-			if(val==IPTOS_LOWDELAY)
-				sk->priority=SOPRI_INTERACTIVE;
-			if(val==IPTOS_THROUGHPUT)
-				sk->priority=SOPRI_BACKGROUND;
+			switch (val & 0x38) {
+				case IPTOS_LOWDELAY:
+					sk->priority=SOPRI_INTERACTIVE;
+					break;
+				case IPTOS_THROUGHPUT:
+					sk->priority=SOPRI_BACKGROUND;
+					break;
+				default:
+					sk->priority=SOPRI_NORMAL;
+					break;
+			}
 			return 0;
 		case IP_TTL:
 			if(val<1||val>255)
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.95/linux/net/ipv4/tcp.c	Sun Apr 21 12:39:03 1996
+++ linux/net/ipv4/tcp.c	Fri Apr 26 14:07:30 1996
@@ -437,12 +437,6 @@
 static void tcp_close(struct sock *sk, unsigned long timeout);
 
 /*
- *	The less said about this the better, but it works and will do for 1.2  (and 1.4 ;))
- */
-
-struct wait_queue *master_select_wakeup;
-
-/*
  *	Find someone to 'accept'. Must be called with
  *	the socket locked or with interrupts disabled
  */
@@ -463,24 +457,6 @@
 }
 
 /*
- *	Remove a completed connection and return it. This is used by
- *	tcp_accept() to get connections from the queue.
- */
-
-static struct sk_buff *tcp_dequeue_established(struct sock *s)
-{
-	struct sk_buff *skb;
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	skb=tcp_find_established(s);
-	if(skb!=NULL)
-		skb_unlink(skb);	/* Take it off the queue */
-	restore_flags(flags);
-	return skb;
-}
-
-/*
  *	This routine closes sockets which have been at least partially
  *	opened, but not yet accepted. Currently it is only called by
  *	tcp_close, and timeout mirrors the value there.
@@ -685,14 +661,15 @@
 static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait)
 {
 	if (sel_type == SEL_IN) {
-		int retval;
+		struct sk_buff * skb;
 
 		lock_sock(sk);
-		retval = (tcp_find_established(sk) != NULL);
+		skb = tcp_find_established(sk);
 		release_sock(sk);
-		if (!retval)
-			select_wait(&master_select_wakeup,wait);
-		return retval;
+		if (skb)
+			return 1;
+		select_wait(sk->sleep,wait);
+		return 0;
 	}
 	return 0;
 }
@@ -895,31 +872,53 @@
  *	and starts the transmit system.
  */
 
-static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
-	  int len, int nonblock, int flags)
+static int do_tcp_sendmsg(struct sock *sk,
+	int iovlen, struct iovec *iov,
+	int len, int nonblock, int flags)
 {
 	int copied = 0;
-	int copy;
-	int tmp;
-	int seglen;
-	int iovct=0;
-	struct sk_buff *skb;
-	struct sk_buff *send_tmp;
-	struct proto *prot;
 	struct device *dev = NULL;
-	unsigned char *from;
+
+	/*
+	 *	Wait for a connection to finish.
+	 */
+	while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+	{
+		if (sk->err)
+			return sock_error(sk);
+
+		if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
+		{
+			if (sk->keepopen)
+				send_sig(SIGPIPE, current, 0);
+			return -EPIPE;
+		}
+
+		if (nonblock)
+			return -EAGAIN;
+
+		if (current->signal & ~current->blocked)
+			return -ERESTARTSYS;
+
+		wait_for_tcp_connect(sk);
+	}
 
 	/*
 	 *	Ok commence sending
 	 */
 
-	while(iovct<msg->msg_iovlen)
+	while (--iovlen >= 0)
 	{
-		seglen=msg->msg_iov[iovct].iov_len;
-		from=msg->msg_iov[iovct++].iov_base;
-		prot = sk->prot;
+		int seglen=iov->iov_len;
+		unsigned char * from=iov->iov_base;
+		iov++;
+
 		while(seglen > 0)
 		{
+			int copy, delay;
+			int tmp;
+			struct sk_buff *skb;
+
 			/*
 			 * Stop on errors
 			 */
@@ -940,33 +939,6 @@
 				return -EPIPE;
 			}
 
-			/*
-			 *	Wait for a connection to finish.
-			 */
-			while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
-			{
-				if (copied)
-					return copied;
-
-				if (sk->err)
-					return sock_error(sk);
-
-				if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
-				{
-					if (sk->keepopen)
-						send_sig(SIGPIPE, current, 0);
-					return -EPIPE;
-				}
-
-				if (nonblock)
-					return -EAGAIN;
-
-				if (current->signal & ~current->blocked)
-					return -ERESTARTSYS;
-
-				wait_for_tcp_connect(sk);
-			}
-
 		/*
 		 * The following code can result in copy <= if sk->mss is ever
 		 * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
@@ -1055,20 +1027,18 @@
 		  		return -EFAULT;
 			}
 
-		/*
-		 *	We should really check the window here also.
-		 */
+			/*
+			 *	We should really check the window here also.
+			 */
 
-			send_tmp = NULL;
+			delay = 0;
+			tmp = copy + sk->prot->max_header + 15;
 			if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out)
 			{
-				skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL);
-				send_tmp = skb;
-			}
-			else
-			{
-				skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL);
+				tmp = tmp - copy + sk->mtu + 128;
+				delay = 1;
 			}
+			skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 
 			/*
 			 *	If we didn't get any memory, we need to sleep.
@@ -1104,7 +1074,7 @@
 			 * Perhaps some hints here would be good.
 			 */
 
-			tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+			tmp = sk->prot->build_header(skb, sk->saddr, sk->daddr, &dev,
 				 IPPROTO_TCP, sk->opt, skb->truesize,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache);
 			if (tmp < 0 )
 			{
@@ -1143,9 +1113,9 @@
 			skb->free = 0;
 			sk->write_seq += copy;
 
-			if (send_tmp != NULL)
+			if (delay)
 			{
-				tcp_enqueue_partial(send_tmp, sk);
+				tcp_enqueue_partial(skb, sk);
 				continue;
 			}
 			tcp_send_skb(sk, skb);
@@ -1186,7 +1156,7 @@
 	}
 
 	lock_sock(sk);
-	retval = do_tcp_sendmsg(sk, msg, len, nonblock, flags);
+	retval = do_tcp_sendmsg(sk, msg->msg_iovlen, msg->msg_iov, len, nonblock, flags);
 
 /*
  *	Nagle's rule. Turn Nagle off with TCP_NODELAY for highly
@@ -1798,62 +1768,79 @@
 
 
 /*
+ * Wait for a incoming connection, avoid race
+ * conditions. This must be called with the socket
+ * locked.
+ */
+static struct sk_buff * wait_for_connect(struct sock * sk)
+{
+	struct wait_queue wait = { current, NULL };
+	struct sk_buff * skb = NULL;
+
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+		release_sock(sk);
+		schedule();
+		lock_sock(sk);
+		skb = tcp_find_established(sk);
+		if (skb)
+			break;
+		if (current->signal & ~current->blocked)
+			break;
+	}
+	remove_wait_queue(sk->sleep, &wait);
+	return skb;
+}
+
+/*
  *	This will accept the next outstanding connection.
+ *
+ *	Be careful about race conditions here - this is subtle.
  */
 
 static struct sock *tcp_accept(struct sock *sk, int flags)
 {
-	struct sock *newsk;
+	int error;
 	struct sk_buff *skb;
+	struct sock *newsk = NULL;
 
   /*
    * We need to make sure that this socket is listening,
    * and that it has something pending.
    */
 
+	error = EINVAL;
 	if (sk->state != TCP_LISTEN)
-	{
-		sk->err = EINVAL;
-		return(NULL);
-	}
+		goto no_listen;
 
-	/* Avoid the race. */
-	cli();
 	lock_sock(sk);
 
-	while((skb = tcp_dequeue_established(sk)) == NULL)
-	{
-		if (flags & O_NONBLOCK)
-		{
-			sti();
-			release_sock(sk);
-			sk->err = EAGAIN;
-			return(NULL);
-		}
-
+	skb = tcp_find_established(sk);
+	if (skb) {
+got_new_connect:
+		__skb_unlink(skb, &sk->receive_queue);
+		newsk = skb->sk;
+		kfree_skb(skb, FREE_READ);
+		sk->ack_backlog--;
+		error = 0;
+out:
 		release_sock(sk);
-		interruptible_sleep_on(sk->sleep);
-		if (current->signal & ~current->blocked)
-		{
-			sti();
-			sk->err = ERESTARTSYS;
-			return(NULL);
-		}
-		lock_sock(sk);
-  	}
-	sti();
-
-	/*
-	 *	Now all we need to do is return skb->sk.
-	 */
-
-	newsk = skb->sk;
+no_listen:
+		sk->err = error;
+		return newsk;
+	}
 
-	kfree_skb(skb, FREE_READ);
-	sk->ack_backlog--;
-	release_sock(sk);
-	return(newsk);
+	error = EAGAIN;
+	if (flags & O_NONBLOCK)
+		goto out;
+	skb = wait_for_connect(sk);
+	if (skb)
+		goto got_new_connect;
+	error = ERESTARTSYS;
+	goto out;
 }
+
 
 /*
  *	This will initiate an outgoing connection.
diff -u --recursive --new-file v1.3.95/linux/net/socket.c linux/net/socket.c
--- v1.3.95/linux/net/socket.c	Fri Apr 12 15:52:13 1996
+++ linux/net/socket.c	Sat Apr 27 14:06:47 1996
@@ -1137,8 +1137,9 @@
 	if(msg_sys.msg_iovlen>MAX_IOVEC)
 		return -EINVAL;
 
-	err=verify_iovec(&msg_sys,iov,address, VERIFY_READ);
-	if(err<0)
+	/* This will also move the address data into kernel space */
+	err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
+	if (err < 0)
 		return err;
 	total_len=err;
 
@@ -1153,13 +1154,19 @@
 {
 	struct socket *sock;
 	struct file *file;
-	char address[MAX_SOCK_ADDR];
 	struct iovec iov[MAX_IOVEC];
 	struct msghdr msg_sys;
 	int err;
 	int total_len;
-	int addr_len;
 	int len;
+
+	/* kernel mode address */
+	char addr[MAX_SOCK_ADDR];
+	int addr_len;
+
+	/* user mode address pointers */
+	struct sockaddr *uaddr;
+	int *uaddr_len;
 	
 	if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
 		return(-EBADF);
@@ -1172,9 +1179,17 @@
 	memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
 	if(msg_sys.msg_iovlen>MAX_IOVEC)
 		return -EINVAL;
-	err=verify_iovec(&msg_sys,iov,address, VERIFY_WRITE);
+
+	/*
+	 * save the user-mode address (verify_iovec will change the
+	 * kernel msghdr to use the kernel address space)
+	 */
+	uaddr = msg_sys.msg_name;
+	uaddr_len = &msg->msg_namelen;
+	err=verify_iovec(&msg_sys,iov,addr, VERIFY_WRITE);
 	if(err<0)
 		return err;
+
 	total_len=err;
 	
 	if(sock->ops->recvmsg==NULL)
@@ -1182,11 +1197,12 @@
 	len=sock->ops->recvmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags, &addr_len);
 	if(len<0)
 		return len;
-	/*
-	 *	Fixme: writing actual length into original msghdr.
-	 */
-	if(msg_sys.msg_name!=NULL && (err=move_addr_to_user(address,addr_len, msg_sys.msg_name, &msg_sys.msg_namelen))<0)
-		return err;
+
+	if (uaddr != NULL) {
+		err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len);
+		if (err)
+			return err;
+	}
 	return len;
 }
 
diff -u --recursive --new-file v1.3.95/linux/scripts/lxdialog/menubox.c linux/scripts/lxdialog/menubox.c
--- v1.3.95/linux/scripts/lxdialog/menubox.c	Fri Apr 19 10:08:03 1996
+++ linux/scripts/lxdialog/menubox.c	Sat Apr 27 13:18:18 1996
@@ -199,7 +199,7 @@
     while (key != ESC) {
 	key = wgetch(dialog);
 
-	if (isalpha(key)) key = tolower(key);
+	if (key < 256 && isalpha(key)) key = tolower(key);
 
 	if (strchr("ynm", key))
 		i = max_choice;
diff -u --recursive --new-file v1.3.95/linux/scripts/lxdialog/util.c linux/scripts/lxdialog/util.c
--- v1.3.95/linux/scripts/lxdialog/util.c	Fri Apr 19 10:08:03 1996
+++ linux/scripts/lxdialog/util.c	Sat Apr 27 13:18:18 1996
@@ -347,8 +347,8 @@
 	for (i = 0; i < strlen(string); i++) {
 		c = tolower(string[i]);
 
-		if (c == '(') ++in_paren;
-		if (c == ')') --in_paren;
+		if (strchr("<[(", c)) ++in_paren;
+		if (strchr(">])", c)) --in_paren;
 
 		if ((! in_paren) && isalpha(c) && 
 		     strchr(exempt, c) == 0)
