diff -u --recursive --new-file v2.1.128/linux/CREDITS linux/CREDITS
--- v2.1.128/linux/CREDITS	Thu Nov 12 16:21:17 1998
+++ linux/CREDITS	Mon Nov 16 10:32:58 1998
@@ -429,7 +429,7 @@
 N: Cort Dougan
 E: cort@cs.nmt.edu
 W: http://www.cs.nmt.edu/~cort/
-D: PowerPC PReP port
+D: PowerPC
 S: Computer Science Department
 S: New Mexico Tech
 S: Socorro, New Mexico 87801
diff -u --recursive --new-file v2.1.128/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.128/linux/Documentation/Configure.help	Thu Nov 12 16:21:17 1998
+++ linux/Documentation/Configure.help	Sun Nov 15 10:12:01 1998
@@ -1759,6 +1759,58 @@
   which includes a server that supports the frame buffer device
   directly (XF68_FBDev).
 
+Matrox unified accelerated driver
+CONFIG_FB_MATROX
+  Say Y here if you have Matrox Millenium, Matrox Millenium II, Matrox
+  Mystique, Matrox Mystique 220 or Matrox Productiva G100 in your box.
+  At this time,  G100 support  is untested and  G200 support  does not
+  exist at all.  If you want,  you can select  M, in this  case module
+  matroxfb.o will be created.
+  You can pass parameters into driver if it is compiled into kernel by 
+  specifying "video=matrox:XXX", where meaning of XXX you can found at 
+  the end of main source file  (drivers/video/matroxfb.c) at boottime.
+  Same  parameters can  be passed  into insmod  if driver  is used  as 
+  module.
+
+Matrox Millenium support
+CONFIG_FB_MATROX_MILLENIUM
+  Say Y here if you have Matrox Millenium or Matrox Millenium II in the
+  box. If you  select "Advanced  lowlevel driver  options", you  should 
+  check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp packed pixel, 24
+  bpp  packed pixel  and 32  bpp packed  pixel. You  can also  use font 
+  widths different from 8.
+
+Matrox Mystique support
+CONFIG_FB_MATROX_MYSTIQUE
+  Say Y here if you have  Matrox Mystique or Matrox Mystique 220 in the 
+  box.  If you  select  "Advanced lowlevel driver options",  you should 
+  check  8 bpp packed pixel,  16 bpp packed pixel,  24 bpp packed pixel
+  and  32 bpp  packed pixel.  You can  also use  font widths  different 
+  from 8.
+
+Matrox G100 support
+CONFIG_FB_MATROX_G100
+  Say Y here  if you have  Matrox Productiva G100  in the box. But THIS 
+  DRIVER  IS NOT  TESTED BECAUSE  OF I  HAVE NO  G100  board  and  G100 
+  technical sheets  are top secret at this time.  But driver should not 
+  cause any damage to your computer.
+  If you select  "Advanced lowlevel  driver options",  you should check
+  8 bpp  packed pixel,  16 bpp  packed pixel,  24 bpp  packed pixel and 
+  32 bpp packed pixel. You can also use font widths different from 8.
+
+Matrox unified driver multihead support
+CONFIG_FB_MATROX_MULTIHEAD
+  Say Y  here if you  have more  than one (supported) Matrox  device in 
+  computer  and you  want to  use all  of them.  If you  have only  one 
+  device,  you should say N because of driver compiled with Y is larger 
+  and a bit slower, especially on ia32 (ix86).
+  If you compiled  driver as module,  you are VERY  interested in speed 
+  and  you can  use 40KB  of memory  per each  Matrox  device,  you can 
+  compile driver  without multihead  support and  instead of  it insmod 
+  more module instances. In this case, you MUST specify parameter dev=N 
+  to insmod, where N is sequential number of Matrox device  (0 = first, 
+  1 = second and so on).
+  
 MDA text console (dual-headed)
 CONFIG_MDA_CONSOLE
   Say Y here if you have an old MDA or monochrome Hercules graphics
@@ -3740,6 +3792,13 @@
   The module will be called fdomain.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Future Domain MCS-600/700 SCSI support
+CONFIG_SCSI_FD_MCS
+ This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some
+ PS/2s are also equipped with IBM Fast SCSI Adapter/A which is an OEM
+ of the MCS 700. This driver also supports Reply SB16/SCSI card (the 
+ SCSI part). It supports multiple adapters in the same system.
+
 Generic NCR5380/53c400 SCSI support
 CONFIG_SCSI_GENERIC_NCR5380
   This is the generic NCR family of SCSI controllers, not to be
@@ -3878,9 +3937,8 @@
   this feature, enter 0 or 1 here (it doesn't matter which).
 
   The default value is 8 and should be supported by most hard disks.
-  This option has no effect for adapters with NVRAM, since the driver
-  will get this information from the user set-up. It also can be
-  overridden using a boot setup option, as follows (example):
+  This value can be overridden from the boot command line using the 
+  'tags' option as follows (example):
   'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
   4, set queue depth to 16 for target 2 and target 3 on controller 0
   and set queue depth to 10 for target 0 / lun 2 on controller 1.
@@ -3895,12 +3953,10 @@
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS
   This option allows you to specify the maximum number of commands
   that can be queued to any device, when tagged command queuing is
-  possible. The default value is 32. Minimum is 2, maximum is 64. For
-  value less than 32, this option only saves a little memory
-  (8*7*(32-MAXTAGS) bytes), so using less than 32 isn't worth it. For
-  value greater than 32, latency on reselection will be increased by 1
-  or 2 micro-seconds. 
-
+  possible. The default value is 32. Minimum is 2, maximum is 64.
+  Modern hard disks are able to support 64 tags and even more, but 
+  donnot seem to be faster when more than 32 tags are being used.
+  
   So, the normal answer here is to go with the default value 32 unless
   you are using very large hard disks with large cache (>= 1 MB) that
   are able to take advantage of more than 32 tagged commands.
@@ -5013,9 +5069,9 @@
 
 Comtrol Hostess SV-11 support
 CONFIG_HOSTESS_SV11
-  This is a network card for high speed synchronous serial links. It
-  is commonly used to connect to Cisco equipment over HSSI links. At
-  this point, the driver can only be compiled as a module.
+  This is a network card for low speed synchronous serial links, at
+  up to 256Kbits. It supports both PPP and Cisco HDLC
+  At this point, the driver can only be compiled as a module.
 
 WAN Drivers
 CONFIG_WAN_DRIVERS
@@ -5576,7 +5632,7 @@
   is for you, read the Ethernet-HOWTO, available via FTP (user:
   anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
 
-AT1700 support
+AT1700/1720 support
 CONFIG_AT1700
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
@@ -9627,7 +9683,7 @@
 
 Ariadne support
 CONFIG_ARIADNE
-  If you have a VillageTronics Ariadne Ethernet adapter, say Y.
+  If you have a Village Tronic Ariadne Ethernet adapter, say Y.
   Otherwise, say N.
 
   This driver is also available as a module ( = code which can be
@@ -9637,7 +9693,7 @@
 
 Ariadne II support
 CONFIG_ARIADNE2
-  If you have a VillageTronics Ariadne II Ethernet adapter, say Y.
+  If you have a Village Tronic Ariadne II Ethernet adapter, say Y.
   Otherwise, say N.
 
   This driver is also available as a module ( = code which can be
@@ -10213,7 +10269,7 @@
 # LocalWords:  INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB
 # LocalWords:  AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP
 # LocalWords:  PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx
-# LocalWords:  VillageTronics ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
+# LocalWords:  Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
 # LocalWords:  Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes
 # LocalWords:  ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND
 # LocalWords:  fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic
diff -u --recursive --new-file v2.1.128/linux/Documentation/networking/ltpc.txt linux/Documentation/networking/ltpc.txt
--- v2.1.128/linux/Documentation/networking/ltpc.txt	Sat May  2 14:19:51 1998
+++ linux/Documentation/networking/ltpc.txt	Fri Nov 13 10:29:43 1998
@@ -6,18 +6,37 @@
 driver applies only to the one with the 65c02 processor chip on it.
 
 To include it in the kernel, select the CONFIG_LTPC switch in the
-configuration dialog; at this time (kernel 2.1.23) compiling it as
-a module will not work.
+configuration dialog.  You can also compile it as a module.
+
+While the driver will attempt to autoprobe the I/O port address, IRQ
+line, and DMA channel of the card, this does not always work.  For
+this reason, you should be prepared to supply these parameters
+yourself.  (see "Card Configuration" below for how to determine or
+change the settings on your card)
+
+When the driver is compiled into the kernel, you can add a line such
+as the following to your /etc/lilo.conf:
+
+ append="ltpc=0x240,9,1"
+
+where the parameters (in order) are the port address, IRQ, and DMA
+channel.  The second and third values can be omitted, in which case
+the driver will try to determine them itself.
+
+If you load the driver as a module, you can pass the parameters "io=",
+"irq=", and "dma=" on the command line with insmod or modprobe, or add
+them as options in /etc/conf.modules:
+
+ alias lt0 ltpc # autoload the module when the interface is configured
+ options ltpc io=0x240 irq=9 dma=1
 
 Before starting up the netatalk demons (perhaps in rc.local), you
 need to add a line such as:
 
-/sbin/ifconfig ltalk0 127.0.0.42
-
+ /sbin/ifconfig lt0 127.0.0.42
 
-The driver will autoprobe, and you should see a message like:
-"LocalTalk card found at 240, IR9, DMA1."
-at bootup.
+The address is unimportant - however, the card needs to be configured
+with ifconfig so that Netatalk can find it.
 
 The appropriate netatalk configuration depends on whether you are
 attached to a network that includes AppleTalk routers or not.  If,
@@ -25,22 +44,22 @@
 printers, you need to set up netatalk to "seed".  The way I do this
 is to have the lines
 
-dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
-ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
+ dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
+ lt0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
 
 in my atalkd.conf.  What is going on here is that I need to fool
 netatalk into thinking that there are two AppleTalk interfaces
-present -- otherwise it refuses to seed.  This is a hack, and a
-more permanent solution would be to alter the netatalk code.
-Note that the dummy driver needs to accept multicasts also -- earlier
-versions of dummy.c may need to be patched.  
-
+present; otherwise, it refuses to seed.  This is a hack, and a more
+permanent solution would be to alter the netatalk code.  Also, make
+sure you have the correct name for the dummy interface - If it's
+compiled as a module, you will need to refer to it as "dummy0" or some
+such.
 
 If you are attached to an extended AppleTalk network, with routers on
 it, then you don't need to fool around with this -- the appropriate
 line in atalkd.conf is
 
-ltalk0 -phase 1
+ lt0 -phase 1
 
 --------------------------------------
 
@@ -74,19 +93,32 @@
 --------------------------------------
 
 IP:
-	Many people are interested in this driver in order to use IP
-when LocalTalk, but no Ethernet, is available.  While the code to do
-this is not strictly speaking part of this driver, an experimental 
-version is available which seems to work under kernel 2.0.xx.  It is
-not yet functional in the 2.1.xx kernels.
+
+Yes, it is possible to do IP over LocalTalk.  However, you can't just
+treat the LocalTalk device like an ordinary Ethernet device, even if
+that's what it looks like to Netatalk.
+
+Instead, you follow the same procedure as for doing IP in EtherTalk.
+See Documentation/networking/ipddp.txt for more information about the
+kernel driver and userspace tools needed.
 
 --------------------------------------
 
 BUGS:
 
-2.0.xx:
-
-2.1.xx:	The module support doesn't work yet.
+IRQ autoprobing often doesn't work on a cold boot.  To get around
+this, either compile the driver as a module, or pass the parameters
+for the card to the kernel as described above.
+
+Also, as usual, autoprobing is not recommended when you use the driver
+as a module. (though it usually works at boot time, at least)
+
+Polled mode is *really* slow sometimes, but this seems to depend on
+the configuration of the network.
+
+It may theoretically be possible to use two LTPC cards in the same
+machine, but this is unsupported, so if you really want to do this,
+you'll probably have to hack the initialization code a bit.
 
 ______________________________________
 
@@ -96,3 +128,4 @@
 
 -- Bradford Johnson <bradford@math.umn.edu>
 
+-- Updated 11/09/1998 by David Huggins-Daines <dhd@debian.org>
diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/README linux/Documentation/sysctl/README
--- v2.1.128/linux/Documentation/sysctl/README	Wed Jun 24 22:54:02 1998
+++ linux/Documentation/sysctl/README	Fri Nov 13 10:07:26 1998
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/*/*		version 0.1
+Documentation for /proc/sys/		kernel version 2.1.128
 	(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 'Why', I hear you ask, 'would anyone even _want_ documentation
@@ -12,6 +12,9 @@
 Furthermore, the programmers who built sysctl have built it to
 be actually used, not just for the fun of programming it :-)
 
+If you prefer HTML, feel free to visit the Linux-MM homepage
+<http://www.phys.uu.nl/~riel/mm-patch/>...
+
 ==============================================================
 
 Legal blurb:
@@ -58,9 +61,9 @@
 debug/		<empty>
 dev/		device specific information (eg dev/cdrom/info)
 fs/		specific filesystems
+		filehandle, inode, dentry and quota tuning
 		binfmt_misc <linux/Documentation/binfmt_misc.txt>
 kernel/		global kernel info / tuning
-		open file / inode tuning
 		miscellaneous stuff
 net/		networking stuff, for documentation look in:
 		<linux/Documentation/networking/>
diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt
--- v2.1.128/linux/Documentation/sysctl/fs.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sysctl/fs.txt	Fri Nov 13 10:07:26 1998
@@ -0,0 +1,116 @@
+Documentation for /proc/sys/fs/*	kernel version 2.1.128
+	(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
+
+For general info and legal blurb, please look in README.
+
+==============================================================
+
+This file contains documentation for the sysctl files in
+/proc/sys/fs/ and is valid for Linux kernel version 2.1.
+
+The files in this directory can be used to tune and monitor
+miscellaneous and general things in the operation of the Linux
+kernel. Since some of the files _can_ be used to screw up your
+system, it is advisable to read both documentation and source
+before actually making adjustments.
+
+Currently, these files are in /proc/sys/fs:
+- dentry-state
+- dquot-max
+- dquot-nr
+- file-max
+- file-nr
+- inode-max
+- inode-nr
+- inode-state
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/binfmt_misc.txt.
+
+==============================================================
+
+dentry-state:
+
+From linux/fs/dentry.c:
+--------------------------------------------------------------
+struct {
+        int nr_dentry;
+        int nr_unused;
+        int age_limit;         /* age in seconds */
+        int want_pages;        /* pages requested by system */
+        int dummy[2];
+} dentry_stat = {0, 0, 45, 0,};
+-------------------------------------------------------------- 
+
+Dentries are dynamically allocated and deallocated, and
+nr_dentry seems to be 0 all the time. Hence it's safe to
+assume that only nr_unused, age_limit and want_pages are
+used. Nr_unused seems to be exactly what its name says.
+Age_limit is the age in seconds after which dcache entries
+can be reclaimed when memory is short and want_pages is
+nonzero when shrink_dcache_pages() has been called and the
+dcache isn't pruned yet.
+
+==============================================================
+
+dquot-max & dquot-nr:
+
+The file dquot-max shows the maximum number of cached disk
+quota entries.
+
+The file dquot-nr shows the number of allocated disk quota
+entries and the number of free disk quota entries.
+
+If the number of free cached disk quotas is very low and
+you have some awesome number of simultaneous system users,
+you might want to raise the limit.
+
+==============================================================
+
+file-max & file-nr:
+
+The kernel allocates file handles dynamically, but as yet it
+doesn't free them again.
+
+The value in file-max denotes the maximum number of file-
+handles that the Linux kernel will allocate. When you get lots
+of error messages about running out of file handles, you might
+want to increase this limit.
+
+The three values in file-nr denote the number of allocated
+file handles, the number of used file handles and the maximum
+number of file handles. When the allocated file handles come
+close to the maximum, but the number of actually used ones is
+far behind, you've encountered a peak in your usage of file
+handles and you don't need to increase the maximum.
+
+==============================================================
+
+inode-max, inode-nr & inode-state:
+
+As with file handles, the kernel allocates the inode structures
+dynamically, but can't free them yet.
+
+The value in inode-max denotes the maximum number of inode
+handlers. This value should be 3-4 times larger than the value
+in file-max, since stdin, stdout and network sockets also
+need an inode struct to handle them. When you regularly run
+out of inodes, you need to increase this value.
+
+The file inode-nr contains the first two items from
+inode-state, so we'll skip to that file...
+
+Inode-state contains three actual numbers and four dummies.
+The actual numbers are, in order of appearance, nr_inodes,
+nr_free_inodes and preshrink.
+
+Nr_inodes stands for the number of inodes the system has
+allocated, this can be slightly more than inode-max because
+Linux allocates them one pageful at a time.
+
+Nr_free_inodes represents the number of free inodes (?) and
+preshrink is nonzero when the nr_inodes > inode-max and the
+system needs to prune the inode list instead of allocating
+more.
+
+
diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt
--- v2.1.128/linux/Documentation/sysctl/kernel.txt	Thu Nov 12 16:21:17 1998
+++ linux/Documentation/sysctl/kernel.txt	Fri Nov 13 10:07:26 1998
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/kernel/*	version 0.1
+Documentation for /proc/sys/kernel/*	kernel version 2.1.128
 	(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
@@ -14,26 +14,27 @@
 system, it is advisable to read both documentation and source
 before actually making adjustments.
 
-Currently, these files are in /proc/sys/kernel:
+Currently, these files might (depending on your configuration)
+show up in /proc/sys/kernel:
 - acct
 - ctrl-alt-del
 - dentry-state
 - domainname
-- file-max
-- file-nr
 - hostname
-- inode-max
-- inode-nr
-- inode-state
+- htab-reclaim                [ PPC only ]
+- java-appletviewer           [ binfmt_java, obsolete ]
+- java-interpreter            [ binfmt_java, obsolete ]
 - modprobe                    ==> Documentation/kmod.txt
 - osrelease
 - ostype
 - panic
+- powersave-nap               [ PPC only ]
 - printk
 - real-root-dev               ==> Documentation/initrd.txt
-- reboot-cmd                  ==> SPARC specific
-- securelevel
+- reboot-cmd                  [ SPARC only ]
+- sg-big-buff                 [ generic SCSI device (sg) ]
 - version
+- zero-paged                  [ PPC only ]
 
 ==============================================================
 
@@ -69,30 +70,6 @@
 
 ==============================================================
 
-dentry-state:
-
-From linux/fs/dentry.c:
---------------------------------------------------------------
-struct {
-        int nr_dentry;
-        int nr_unused;
-        int age_limit;         /* age in seconds */
-        int want_pages;        /* pages requested by system */
-        int dummy[2];
-} dentry_stat = {0, 0, 45, 0,};
--------------------------------------------------------------- 
-
-Dentries are dynamically allocated and deallocated, and
-nr_dentry seems to be 0 all the time. Hence it's safe to
-assume that only nr_unused, age_limit and want_pages are
-used. Nr_unused seems to be exactly what its name says.
-Age_limit is the age in seconds after which dcache entries
-can be reclaimed when memory is short and want_pages is
-nonzero when shrink_dcache_pages() has been called and the
-dcache isn't pruned yet.
-
-==============================================================
-
 domainname & hostname:
 
 These files can be controlled to set the domainname and
@@ -104,52 +81,12 @@
 
 ==============================================================
 
-file-max & file-nr:
-
-The kernel allocates file handles dynamically, but as yet it
-doesn't free them again.
-
-The value in file-max denotes the maximum number of file-
-handles that the Linux kernel will allocate. When you get lots
-of error messages about running out of file handles, you might
-want to increase this limit.
-
-The three values in file-nr denote the number of allocated
-file handles, the number of used file handles and the maximum
-number of file handles. When the allocated file handles come
-close to the maximum, but the number of actually used ones is
-far behind, you've encountered a peak in your usage of file
-handles and you don't need to increase the maximum.
-
-==============================================================
-
-inode-max, inode-nr & inode-state:
-
-As with file handles, the kernel allocates the inode structures
-dynamically, but can't free them yet.
-
-The value in inode-max denotes the maximum number of inode
-handlers. This value should be 3-4 times larger than the value
-in file-max, since stdin, stdout and network sockets also
-need an inode struct to handle them. When you regularly run
-out of inodes, you need to increase this value.
-
-The file inode-nr contains the first two items from
-inode-state, so we'll skip to that file...
-
-Inode-state contains three actual numbers and four dummies.
-The actual numbers are, in order of appearance, nr_inodes,
-nr_free_inodes and preshrink.
-
-Nr_inodes stands for the number of inodes the system has
-allocated, this can be slightly more than inode-max because
-Linux allocates them one pageful at a time.
-
-Nr_free_inodes represents the number of free inodes (?) and
-preshrink is nonzero when the nr_inodes > inode-max and the
-system needs to prune the inode list instead of allocating
-more.
+htab-reclaim: (PPC only)
 
+Setting this to a non-zero value, the PowerPC htab
+(see Documentation/powerpc/ppc_htab.txt) is pruned
+each time the system hits the idle loop.
+ 
 ==============================================================
 
 osrelease, ostype & version:
@@ -177,6 +114,13 @@
 
 ==============================================================
 
+powersave-nap: (PPC only)
+
+If set, Linux-PPC will use the 'nap' mode of powersaving,
+otherwise the 'doze' mode will be used.
+
+==============================================================
+
 printk:
 
 The four values in printk denote: console_loglevel,
@@ -202,27 +146,30 @@
 
 ==============================================================
 
-securelevel:
+reboot-cmd: (Sparc only)
 
-When the value in this file is nonzero, root is prohibited
-from:
-- changing the immutable and append-only flags on files
-- changing sysctl things (limited ???)
+??? This seems to be a way to give an argument to the Sparc
+ROM/Flash boot loader. Maybe to tell it what to do after
+rebooting. ???
 
 ==============================================================
 
-real-root-dev: (CONFIG_INITRD only)
+sg-big-buff:
 
-This file is used to configure the real root device when using
-an initial ramdisk to configure the system before switching to
-the 'real' root device. See linux/Documentation/initrd.txt for
-more info.
+This file shows the size of the generic SCSI (sg) buffer.
+You can't tune it just yet, but you could change it on
+compile time by editing include/scsi/sg.h and changing
+the value of SG_BIG_BUFF.
 
-==============================================================
+There shouldn't be any reason to change this value. If
+you can come up with one, you probably know what you
+are doing anyway :)
 
-reboot-cmd: (Sparc only)
+==============================================================
 
-??? This seems to be a way to give an argument to the Sparc
-ROM/Flash boot loader. Maybe to tell it what to do after
-rebooting. ???
+zero-paged: (PPC only)
 
+When enabled (non-zero), Linux-PPC will pre-zero pages in
+the idle loop, possibly speeding up get_free_pages. Since
+this only affects what the idle loop is doing, you should
+enable this and see if anything changes.
diff -u --recursive --new-file v2.1.128/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt
--- v2.1.128/linux/Documentation/sysctl/vm.txt	Wed Jun 24 22:54:02 1998
+++ linux/Documentation/sysctl/vm.txt	Fri Nov 13 10:07:26 1998
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*	version 0.1
+Documentation for /proc/sys/vm/*	kernel version 2.1.128
 	(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
@@ -20,8 +20,8 @@
 - kswapd
 - overcommit_memory
 - pagecache
+- pagetable_cache
 - swapctl
-- swapout_interval
 
 ==============================================================
 
@@ -56,7 +56,7 @@
 } bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 --------------------------------------------------------------
 
-The first parameter governs the maximum number of of dirty
+The first parameter governs the maximum number of dirty
 buffers in the buffer cache. Dirty means that the contents
 of the buffer still have to be written to disk (as opposed
 to a clean buffer, which can just be forgotten about).
@@ -101,8 +101,9 @@
 min_percent	-- this is the minimum percentage of memory
 		   that should be spent on buffer memory
 borrow_percent  -- when Linux is short on memory, and the
-                   buffer cache uses more memory, free pages
-                   are stolen from it
+                   buffer cache uses more memory than this,
+                   the MM subsystem will prune the buffercache
+                   more heavily than other memory
 max_percent     -- this is the maximum amount of memory that
                    can be used for buffer memory 
 
@@ -112,25 +113,17 @@
 This file contains the values in the struct freepages. That
 struct contains three members: min, low and high.
 
-Although the goal of the Linux memory management subsystem
-is to avoid fragmentation and make large chunks of free
-memory (so that we can hand out DMA buffers and such), there
-still are some page-based limits in the system, mainly to
-make sure we don't waste too much memory trying to get large
-free area's.
-
 The meaning of the numbers is:
 
 freepages.min	When the number of free pages in the system
 		reaches this number, only the kernel can
 		allocate more memory.
-freepages.low	If memory is too fragmented, the swapout
-		daemon is started, except when the number
-		of free pages is larger than freepages.low.
-freepages.high	The swapping daemon exits when memory is
-		sufficiently defragmented, when the number
-		of free pages reaches freepages.high or when
-		it has tried the maximum number of times. 
+freepages.low	If the number of free pages gets below this
+		point, the kernel starts swapping agressively.
+freepages.high	The kernel tries to keep up to this amount of
+		memory free; if memory comes below this point,
+		the kernel gently starts swapping in the hopes
+		that it never has to do real agressive swapping.
 
 ==============================================================
 
@@ -210,7 +203,8 @@
 
 This file does exactly the same as buffermem, only this
 file controls the struct page_cache, and thus controls
-the amount of memory allowed for memory mapping of files.
+the amount of memory allowed for memory mapping and generic
+caching of files.
 
 You don't want the minimum level to be too low, otherwise
 your system might thrash when memory is tight or fragmentation
@@ -218,6 +212,23 @@
 
 ==============================================================
 
+pagetable_cache:
+
+The kernel keeps a number of page tables in a per-processor
+cache (this helps a lot on SMP systems). The cache size for
+each processor will be between the low and the high value.
+
+On a low-memory, single CPU system you can safely set these
+values to 0 so you don't waste the memory. On SMP systems it
+is used so that the system can do fast pagetable allocations
+without having to aquire the kernel memory lock.
+
+For large systems, the settings are probably OK. For normal
+systems they won't hurt a bit. For small systems (<16MB ram)
+it might be advantageous to set both values to 0.
+
+==============================================================
+
 swapctl:
 
 This file contains no less than 8 variables.
@@ -274,14 +285,4 @@
 might want to either increase sc_bufferout_weight, or decrease
 the value of sc_pageout_weight.
 
-==============================================================
-
-swapout_interval:
-
-The single value in this file controls the amount of time
-between successive wakeups of kswapd when nr_free_pages is
-between free_pages_low and free_pages_high. The default value
-of HZ/4 is usually right, but when kswapd can't keep up with
-the number of allocations in your system, you might want to
-decrease this number. 
 
diff -u --recursive --new-file v2.1.128/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.128/linux/MAINTAINERS	Thu Nov 12 16:21:17 1998
+++ linux/MAINTAINERS	Mon Nov 16 10:32:58 1998
@@ -387,7 +387,7 @@
 LINUX FOR POWERPC (PREP)
 P:	Cort Dougan
 M:	cort@cs.nmt.edu
-W:	http://www.cs.nmt.edu/~linuxppc/
+W:	http://linuxppc.cs.nmt.edu/
 S:	Maintained
 
 LINUX FOR POWER MACINTOSH
diff -u --recursive --new-file v2.1.128/linux/Makefile linux/Makefile
--- v2.1.128/linux/Makefile	Thu Nov 12 16:21:17 1998
+++ linux/Makefile	Thu Nov 12 16:21:37 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 128
+SUBLEVEL = 129
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -u --recursive --new-file v2.1.128/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.128/linux/arch/i386/defconfig	Sun Nov  8 14:02:42 1998
+++ linux/arch/i386/defconfig	Mon Nov 16 22:50:28 1998
@@ -275,6 +275,7 @@
 CONFIG_LOCKD=y
 # CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
diff -u --recursive --new-file v2.1.128/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.128/linux/arch/i386/kernel/i386_ksyms.c	Tue Jul 28 14:21:07 1998
+++ linux/arch/i386/kernel/i386_ksyms.c	Fri Nov 13 10:29:44 1998
@@ -98,6 +98,9 @@
 EXPORT_SYMBOL(mca_set_adapter_procfn);
 EXPORT_SYMBOL(mca_isenabled);
 EXPORT_SYMBOL(mca_isadapter);
+EXPORT_SYMBOL(mca_mark_as_used);
+EXPORT_SYMBOL(mca_mark_as_unused);
+EXPORT_SYMBOL(mca_find_unused_adapter);
 #endif
 
 #ifdef CONFIG_VT
diff -u --recursive --new-file v2.1.128/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.128/linux/arch/i386/kernel/time.c	Thu Nov 12 16:21:18 1998
+++ linux/arch/i386/kernel/time.c	Sun Nov 15 11:14:36 1998
@@ -526,9 +526,9 @@
 	       /* Now let's take care of CTC channel 2 */
 	       "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/
 	       "outb %%al, $0x43\n\t" /* Write to CTC command port */
-	       "movb $0x0c, %%al\n\t"
+	       "movl %1, %%eax\n\t"
 	       "outb %%al, $0x42\n\t" /* LSB of count */
-	       "movb $0xe9, %%al\n\t"
+	       "shrl $8, %%eax\n\t"
 	       "outb %%al, $0x42\n\t" /* MSB of count */
 
                /* Read the TSC; counting has just started */
@@ -562,12 +562,12 @@
                 * do a real 64-by-64 divide before that time's up. */
                "movl %%eax, %%ecx\n\t"
                "xorl %%eax, %%eax\n\t"
-               "movl %1, %%edx\n\t"
+               "movl %2, %%edx\n\t"
                "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */
 	       /* Return eax for the use of fast_gettimeoffset */
                "movl %%eax, %0\n\t"
                : "=r" (retval)
-               : "r" (5 * 1000020/HZ)
+               : "r" (5 * LATCH), "r" (5 * 1000020/HZ)
                : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory");
        return retval;
 }
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.1.128/linux/arch/ppc/Makefile	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/Makefile	Sun Nov 15 10:51:41 1998
@@ -16,6 +16,8 @@
 
 ifeq ($(shell uname -m),ppc)
 CHECKS		= checks
+else
+CROSS_COMPILE	= ppc-linux-elf-
 endif
 
 ASFLAGS		=
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- v2.1.128/linux/arch/ppc/amiga/amiints.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/amiga/amiints.c	Sun Nov 15 10:51:41 1998
@@ -108,6 +108,11 @@
 	custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
+	/* Clear any inter-CPU interupt requests. Circumvents bug in
+           Blizzard IPL emulation HW (or so it appears). */
+	APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
+
+	/* Init IPL emulation. */
 	APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL);
 	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
 	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
@@ -304,12 +309,14 @@
 	}
 
 	if (irq >= IRQ_AMIGA_CIAB) {
+		cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB)));
 		cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
 		             (1 << (irq - IRQ_AMIGA_CIAB)));
 		return;
 	}
 
 	if (irq >= IRQ_AMIGA_CIAA) {
+		cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA)));
 		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
 		             (1 << (irq - IRQ_AMIGA_CIAA)));
 		return;
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- v2.1.128/linux/arch/ppc/amiga/config.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/amiga/config.c	Sun Nov 15 10:51:41 1998
@@ -434,10 +434,6 @@
    */
   if (AMIGAHW_PRESENT(MAGIC_REKICK))
 	  *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
-
-#ifdef CONFIG_ZORRO
-  zorro_init();
-#endif
 }
 
 static unsigned short jiffy_ticks;
@@ -739,33 +735,32 @@
     savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM);
     savekmsg->magic1 = SAVEKMSG_MAGIC1;
     savekmsg->magic2 = SAVEKMSG_MAGIC2;
-    savekmsg->magicptr = VTOP(savekmsg);
+    savekmsg->magicptr = virt_to_phys(savekmsg);
     savekmsg->size = 0;
 }
 
 static void amiga_serial_putc(char c)
 {
-	custom.serdat = (unsigned char)c | 0x100;
-
-#ifdef CONFIG_APUS
-	/* I'm sure this should not be necessary since the address is
-	   marked non-cachable and coherent. Still, without it the
-	   serial output is not usable. -jskov */
-	eieio ();
-#endif
-
-	while (!(custom.serdatr & 0x2000))
-		;
+    custom.serdat = (unsigned char)c | 0x100;
+    iobarrier ();
+    while (!(custom.serdatr & 0x2000))
+       ;
 }
 
 void amiga_serial_console_write(struct console *co, const char *s,
 				       unsigned int count)
 {
-    while (count--) {
-	if (*s == '\n')
-	    amiga_serial_putc('\r');
-	amiga_serial_putc(*s++);
-    }
+#if 0 /* def CONFIG_KGDB */
+	/* FIXME:APUS GDB doesn't seem to like O-packages before it is
+           properly connected with the target. */
+	__gdb_output_string (s, count);
+#else
+	while (count--) {
+		if (*s == '\n')
+			amiga_serial_putc('\r');
+		amiga_serial_putc(*s++);
+	}
+#endif
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/amiga/time.c linux/arch/ppc/amiga/time.c
--- v2.1.128/linux/arch/ppc/amiga/time.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/amiga/time.c	Sun Nov 15 10:51:41 1998
@@ -1,3 +1,4 @@
+#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -68,3 +69,24 @@
 }
 
 
+void apus_heartbeat (void)
+{
+#ifdef CONFIG_HEARTBEAT
+	static unsigned cnt = 0, period = 0, dist = 0;
+
+	if (cnt == 0 || cnt == dist)
+                mach_heartbeat( 1 );
+	else if (cnt == 7 || cnt == dist+7)
+                mach_heartbeat( 0 );
+
+	if (++cnt > period) {
+                cnt = 0;
+                /* The hyperbolic function below modifies the heartbeat period
+                 * length in dependency of the current (5min) load. It goes
+                 * through the points f(0)=126, f(1)=86, f(5)=51,
+                 * f(inf)->30. */
+                period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+                dist = period / 4;
+	}
+#endif
+}
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/apus_defconfig linux/arch/ppc/apus_defconfig
--- v2.1.128/linux/arch/ppc/apus_defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/apus_defconfig	Sun Nov 15 10:51:42 1998
@@ -8,11 +8,11 @@
 CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 # CONFIG_ALL_PPC is not set
-CONFIG_APUS=y
+# CONFIG_APUS is not set
 # CONFIG_MBX is not set
 CONFIG_MACH_SPECIFIC=y
 
@@ -20,42 +20,33 @@
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_MODULES is not set
-# CONFIG_PCI is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
-# CONFIG_PCI_OLD_PROC is not set
+CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
-# CONFIG_FB_COMPAT_XPMAC is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_KEYBOARD is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_MACMOUSE is not set
-# CONFIG_PROC_DEVICETREE is not set
+CONFIG_FB_COMPAT_XPMAC=y
+CONFIG_PMAC_PBOOK=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_MAC_SERIAL=y
+CONFIG_ADBMOUSE=y
+CONFIG_PROC_DEVICETREE=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
-CONFIG_FB_CONSOLE=y
-CONFIG_AMIGA=y
-CONFIG_ZORRO=y
-CONFIG_AMIGAMOUSE=y
-CONFIG_ABSTRACT_CONSOLE=y
-CONFIG_FB=y
-CONFIG_AMIGA_BUILTIN_SERIAL=y
-CONFIG_GVPIOEXT=y
-# CONFIG_GVPIOEXT_LP is not set
-# CONFIG_GVPIOEXT_PLIP is not set
-CONFIG_MULTIFACE_III_TTY=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_PROC_HARDWARE is not set
+# CONFIG_TOTALMP is not set
 
 #
 # Plug and Play support
@@ -66,7 +57,6 @@
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-CONFIG_AMIGA_FLOPPY=y
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -76,15 +66,17 @@
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_PCIDE is not set
-CONFIG_BLK_DEV_GAYLE=y
-# CONFIG_BLK_DEV_IDEDOUBLER is not set
-CONFIG_BLK_DEV_BUDDHA=y
 # CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_AMIGA_Z2RAM is not set
 
 #
 # Additional Block Devices
@@ -102,27 +94,30 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
+CONFIG_NET_ALIAS=y
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
 # CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
 #
 CONFIG_INET_RARP=y
-# CONFIG_IP_NOSR is not set
+CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 
@@ -130,7 +125,7 @@
 #  
 #
 # CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_ATALK=m
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -151,7 +146,7 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
+CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
@@ -160,7 +155,7 @@
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 # CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
 #
@@ -170,7 +165,10 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
+CONFIG_SCSI_AIC7XXX=y
+# CONFIG_OVERRIDE_CMDS is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -183,23 +181,23 @@
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_DEBUG is not set
-CONFIG_A3000_SCSI=y
-CONFIG_A2091_SCSI=y
-CONFIG_GVP11_SCSI=y
-CONFIG_FASTLANE_SCSI=y
-CONFIG_A4000T_SCSI=y
-CONFIG_A4091_SCSI=y
-CONFIG_BLZ603EPLUS_SCSI=y
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MAC53C94=y
 
 #
 # Network device support
@@ -208,12 +206,10 @@
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
 CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-CONFIG_ARIADNE=y
-CONFIG_A2065=y
-CONFIG_HYDRA=y
+CONFIG_MACE=y
+CONFIG_BMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -221,22 +217,40 @@
 # CONFIG_RTL8139 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_ES3210 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_DLCI is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
 CONFIG_PPP=y
 
 #
 # CCP compressors for PPP are only built as modules.
 #
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
 
 #
 # Amateur Radio support
@@ -257,50 +271,46 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_AMIGA=y
-CONFIG_FB_AMIGA_OCS=y
-CONFIG_FB_AMIGA_ECS=y
-CONFIG_FB_AMIGA_AGA=y
-CONFIG_FB_CYBER=y
-CONFIG_FB_VIRGE=y
-CONFIG_FB_RETINAZ3=y
-CONFIG_FB_CLGEN=y
-# CONFIG_FB_OF is not set
-# CONFIG_FB_VGA is not set
-CONFIG_FB_VIRTUAL=y
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_IMSTT=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_MFB=y
-CONFIG_FBCON_CFB2=y
-CONFIG_FBCON_CFB4=y
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
-CONFIG_FBCON_AFB=y
-CONFIG_FBCON_ILBM=y
-CONFIG_FBCON_MAC=y
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-# CONFIG_FBCON_FONTS is not set
-CONFIG_FONT_8x8=y
+CONFIG_FBCON_FONTS=y
+# CONFIG_FONT_8x8 is not set
 CONFIG_FONT_8x16=y
-CONFIG_FONT_PEARL_8x8=y
+CONFIG_FONT_SUN8x16=y
+CONFIG_FONT_SUN12x22=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
 # CONFIG_JOYSTICK is not set
 
 #
@@ -312,17 +322,17 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=y
+# CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_CODA_FS is not set
@@ -330,31 +340,24 @@
 # CONFIG_HPFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
-CONFIG_AFFS_FS=y
-# CONFIG_HFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
 # CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
-
-#
-# Partition Tables
-#
-CONFIG_AMIGA_PARTITION=y
-CONFIG_FOREIGN_PARTITIONS=y
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_ADFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_MAC_PARTITION=y
 CONFIG_NLS=y
 
 #
 # Native Language Support
 #
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -384,4 +387,11 @@
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+CONFIG_DMASOUND=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.1.128/linux/arch/ppc/boot/Makefile	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/boot/Makefile	Sun Nov 15 10:51:42 1998
@@ -24,15 +24,21 @@
 ZSZ = 0
 IOFF = 0
 ISZ = 0
+
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build prep stuff
+CONFIG_PREP = y
+endif
+
 ifeq ($(CONFIG_MBX),y)
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
 else
-#ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000
 endif
+
 GZIP_FLAGS = -v9
 
-OBJECTS := head.o misc.o ../coffboot/zlib.o # inflate.o unzip.o
+OBJECTS := head.o misc.o ../coffboot/zlib.o
 CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
@@ -46,10 +52,6 @@
 
 all:	zImage
 
-ifeq ($(CONFIG_ALL_PPC),y)
-CONFIG_PREP = y
-endif
-
 ifeq ($(CONFIG_PREP),y)
 zvmlinux.initrd: zvmlinux
 	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
@@ -93,14 +95,12 @@
 zImage: zvmlinux mkprep
 	./mkprep -pbp zvmlinux zImage
 else
-
 ifeq ($(CONFIG_MBX),y)
 zImage: zvmlinux
 	ln -sf zvmlinux zImage
 else
 zImage:
 endif
-
 endif
 
 ifeq ($(CONFIG_PREP),y)
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile
--- v2.1.128/linux/arch/ppc/chrpboot/Makefile	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/chrpboot/Makefile	Sun Nov 15 10:51:42 1998
@@ -23,6 +23,10 @@
 OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o
 LIBS = $(TOPDIR)/lib/lib.a
 
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build chrp stuff
+CONFIG_CHRP = y
+endif
 
 all:	$(TOPDIR)/zImage
 
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- v2.1.128/linux/arch/ppc/coffboot/Makefile	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/coffboot/Makefile	Sun Nov 15 10:51:42 1998
@@ -15,7 +15,6 @@
 CROSS_COMPILE  =ppc-linux-elf-
 endif
 
-
 HOSTCC	= gcc
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
@@ -31,6 +30,11 @@
 OBJS = crt0.o start.o main.o misc.o string.o zlib.o
 LIBS = $(TOPDIR)/lib/lib.a
 
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build pmac stuff
+CONFIG_PMAC = y
+endif
+
 ifeq ($(CONFIG_PMAC),y)
 hack-coff: hack-coff.c
 	$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
@@ -79,8 +83,6 @@
 vmlinux.coff.initrd: vmlinux.gz
 
 floppy: vmlinux.gz
-
-
 
 endif
 
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.1.128/linux/arch/ppc/common_defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/common_defconfig	Sun Nov 15 10:51:42 1998
@@ -21,7 +21,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
 CONFIG_PCI_OLD_PROC=y
@@ -34,16 +34,20 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
-# CONFIG_PMAC_PBOOK is not set
+CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_MACMOUSE is not set
+CONFIG_MAC_FLOPPY=y
+CONFIG_MAC_SERIAL=y
+CONFIG_ADBMOUSE=y
+CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+CONFIG_XMON=y
+# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
 
 #
 # Plug and Play support
@@ -53,7 +57,7 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
@@ -66,7 +70,7 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 CONFIG_BLK_DEV_SL82C105=y
 # CONFIG_IDE_CHIPSETS is not set
-CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -94,7 +98,7 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 CONFIG_SYN_COOKIES=y
-CONFIG_INET_RARP=y
+# CONFIG_INET_RARP is not set
 # CONFIG_IP_NOSR is not set
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
@@ -116,7 +120,7 @@
 #
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
@@ -146,11 +150,11 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
-# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
-CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
-CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
 CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
 # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
@@ -166,7 +170,7 @@
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_MAC53C94=m
 
 #
 # Network device support
@@ -176,17 +180,17 @@
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
+CONFIG_MACE=y
+CONFIG_BMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
-CONFIG_LANCE=y
+# CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+CONFIG_PCNET32=m
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -195,19 +199,26 @@
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
-# CONFIG_TLAN is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+CONFIG_PPP=y
+CONFIG_SLIP=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
 
 #
 # Amateur Radio support
@@ -225,59 +236,27 @@
 # CONFIG_CD_NO_IDESCSI is not set
 
 #
-# Filesystems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_DEVPTS_FS is not set
-CONFIG_MAC_PARTITION=y
-# CONFIG_NLS is not set
-
-#
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
-CONFIG_FB_OF=y
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_CT65550 is not set
-CONFIG_FB_VGA=y
+# CONFIG_FB_OF is not set
+# CONFIG_FB_MATROX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_MOUSE=y
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
@@ -285,14 +264,12 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
-# CONFIG_MISC_RADIO is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -300,6 +277,104 @@
 # CONFIG_FTAPE is not set
 
 #
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+CONFIG_DMASOUND=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.128/linux/arch/ppc/config.in	Fri Oct  9 13:27:06 1998
+++ linux/arch/ppc/config.in	Sun Nov 15 10:51:42 1998
@@ -1,19 +1,9 @@
-# $Id: config.in,v 1.72 1998/10/01 14:09:40 cort Exp $
+# $Id: config.in,v 1.80 1998/11/11 03:54:56 paulus Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
-
-
-mainmenu_option next_comment
-comment 'Cross development support'
-  bool 'Build using cross development tools' CONFIG_CROSSCOMPILE 
-if [ "$CONFIG_CROSSCOMPILE" = "y" ]; then
-  string '  Prefix for cross devel tools' CROSS_COMPILE "ppc-linux-elf-"
-fi
-endmenu
-
 mainmenu_option next_comment
 comment 'Platform support'
 define_bool CONFIG_PPC y
@@ -28,16 +18,16 @@
 	 PowerMac/PReP/CHRP	CONFIG_ALL_PPC \
   	 APUS           CONFIG_APUS \
 	 MBX		CONFIG_MBX" PowerMac
+
+if [ "$CONFIG_ALL_PPC" != "y" ];then
+  define_bool CONFIG_MACH_SPECIFIC y
+fi
 endmenu
 
 if [ "$CONFIG_MBX" = "y" ];then
   define_bool CONFIG_SERIAL_CONSOLE y
 fi
 
-if [ "$CONFIG_ALL_PPC" != "y" ]; then
-  define_bool CONFIG_MACH_SPECIFIC y
-fi
-
 mainmenu_option next_comment
 comment 'General setup'
 
@@ -79,23 +69,23 @@
   fi
 fi
 
+bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
 if [ "$CONFIG_FB" = "y" ]; then
   bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
 fi
-if [ "$CONFIG_FB" != "y" ]; then
-  bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
-fi
 
 bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK
 bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
 bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
 bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
 bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
+bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC
 bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
 bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
+bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
 
 if [ "$CONFIG_APUS" = "y" ]; then
   define_bool CONFIG_FB_CONSOLE y
@@ -105,6 +95,7 @@
   define_bool CONFIG_ABSTRACT_CONSOLE y
   define_bool CONFIG_FB y
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
   tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
@@ -113,7 +104,8 @@
        "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
   fi
-bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+  bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
+  bool '/proc/hardware support' CONFIG_PROC_HARDWARE
 fi
 
 endmenu
@@ -128,9 +120,7 @@
 
 mainmenu_option next_comment
 comment 'SCSI support'
-
 tristate 'SCSI support' CONFIG_SCSI
-
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
@@ -173,22 +163,15 @@
 endmenu
 
 source drivers/char/Config.in
-
 source fs/Config.in
-
 source fs/nls/Config.in
 
 mainmenu_option next_comment
 comment 'Sound'
-
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
-  if [ "$CONFIG_APUS" = "y" -o "$CONFIG_PMAC" = "y" ]; then
-     tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND
-  fi
-  if [ "$CONFIG_PREP" = "y" -o "$CONFIG_CHRP" = "y" ]; then
-     source drivers/sound/Config.in
-  fi
+  tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND
+  source drivers/sound/Config.in
 fi
 
 endmenu
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.1.128/linux/arch/ppc/defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/defconfig	Sun Nov 15 10:51:43 1998
@@ -35,16 +35,20 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
-CONFIG_MACMOUSE=y
+CONFIG_ADBMOUSE=y
+CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+# CONFIG_TOTALMP is not set
+CONFIG_BOOTX_TEXT=y
 
 #
 # Plug and Play support
@@ -70,6 +74,10 @@
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
@@ -159,7 +167,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC7XXX=y
 # CONFIG_OVERRIDE_CMDS is not set
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
@@ -216,23 +224,26 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-CONFIG_DE4X5=m
+CONFIG_DE4X5=y
 CONFIG_DEC_ELCP=m
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_DLCI is not set
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
-CONFIG_PPP=m
+CONFIG_PPP=y
 
 #
 # CCP compressors for PPP are only built as modules.
@@ -241,6 +252,7 @@
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
 
 #
 # Amateur Radio support
@@ -264,11 +276,12 @@
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
 CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA is not set
+# CONFIG_FB_MATROX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -293,8 +306,9 @@
 CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_MOUSE is not set
-# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
@@ -322,6 +336,7 @@
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_CODA_FS is not set
@@ -330,12 +345,16 @@
 # CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=m
+CONFIG_HFS_FS=y
 # CONFIG_ROMFS_FS is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
-# CONFIG_ADFS_FS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
 CONFIG_DEVPTS_FS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
 CONFIG_MAC_PARTITION=y
 CONFIG_NLS=y
 
@@ -374,3 +393,9 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.1.128/linux/arch/ppc/kernel/Makefile	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/Makefile	Sun Nov 15 10:51:43 1998
@@ -15,7 +15,7 @@
 
 
 O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \
-	  bitops.o ptrace.o align.o ppc_htab.o
+	  bitops.o ptrace.o align.o ppc_htab.o feature.o
 
 ifdef CONFIG_PCI
 O_OBJS += pci.o
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.1.128/linux/arch/ppc/kernel/apus_setup.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/apus_setup.c	Sun Nov 15 10:51:43 1998
@@ -61,6 +61,8 @@
 extern void amiga_floppy_setup(char *, int *);
 extern void config_amiga(void);
 
+static int __60nsram = 0;
+
 /*********************************************************** SETUP */
 /* From arch/m68k/kernel/setup.c. */
 __initfunc(void apus_setup_arch(unsigned long * memory_start_p,
@@ -76,10 +78,17 @@
 	for( p = cmd_line; p && *p; ) {
 	    i = 0;
 	    if (!strncmp( p, "debug=", 6 )) {
-		strncpy( debug_device, p+6, sizeof(debug_device)-1 );
-		debug_device[sizeof(debug_device)-1] = 0;
-		if ((q = strchr( debug_device, ' ' ))) *q = 0;
-		i = 1;
+		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
+		    debug_device[sizeof(debug_device)-1] = 0;
+		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
+		    i = 1;
+	    } else if (!strncmp( p, "60nsram", 7 )) {
+		    APUS_WRITE (APUS_REG_WAITSTATE, 
+				REGWAITSTATE_SETRESET
+				|REGWAITSTATE_PPCR
+				|REGWAITSTATE_PPCW);
+		    __60nsram = 1;
+		    i = 1;
 	    }
 
 	    if (i) {
@@ -96,67 +105,85 @@
 	config_amiga();
 }
 
+
+void get_current_tb(unsigned long long *time)
+{
+	__asm __volatile ("1:mftbu 4      \n\t"
+			  "  mftb  5      \n\t"
+			  "  mftbu 6      \n\t"
+			  "  cmpw  4,6    \n\t"
+			  "  bne   1b     \n\t"
+			  "  stw   4,0(%0)\n\t"
+			  "  stw   5,4(%0)\n\t"
+			  : 
+			  : "r" (time)
+			  : "r4", "r5", "r6");
+}
+
+
 void apus_calibrate_decr(void)
 {
 	int freq, divisor;
-	unsigned char c = *(unsigned char*)ZTWO_VADDR(0xf00011);
-	printk ("CPU speed ID ('%c') ", c);
 
-	switch (c)
+	/* This algorithm for determining the bus speed was
+           contributed by Ralph Schmidt. */
+	unsigned long long start, stop;
+	int bus_speed;
+
 	{
-	case 'A':
-	case 'B':
-		if (amiga_model == AMI_1200 || amiga_model == AMI_2000){
-			freq = 1;
-		} else {
-			freq = 0;
-		}
-		break;
-	case 'C':
-		if (amiga_model == AMI_1200 || amiga_model == AMI_2000){
-			freq = 0;
-		} else {
-			freq = 1;
+		unsigned long loop = amiga_eclock / 10;
+
+		get_current_tb (&start);
+		while (loop--) {
+			unsigned char tmp;
+
+			tmp = ciaa.pra;
 		}
-		break;
-	case 'D':
-		freq = 1;
-		break;
-	default:
-		freq = 0;
-		printk (" *Unknown* ");
-		break;
+		get_current_tb (&stop);
 	}
 
+	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
+	if (AMI_1200 == amiga_model)
+		bus_speed /= 2;
+
+	if ((bus_speed >= 47) && (bus_speed < 53)) {
+		bus_speed = 50;
+		freq = 12500000;
+	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
+		bus_speed = 60;
+		freq = 15000000;
+	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
+		bus_speed = 66;
+		freq = 16500000;
+	} else {
+		printk ("APUS: Unable to determine bus speed (%d). "
+			"Defaulting to 50MHz", bus_speed);
+		bus_speed = 50;
+		freq = 12500000;
+	}
+
+	/* Ease diagnostics... */
 	{
-		int speed;
-		switch (freq)
-		{
-		case 0:
-			freq = 15000000;
-			speed = 60;
-			break;
-
-		case 1:
-			freq = 16500000;
-			speed =66;
-			break;
-		}
-	
-		/* Use status of left mouse button to select
-		   RAM speed. */
-		if (!(ciaa.pra & 0x40))
-		{
-			APUS_WRITE (APUS_REG_WAITSTATE, 
-				    REGWAITSTATE_SETRESET
-				    |REGWAITSTATE_PPCR
-				    |REGWAITSTATE_PPCW);
-			printk (" [RAM R/W waitstate removed. "
-				"(expecting 60ns RAM).] ");
+		extern int __map_without_bats;
+
+		printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n",
+			(__map_without_bats) ? 0 : 1,
+			bus_speed,
+			(__60nsram) ? 60 : 70);
+
+		/* print a bit more if asked politely... */
+		if (!(ciaa.pra & 0x40)){
+			extern unsigned int bat_addrs[4][3];
+			int b;
+			for (b = 0; b < 4; ++b) {
+				printk ("APUS: BAT%d ", b);
+				printk ("%08x-%08x -> %08x\n",
+					bat_addrs[b][0],
+					bat_addrs[b][1],
+					bat_addrs[b][2]);
+			}
 		}
 
-		
-		printk ("PowerUp Bus Speed: %dMHz\n", speed);
 	}
 
 	freq *= 60;	/* try to make freq/1e6 an integer */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.1.128/linux/arch/ppc/kernel/chrp_setup.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/chrp_setup.c	Sun Nov 15 10:51:43 1998
@@ -39,6 +39,7 @@
 #include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
+#include <asm/pci-bridge.h>
 
 extern void hydra_init(void);
 extern void w83c553f_init(void);
@@ -191,7 +192,15 @@
 	
 	aux_device_present = 0xaa;
 
-	ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* this is fine for chrp */
+	initrd_below_start_ok = 1;
+	
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
 	
 	printk("Boot arguments: %s\n", cmd_line);
 	
@@ -205,7 +214,6 @@
 	/* PCI bridge config space access area -
 	 * appears to be not in devtree on longtrail. */
 	ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
-
 	/*
 	 *  Temporary fixes for PCI devices.
 	 *  -- Geert
@@ -217,10 +225,13 @@
 	 *  Fix the Super I/O configuration
 	 */
 	sio_init();
-
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
+	/* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */
+	if ( !strncmp("MOT", get_property(find_path_device("/"),
+					  "model", NULL),3) )
+		*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.1.128/linux/arch/ppc/kernel/feature.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/feature.c	Sun Nov 15 10:51:43 1998
@@ -0,0 +1,249 @@
+/*
+ *  arch/ppc/kernel/feature.c
+ *
+ *  Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/errno.h>
+#include <asm/ohare.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/feature.h>
+
+#define MAX_FEATURE_REGS		2
+#undef DEBUG_FEATURE
+
+static u32 feature_bits_pbook[] = {
+	0,			/* FEATURE_null */
+	OH_SCC_RESET,		/* FEATURE_Serial_reset */
+	OH_SCC_ENABLE,		/* FEATURE_Serial_enable */
+	OH_SCCA_IO,		/* FEATURE_Serial_IO_A */
+	OH_SCCB_IO,		/* FEATURE_Serial_IO_B */
+	OH_FLOPPY_ENABLE,	/* FEATURE_SWIM3_enable */
+	OH_MESH_ENABLE,		/* FEATURE_MESH_enable */
+	OH_IDE_ENABLE,		/* FEATURE_IDE_enable */
+	OH_VIA_ENABLE,		/* FEATURE_VIA_enable */
+	OH_IDECD_POWER,		/* FEATURE_CD_power */
+	OH_BAY_RESET,		/* FEATURE_Mediabay_reset */
+	OH_BAY_ENABLE,		/* FEATURE_Mediabay_enable */
+	OH_BAY_PCI_ENABLE,	/* FEATURE_Mediabay_PCI_enable */
+	OH_BAY_IDE_ENABLE,	/* FEATURE_Mediabay_IDE_enable */
+	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
+	0,			/* FEATURE_BMac_reset */
+	0,			/* FEATURE_BMac_IO_enable */
+	0,			/* FEATURE_Modem_PowerOn -> guess...*/
+	0			/* FEATURE_Modem_Reset -> guess...*/
+};
+
+/* assume these are the same as the ohare until proven otherwise */
+static u32 feature_bits_heathrow[] = {
+	0,			/* FEATURE_null */
+	OH_SCC_RESET,		/* FEATURE_Serial_reset */
+	OH_SCC_ENABLE,		/* FEATURE_Serial_enable */
+	OH_SCCA_IO,		/* FEATURE_Serial_IO_A */
+	OH_SCCB_IO,		/* FEATURE_Serial_IO_B */
+	OH_FLOPPY_ENABLE,	/* FEATURE_SWIM3_enable */
+	OH_MESH_ENABLE,		/* FEATURE_MESH_enable */
+	OH_IDE_ENABLE,		/* FEATURE_IDE_enable */
+	OH_VIA_ENABLE,		/* FEATURE_VIA_enable */
+	OH_IDECD_POWER,		/* FEATURE_CD_power */
+	OH_BAY_RESET,		/* FEATURE_Mediabay_reset */
+	OH_BAY_ENABLE,		/* FEATURE_Mediabay_enable */
+	OH_BAY_PCI_ENABLE,	/* FEATURE_Mediabay_PCI_enable */
+	OH_BAY_IDE_ENABLE,	/* FEATURE_Mediabay_IDE_enable */
+	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
+	0x80000000,		/* FEATURE_BMac_reset */
+	0x60000000,		/* FEATURE_BMac_IO_enable */
+	0x02000000,		/* FEATURE_Modem_PowerOn -> guess...*/
+	0x07000000		/* FEATURE_Modem_Reset -> guess...*/
+};
+
+/* definition of a feature controller object */
+struct feature_controller
+{
+	u32*			bits;
+	volatile u32*		reg;
+	struct device_node*	device;
+};
+
+/* static functions */
+static void
+feature_add_controller(struct device_node *controller_device, u32* bits);
+
+static int
+feature_lookup_controller(struct device_node *device);
+
+/* static varialbles */
+static struct feature_controller	controllers[MAX_FEATURE_REGS];
+static int				controller_count = 0;
+
+
+void
+feature_init(void)
+{
+	struct device_node *np;
+
+	np = find_devices("mac-io");
+	while (np != NULL)
+	{
+		feature_add_controller(np, feature_bits_heathrow);
+		np = np->next;
+	}
+	if (controller_count == 0)
+	{
+		np = find_devices("ohare");
+		if (np)
+		{
+			if (find_devices("via-pmu") != NULL)
+				feature_add_controller(np, feature_bits_pbook);
+			else
+				/* else not sure; maybe this is a Starmax? */
+				feature_add_controller(np, NULL);
+		}
+	}
+
+	if (controller_count)
+		printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+}
+
+static void
+feature_add_controller(struct device_node *controller_device, u32* bits)
+{
+	struct feature_controller*	controller;
+	
+	if (controller_count >= MAX_FEATURE_REGS)
+	{
+		printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
+			controller_device->full_name, MAX_FEATURE_REGS);
+		return;
+	}
+	controller = &controllers[controller_count];
+
+	controller->bits	= bits;
+	controller->device	= controller_device;
+	if (controller_device->n_addrs == 0) {
+		printk(KERN_ERR "No addresses for %s\n",
+			controller_device->full_name);
+		return;
+	}
+
+	controller->reg		= (volatile u32 *)ioremap(
+		controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+
+	if (bits == NULL) {
+		printk(KERN_INFO "Twiddling the magic ohare bits\n");
+		out_le32(controller->reg, STARMAX_FEATURES);
+		return;
+	}
+
+	controller_count++;
+}
+
+static int
+feature_lookup_controller(struct device_node *device)
+{
+	int	i;
+	
+	if (device == NULL)
+		return -EINVAL;
+		
+	while(device)
+	{
+		for (i=0; i<controller_count; i++)
+			if (device == controllers[i].device)
+				return i;
+		device = device->parent;
+	}
+
+#ifdef DEBUG_FEATURE
+	printk("feature: <%s> not found on any controller\n",
+		device->name);
+#endif
+	
+	return -ENODEV;
+}
+
+int
+feature_set(struct device_node* device, enum system_feature f)
+{
+	int		controller;
+	unsigned long	flags;
+
+	if (f >= FEATURE_last)
+		return -EINVAL;	
+
+	controller = feature_lookup_controller(device);
+	if (controller < 0)
+		return controller;
+	
+#ifdef DEBUG_FEATURE
+	printk("feature: <%s> setting feature %d in controller @0x%x\n",
+		device->name, (int)f, (unsigned int)controllers[controller].reg);
+#endif
+
+	save_flags(flags);
+	cli();
+	st_le32( controllers[controller].reg,
+		 ld_le32(controllers[controller].reg) |
+		 controllers[controller].bits[f]);
+	restore_flags(flags);
+	udelay(10);
+	
+	return 0;
+}
+
+int
+feature_clear(struct device_node* device, enum system_feature f)
+{
+	int		controller;
+	unsigned long	flags;
+
+	if (f >= FEATURE_last)
+		return -EINVAL;	
+
+	controller = feature_lookup_controller(device);
+	if (controller < 0)
+		return controller;
+	
+#ifdef DEBUG_FEATURE
+	printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+		device->name, (int)f, (unsigned int)controllers[controller].reg);
+#endif
+
+	save_flags(flags);
+	cli();
+	st_le32( controllers[controller].reg,
+		 ld_le32(controllers[controller].reg) &
+		 ~(controllers[controller].bits[f]));
+	restore_flags(flags);
+	udelay(10);
+	
+	return 0;
+}
+
+int
+feature_test(struct device_node* device, enum system_feature f)
+{
+	int		controller;
+
+	if (f >= FEATURE_last)
+		return -EINVAL;	
+
+	controller = feature_lookup_controller(device);
+	if (controller < 0)
+		return controller;
+	
+	return (ld_le32(controllers[controller].reg) &
+		controllers[controller].bits[f]) != 0;
+}
+
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.1.128/linux/arch/ppc/kernel/head.S	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/head.S	Sun Nov 15 10:51:43 1998
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.107 1998/09/25 19:48:52 paulus Exp $
+ *  $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -210,7 +210,8 @@
 	mr	r27,r7
 #ifndef CONFIG_8xx
 	bl	prom_init
-
+	.globl	__secondary_start
+__secondary_start:
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
@@ -1395,15 +1396,13 @@
 next_slot:
 	.long	0
 
-/*
- * FPU stuff for the 6xx/7xx follows
- *  -- Cort
- */
 load_up_fpu:
 /*
  * Disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
+ * On SMP we know the fpu is free, since we give it up every
+ * switch.  -- Cort
  */
 #ifndef CONFIG_APUS
 	lis	r6,-KERNELBASE@h
@@ -1411,28 +1410,23 @@
 	lis	r6,CYBERBASEp@h
 	lwz	r6,0(r6)
 #endif
+
 	addis	r3,r6,last_task_used_math@ha
 	lwz	r4,last_task_used_math@l(r3)
 	mfmsr	r5
 	ori	r5,r5,MSR_FP
 	SYNC
 	mtmsr	r5			/* enable use of fpu now */
-#ifndef __SMP__
-	SYNC
-	cmpi	0,r4,0
-	beq	1f
-#else
 /*
  * All the saving of last_task_used_math is handled
  * by a switch_to() call to smp_giveup_fpu() in SMP so 
  * last_task_used_math is not used.
- *
- * We should never be here on SMP anyway, since the fpu should
- * always be on.
  * -- Cort
  */
-	b	1f
-#endif	
+#ifndef __SMP__
+	SYNC
+	cmpi	0,r4,0
+	beq	1f
 	add	r4,r4,r6
 	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
 	SAVE_32FPRS(0, r4)
@@ -1444,19 +1438,17 @@
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
 	andc	r4,r4,r20		/* disable FP for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-
+#endif /* __SMP__ */
 1:	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1	/* enable use of FP after return */
 	mfspr	r5,SPRG3		/* current task's TSS (phys) */
 	lfd	fr0,TSS_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
-/* 
- * on SMP we don't really use last_task_used_math but set it
- * here anyway to avoid the ifdef's -- Cort
- */
 	subi	r4,r5,TSS
 	sub	r4,r4,r6
+#ifndef __SMP__
 	stw	r4,last_task_used_math@l(r3)
+#endif /* __SMP__ */
 	/* restore registers and return */
 	lwz	r3,_CCR(r21)
 	lwz	r4,_LINK(r21)
@@ -1516,8 +1508,10 @@
 	cmpi	0,r4,0
 	beqlr-				/* if no previous owner, done */
 	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
+#ifndef __SMP__
 	li	r5,0
 	stw	r5,last_task_used_math@l(r3)
+#endif /* __SMP__ */
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,TSS_FPSCR-4(r4)
@@ -1628,14 +1622,27 @@
 5:	mtspr	HID0,r11		/* superscalar exec & br history tbl */
 4:
 #endif /* CONFIG_8xx */
+#ifdef __SMP__
+	/* if we're the second cpu stack and r2 are different
+	* and we want to not clear the bss -- Cort */
+	lis	r5,first_cpu_booted@h
+	ori	r5,r5,first_cpu_booted@l
+	lwz	r5,0(r5)
+	cmpi	0,r5,0
+	beq	99f
+
+	/* get current */
+	lis	r2,current_set@h
+	ori	r2,r2,current_set@l
+	addi	r2,r2,4
+	lwz	r2,0(r2)
+	
+	b	10f
+99:	
+#endif /* __SMP__ */
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
-	/* stack */
-	addi	r1,r2,TASK_UNION_SIZE
-	li	r0,0
-	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
-
 	/* Clear out the BSS */
 	lis	r11,_end@ha
 	addi	r11,r11,_end@l
@@ -1651,6 +1658,15 @@
 3:	stwu	r0,4(r8)
 	bdnz	3b
 2:
+#ifdef __SMP__	
+10:
+#endif /* __SMP__ */
+	
+	/* stack */
+	addi	r1,r2,TASK_UNION_SIZE
+	li	r0,0
+	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
+	
 /*
  * Decide what sort of machine this is and initialize the MMU.
  */
@@ -1999,6 +2015,8 @@
 	beq+	1f
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	do_IRQ
+	.globl	lost_irq_ret
+lost_irq_ret:
 	b	3b
 1:	lis	r4,bh_mask@ha
 	lwz	r4,bh_mask@l(r4)
@@ -2007,6 +2025,8 @@
 	and.	r4,r4,r5
 	beq+	2f
 	bl	do_bottom_half
+	.globl	do_bottom_half_ret
+do_bottom_half_ret:
 	SYNC
 	mtmsr	r30		/* disable interrupts again */
 	SYNC
@@ -2024,6 +2044,8 @@
 	li	r3,0
 	addi	r4,r1,STACK_FRAME_OVERHEAD
 	bl	do_signal
+	.globl	do_signal_ret
+do_signal_ret:
 	b	0b
 8:	addi	r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD	/* size of frame */
 	stw	r4,TSS+KSP(r2)	/* save kernel stack pointer */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.1.128/linux/arch/ppc/kernel/idle.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/idle.c	Sun Nov 15 10:51:43 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.50 1998/08/18 16:19:25 cort Exp $
+ * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -11,8 +11,6 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define __KERNEL_SYSCALLS__
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -32,9 +30,6 @@
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/cache.h>
-#ifdef CONFIG_PMAC
-#include <asm/mediabay.h>
-#endif
 
 void zero_paged(void);
 void power_save(void);
@@ -60,15 +55,7 @@
 
 		if ( !current->need_resched && zero_paged_on ) zero_paged();
 		if ( !current->need_resched && htab_reclaim_on ) htab_reclaim();
-
-		/*
-		 * Only processor 1 may sleep now since processor 2 would
-		 * never wake up.  Need to add timer code for processor 2
-		 * then it can sleep. -- Cort
-		 */
-#ifndef __SMP__
 		if ( !current->need_resched ) power_save();
-#endif /* __SMP__ */
 		run_task_queue(&tq_scheduler);
 		schedule();
 	}
@@ -93,14 +80,8 @@
  */
 asmlinkage int sys_idle(void)
 {
-	extern int media_bay_task(void *);
 	if(current->pid != 0)
 		return -EPERM;
-
-#ifdef CONFIG_PMAC
-	if (media_bay_present)
-		kernel_thread(media_bay_task, NULL, 0);
-#endif
 
 	idled(NULL);
 	return 0; /* should never execute this but it makes gcc happy -- Cort */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.1.128/linux/arch/ppc/kernel/irq.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/irq.c	Sun Nov 15 10:51:43 1998
@@ -9,7 +9,7 @@
  *  Adapted for Power Macintosh by Paul Mackerras
  *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
+ *  
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
  * instead of just grabbing them. Thus setups with different IRQ numbers
@@ -63,8 +63,9 @@
 extern void amiga_disable_irq(unsigned int irq);
 extern void amiga_enable_irq(unsigned int irq);
 static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-static volatile unsigned char *gg2_int_ack_special;
+static volatile unsigned char *chrp_int_ack_special;
 extern volatile unsigned long ipi_count;
+static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
 
 #ifdef CONFIG_APUS
 /* Rename a few functions. Requires the CONFIG_APUS protection. */
@@ -88,6 +89,7 @@
 
 #define VEC_SPUR    (24)
 #undef SHOW_IRQ
+#undef SHOW_GATWICK_IRQS
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 #define cached_21	(((char *)(cached_irq_mask))[3])
 #define cached_A1	(((char *)(cached_irq_mask))[2])
@@ -96,6 +98,7 @@
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
 int max_irqs;
+int max_real_irqs;
 static struct irqaction *irq_action[NR_IRQS];
 static int spurious_interrupts = 0;
 static unsigned int cached_irq_mask[NR_MASK_WORDS];
@@ -111,11 +114,32 @@
 };
 
 /* XXX these addresses should be obtained from the device tree */
-volatile struct pmac_irq_hw *pmac_irq_hw[2] = {
+volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
 	(struct pmac_irq_hw *) 0xf3000020,
 	(struct pmac_irq_hw *) 0xf3000010,
+	(struct pmac_irq_hw *) 0xf4000020,
+	(struct pmac_irq_hw *) 0xf4000010,
 };
 
+/* This is the interrupt used on the main controller for the secondary
+   controller. Happens on PowerBooks G3 Series (a second mac-io)
+   -- BenH
+ */
+static int second_irq = -999;
+
+/* Returns the number of 0's to the left of the most significant 1 bit */
+static inline int cntlzw(int bits)
+{
+	int lz;
+
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
+	return lz;
+}
+
+static inline void sync(void)
+{
+	asm volatile ("sync");
+}
 
 /* nasty hack for shared irq's since we need to do kmalloc calls but
  * can't very very early in the boot when we need to do a request irq.
@@ -173,12 +197,12 @@
 	/*	spin_unlock(&irq_controller_lock);*/
 }
 
-void pmac_mask_and_ack_irq(int irq_nr)
+void __pmac pmac_mask_and_ack_irq(int irq_nr)
 {
 	unsigned long bit = 1UL << (irq_nr & 0x1f);
 	int i = irq_nr >> 5;
 
-	if (irq_nr >= max_irqs)
+	if ((unsigned)irq_nr >= max_irqs)
 		return;
 	/*spin_lock(&irq_controller_lock);*/
 
@@ -188,13 +212,15 @@
 	out_le32(&pmac_irq_hw[i]->ack, bit);
 	out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
 	out_le32(&pmac_irq_hw[i]->ack, bit);
+	/* make sure ack gets to controller before we enable interrupts */
+	sync();
 
 	/*spin_unlock(&irq_controller_lock);*/
 	/*if ( irq_controller_lock.lock )
 	  panic("irq controller lock still held in mask and ack\n");*/
 }
 
-void chrp_mask_and_ack_irq(int irq_nr)
+void __openfirmware chrp_mask_and_ack_irq(int irq_nr)
 {
 	/* spinlocks are done by i8259_mask_and_ack() - Cort */
 	if (is_8259_irq(irq_nr))
@@ -211,12 +237,12 @@
 	}
 }
 
-static void pmac_set_irq_mask(int irq_nr)
+static void __pmac pmac_set_irq_mask(int irq_nr)
 {
 	unsigned long bit = 1UL << (irq_nr & 0x1f);
 	int i = irq_nr >> 5;
 
-	if (irq_nr >= max_irqs)
+	if ((unsigned)irq_nr >= max_irqs)
 		return;
 
 	/* enable unmasked interrupts */
@@ -251,19 +277,20 @@
 	i8259_set_irq_mask(irq_nr);
 }
 
-static void pmac_mask_irq(unsigned int irq_nr)
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
 {
 	clear_bit(irq_nr, cached_irq_mask);
 	pmac_set_irq_mask(irq_nr);
+	sync();
 }
 
-static void pmac_unmask_irq(unsigned int irq_nr)
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
 {
 	set_bit(irq_nr, cached_irq_mask);
 	pmac_set_irq_mask(irq_nr);
 }
 
-static void chrp_mask_irq(unsigned int irq_nr)
+static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
 {
 	if (is_8259_irq(irq_nr))
 		i8259_mask_irq(irq_nr);
@@ -271,7 +298,7 @@
 		openpic_disable_irq(irq_to_openpic(irq_nr));
 }
 
-static void chrp_unmask_irq(unsigned int irq_nr)
+static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
 {
 	if (is_8259_irq(irq_nr))
 		i8259_unmask_irq(irq_nr);
@@ -325,7 +352,7 @@
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
 		action = irq_action[i];
-		if (!action || !action->handler)
+		if ((!action || !action->handler) && (i != second_irq))
 			continue;
 		len += sprintf(buf+len, "%3d: ", i);		
 #ifdef __SMP__
@@ -341,7 +368,10 @@
 			len += sprintf(buf+len, "    82c59 ");
 			break;
 		case _MACH_Pmac:
-			len += sprintf(buf+len, " PMAC-PIC ");
+			if (i < 64)
+				len += sprintf(buf+len, " PMAC-PIC ");
+			else
+				len += sprintf(buf+len, "  GATWICK ");
 			break;
 		case _MACH_chrp:
 			if ( is_8259_irq(i) )
@@ -354,23 +384,26 @@
 			break;
 		}
 
-		len += sprintf(buf+len, "   %s",action->name);
-		for (action=action->next; action; action = action->next) {
-			len += sprintf(buf+len, ", %s", action->name);
-		}
-		len += sprintf(buf+len, "\n");
+		if (i != second_irq) {
+			len += sprintf(buf+len, "    %s",action->name);
+			for (action=action->next; action; action = action->next) {
+				len += sprintf(buf+len, ", %s", action->name);
+			}
+			len += sprintf(buf+len, "\n");
+		} else
+			len += sprintf(buf+len, "    Gatwick secondary IRQ controller\n");
 	}
 #ifdef __SMP__
 	/* should this be per processor send/receive? */
-	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
+	len += sprintf(buf+len, "IPI: %10lu", ipi_count);
 	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
 		len += sprintf(buf+len,"          ");
-	len += sprintf(buf+len, "    interprocessor messages received\n");
+	len += sprintf(buf+len, "     interprocessor messages received\n");
 #endif		
 	len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
 	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
 		len += sprintf(buf+len,"          ");
-	len += sprintf(buf+len, "    spurious or short\n");
+	len += sprintf(buf+len, "     spurious or short\n");
 	return len;
 }
 
@@ -604,7 +637,6 @@
 
 #endif /* __SMP__ */
 
-
 asmlinkage void do_IRQ(struct pt_regs *regs)
 {
 	int irq;
@@ -627,9 +659,6 @@
 		if (!atomic_read(&n_lost_interrupts))
 		{
 			extern void smp_message_recv(void);
-			goto out;
-			
-			ipi_count++;
 			smp_message_recv();
 			goto out;
 		}
@@ -642,20 +671,48 @@
 	switch ( _machine )
 	{
 	case _MACH_Pmac:
-		for (irq = max_irqs - 1; irq > 0; irq -= 32) {
-			int i = irq >> 5, lz;
+		for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+			int i = irq >> 5;
 			bits = ld_le32(&pmac_irq_hw[i]->flag)
 				| lost_interrupts[i];
 			if (bits == 0)
 				continue;
-			/* lz = number of 0 bits to left of most sig. 1 */
-			asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
-			irq -= lz;
+			irq -= cntlzw(bits);
 			break;
 		}
+
+		/* Here, we handle interrupts coming from Gatwick,
+		 * normal interrupt code will take care of acking and
+		 * masking the irq on Gatwick itself but we ack&mask
+		 * the Gatwick main interrupt on Heathrow now. It's
+		 * unmasked later, after interrupt handling. -- BenH 
+		 */
+		if (irq == second_irq) {
+			mask_and_ack_irq(second_irq);
+			for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+				int i = irq >> 5;
+				bits = ld_le32(&pmac_irq_hw[i]->flag)
+					| lost_interrupts[i];
+				if (bits == 0)
+					continue;
+				irq -= cntlzw(bits);
+				break;
+			}
+			/* If not found, on exit, irq is 63 (128-1-32-32).
+			 * We set it to -1 and revalidate second controller
+			 */
+			if (irq < max_real_irqs) {
+				irq = -1;
+				unmask_irq(second_irq);
+			}
+#ifdef SHOW_GATWICK_IRQS
+			printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits);
+#endif
+		}
+
 		break;
 	case _MACH_chrp:
-		irq = openpic_irq(0);		
+		irq = openpic_irq(0);
 		if (irq == IRQ_8259_CASCADE)
 		{
 			/*
@@ -663,7 +720,7 @@
 			 * 
 			 * This should go in the above mask/ack code soon. -- Cort
 			 */
-			irq = *gg2_int_ack_special;
+			irq = *chrp_int_ack_special;
 			/*
 			 * Acknowledge as soon as possible to allow i8259
 			 * interrupt nesting
@@ -740,11 +797,13 @@
 	}
 #endif	
 	}
-	
+
 	if (irq < 0) {
-		printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", regs->nip);
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		spurious_interrupts++;
 		goto out;
-	}
+	}					
 	
 #else /* CONFIG_8xx */
 	/* For MPC8xx, read the SIVEC register and shift the bits down
@@ -753,9 +812,7 @@
 	bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec;
 	irq = bits >> 26;
 #endif /* CONFIG_8xx */
-
 	mask_and_ack_irq(irq);
-
 	status = 0;
 	action = irq_action[irq];
 	kstat.irqs[cpu][irq]++;
@@ -765,14 +822,10 @@
 		do { 
 			status |= action->flags;
 			action->handler(irq, action->dev_id, regs);
-			/*if (status & SA_SAMPLE_RANDOM)
-				  add_interrupt_randomness(irq);*/
 			action = action->next;
 		} while ( action );
 		__cli();
-		/*		spin_lock(&irq_controller_lock);*/
 		unmask_irq(irq);
-		/*		spin_unlock(&irq_controller_lock);*/
 	} else {
 #ifndef CONFIG_8xx	  
 		if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
@@ -781,8 +834,13 @@
 		disable_irq( irq );
 	}
 	
+	/* This was a gatwick sub-interrupt, we re-enable them on Heathrow
+           now */
+	if (_machine == _MACH_Pmac && irq >= max_real_irqs)
+		unmask_irq(second_irq);
+
 	/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-#ifndef CONFIG_8xx	
+#ifndef CONFIG_8xx											
 	if ( is_prep && (irq > 7) )
 		goto retry_cascade;
 	/* do_bottom_half is called if necessary from int_return in head.S */
@@ -808,12 +866,16 @@
 
 #ifdef SHOW_IRQ
 	printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
-	       irq,handler,devname,dev_id);
+	       irq,(int)handler,devname,(int)dev_id);
 #endif /* SHOW_IRQ */
 
 	if (irq >= NR_IRQS)
 		return -EINVAL;
 
+	/* Cannot allocate second controller IRQ */
+	if (irq == second_irq)
+		return -EBUSY;
+
 	if (!handler)
 	{
 		/* Free */
@@ -838,7 +900,7 @@
 	cli();
 	
 	action->handler = handler;
-	action->flags = irqflags;
+	action->flags = irqflags;					
 	action->mask = 0;
 	action->name = devname;
 	action->dev_id = dev_id;
@@ -909,6 +971,9 @@
 {
 	extern void xmon_irq(int, void *, struct pt_regs *);
 	int i;
+	struct device_node *irqctrler;
+	unsigned long addr;
+	struct device_node *np;
 
 #ifndef CONFIG_8xx
 	switch (_machine)
@@ -918,12 +983,59 @@
 		mask_irq = pmac_mask_irq;
 		unmask_irq = pmac_unmask_irq;
 
-		/* G3 powermacs have 64 interrupts, others have 32 */
-		max_irqs = (find_devices("mac-io") ? 64 : 32);
-		printk("System has %d possible interrupts\n", max_irqs);
+		/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
+		   others have 32 */
+		max_irqs = max_real_irqs = 32;
+		irqctrler = find_devices("mac-io");
+		if (irqctrler)
+		{
+			max_real_irqs = 64;
+			if (irqctrler->next)
+				max_irqs = 128;
+			else
+				max_irqs = 64;
+		}
+		
+		/* get addresses of first controller */
+		if (irqctrler) {
+			if  (irqctrler->n_addrs > 0) {
+				addr = (unsigned long) 
+					ioremap(irqctrler->addrs[0].address, 0x40);
+				for (i = 0; i < 2; ++i)
+					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+						(addr + (2 - i) * 0x10);
+			}
+			
+			/* get addresses of second controller */
+			irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+			if (irqctrler && irqctrler->n_addrs > 0) {
+				addr = (unsigned long) 
+					ioremap(irqctrler->addrs[0].address, 0x40);
+				for (i = 2; i < 4; ++i)
+					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+						(addr + (4 - i) * 0x10);
+			}
+		}
 
+		/* disable all interrupts in all controllers */
 		for (i = 0; i * 32 < max_irqs; ++i)
 			out_le32(&pmac_irq_hw[i]->enable, 0);
+			
+		
+		/* get interrupt line of secondary interrupt controller */
+		if (irqctrler) {
+			second_irq = irqctrler->intrs[0].line;
+			printk(KERN_INFO "irq: secondary controller on irq %d\n",
+				(int)second_irq);
+			if (device_is_compatible(irqctrler, "gatwick"))
+				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+			enable_irq(second_irq);
+		}
+		printk("System has %d possible interrupts\n", max_irqs);
+		if (max_irqs != max_real_irqs)
+			printk(KERN_DEBUG "%d interrupts on main controller\n",
+				max_real_irqs);
+
 #ifdef CONFIG_XMON
 		request_irq(20, xmon_irq, 0, "NMI", 0);
 #endif	/* CONFIG_XMON */
@@ -932,8 +1044,15 @@
 		mask_and_ack_irq = chrp_mask_and_ack_irq;
 		mask_irq = chrp_mask_irq;
 		unmask_irq = chrp_unmask_irq;
-		gg2_int_ack_special = (volatile unsigned char *)
-			ioremap(GG2_INT_ACK_SPECIAL, 1);
+		
+		if ( !(np = find_devices("pci") ) )
+			printk("Cannot find pci to get ack address\n");
+		else
+		{
+			chrp_int_ack_special = (volatile unsigned char *)
+			   (*(unsigned long *)get_property(np,
+					"8259-interrupt-acknowledge", NULL));
+		}
 		openpic_init(1);
 		i8259_init();
 		cached_irq_mask[0] = cached_irq_mask[1] = ~0UL;
@@ -993,3 +1112,61 @@
 	}
 #endif /* CONFIG_8xx */
 }
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+__pmac
+static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+	struct device_node *node;
+	static struct interrupt_info int_pool[4];
+	
+	memset(int_pool, 0, sizeof(int_pool));
+	node = gw->child;
+	while(node)
+	{
+		/* Fix SCC */
+		if (strcasecmp(node->name, "escc") == 0)
+			if (node->child && node->child->n_intrs == 0)
+			{
+				node->child->n_intrs = 1;
+				node->child->intrs = &int_pool[0];
+				int_pool[0].line = 15+irq_base;
+				printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n",
+					int_pool[0].line);
+			}
+		/* Fix media-bay & left SWIM */
+		if (strcasecmp(node->name, "media-bay") == 0)
+		{
+			struct device_node* ya_node;
+
+			if (node->n_intrs == 0)
+			{
+				node->n_intrs = 1;
+				node->intrs = &int_pool[1];
+				int_pool[1].line = 29+irq_base;
+				printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+					int_pool[1].line);
+			}
+			ya_node = node->child;
+			while(ya_node)
+			{
+				if ((strcasecmp(ya_node->name, "floppy") == 0) &&
+					ya_node->n_intrs == 0)
+				{
+					ya_node->n_intrs = 2;
+					ya_node->intrs = &int_pool[2];
+					int_pool[2].line = 19+irq_base;
+					int_pool[3].line =  1+irq_base;
+					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+						int_pool[2].line, int_pool[3].line);
+				} 
+				ya_node = ya_node->sibling;
+			}
+		}
+		node = node->sibling;
+	}
+	
+}
+
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.1.128/linux/arch/ppc/kernel/misc.S	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/misc.S	Sun Nov 15 10:51:43 1998
@@ -363,9 +363,25 @@
 	mfspr	r3,THRM1
 	blr
 
+_GLOBAL(_get_THRM2)
+	mfspr	r3,THRM2
+	blr
+
+_GLOBAL(_get_THRM3)
+	mfspr	r3,THRM3
+	blr
+		
 _GLOBAL(_set_THRM1)
 	mtspr	THRM1,r3
 	blr
+
+_GLOBAL(_set_THRM2)
+	mtspr	THRM2,r3
+	blr
+
+_GLOBAL(_set_THRM3)
+	mtspr	THRM3,r3
+	blr
 	
 _GLOBAL(_get_L2CR)
 	mfspr	r3,L2CR
@@ -453,7 +469,6 @@
 #define __NR__exit __NR_exit
 
 SYSCALL(idle)
-SYSCALL(setup)
 SYSCALL(sync)
 SYSCALL(setsid)
 SYSCALL(write)
@@ -490,12 +505,12 @@
 	.long sys_mknod
 	.long sys_chmod		/* 15 */
 	.long sys_lchown
-	.long sys_ni_syscall
+	.long sys_ni_syscall			/* old break syscall holder */
 	.long sys_stat
 	.long sys_lseek
 	.long sys_getpid	/* 20 */
 	.long sys_mount
-	.long sys_umount
+	.long sys_oldumount
 	.long sys_setuid
 	.long sys_getuid
 	.long sys_stime		/* 25 */
@@ -504,11 +519,11 @@
 	.long sys_fstat
 	.long sys_pause
 	.long sys_utime		/* 30 */
-	.long /*sys_stty*/ sys_ni_syscall
-	.long /*sys_gtty*/ sys_ni_syscall
+	.long sys_ni_syscall			/* old stty syscall holder */
+	.long sys_ni_syscall			/* old gtty syscall holder */
 	.long sys_access
 	.long sys_nice
-	.long /*sys_ftime*/ sys_ni_syscall		/* 35 */
+	.long sys_ni_syscall	/* 35 */	/* old ftime syscall holder */
 	.long sys_sync
 	.long sys_kill
 	.long sys_rename
@@ -517,7 +532,7 @@
 	.long sys_dup
 	.long sys_pipe
 	.long sys_times
-	.long /*sys_prof*/ sys_ni_syscall
+	.long sys_ni_syscall			/* old prof syscall holder */
 	.long sys_brk		/* 45 */
 	.long sys_setgid
 	.long sys_getgid
@@ -525,13 +540,13 @@
 	.long sys_geteuid
 	.long sys_getegid	/* 50 */
 	.long sys_acct
-	.long /*sys_phys*/ sys_ni_syscall
-	.long /*sys_lock*/ sys_ni_syscall
+	.long sys_umount			/* recycled never used phys() */
+	.long sys_ni_syscall			/* old lock syscall holder */
 	.long sys_ioctl
 	.long sys_fcntl		/* 55 */
-	.long /*sys_mpx*/ sys_ni_syscall
+	.long sys_ni_syscall			/* old mpx syscall holder */
 	.long sys_setpgid
-	.long /*sys_ulimit*/ sys_ni_syscall
+	.long sys_ni_syscall			/* old ulimit syscall holder */
 	.long sys_olduname
 	.long sys_umask		/* 60 */
 	.long sys_chroot
@@ -562,7 +577,7 @@
 	.long sys_uselib
 	.long sys_swapon
 	.long sys_reboot
-	.long old_readdir		/* was sys_readdir */
+	.long old_readdir
 	.long sys_mmap		/* 90 */
 	.long sys_munmap
 	.long sys_truncate
@@ -571,7 +586,7 @@
 	.long sys_fchown	/* 95 */
 	.long sys_getpriority
 	.long sys_setpriority
-	.long /*sys_profil*/ sys_ni_syscall
+	.long sys_ni_syscall			/* old profil syscall holder */
 	.long sys_statfs
 	.long sys_fstatfs	/* 100 */
 	.long sys_ioperm
@@ -610,7 +625,7 @@
 	.long sys_bdflush
 	.long sys_sysfs		/* 135 */
 	.long sys_personality
-	.long 0				/* for afs_syscall */
+	.long sys_ni_syscall	/* for afs_syscall */
 	.long sys_setfsuid
 	.long sys_setfsgid
 	.long sys_llseek	/* 140 */
@@ -638,28 +653,28 @@
 	.long sys_nanosleep
 	.long sys_mremap
 	.long sys_setresuid
-	.long sys_getresuid		/* 165 */
+	.long sys_getresuid	/* 165 */
 	.long sys_query_module
 	.long sys_poll
 	.long sys_nfsservctl
-	.long sys_setresgid	
-	.long sys_getresgid		/* 170 */
+	.long sys_setresgid
+	.long sys_getresgid	/* 170 */
 	.long sys_prctl
 	.long sys_rt_sigreturn
 	.long sys_rt_sigaction
 	.long sys_rt_sigprocmask	
-	.long sys_rt_sigpending		/* 175 */
+	.long sys_rt_sigpending	/* 175 */
 	.long sys_rt_sigtimedwait
 	.long sys_rt_sigqueueinfo
 	.long sys_rt_sigsuspend
 	.long sys_pread
-	.long sys_pwrite		/* 180 */
+	.long sys_pwrite	/* 180 */
 	.long sys_chown
 	.long sys_getcwd
 	.long sys_capget
 	.long sys_capset
-	.long sys_sigaltstack		/* 185 */
+	.long sys_sigaltstack	/* 185 */
 	.long sys_sendfile
-	.long sys_ni_syscall
-	.long sys_ni_syscall
+	.long sys_ni_syscall		/* streams1 */
+	.long sys_ni_syscall		/* streams2 */
 	.space (NR_syscalls-183)*4
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.1.128/linux/arch/ppc/kernel/pci.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/pci.c	Sun Nov 15 10:51:43 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: pci.c,v 1.38 1998/08/31 06:28:02 cort Exp $
+ * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -164,7 +164,7 @@
 			      get_property(find_path_device("/"), "model", NULL),3) )
 		{
 			isa_io_base = 0xfe000000;
-			set_config_access_method(raven);
+			set_config_access_method(grackle);
 		}
 		else
 		{
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.1.128/linux/arch/ppc/kernel/pmac_pci.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/kernel/pmac_pci.c	Sun Nov 15 10:51:43 1998
@@ -40,7 +40,6 @@
 #define BANDIT_COHERENT	0x40
 
 __pmac
-
 void *pci_io_base(unsigned int bus)
 {
 	struct bridge_data *bp;
@@ -50,6 +49,7 @@
 	return bp->io_base;
 }
 
+__pmac
 int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
 		   unsigned char *devfn_ptr)
 {
@@ -68,6 +68,7 @@
 	return 0;
 }
 
+__pmac
 int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned char *val)
 {
@@ -90,6 +91,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+__pmac
 int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned short *val)
 {
@@ -114,6 +116,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+__pmac
 int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 				   unsigned char offset, unsigned int *val)
 {
@@ -138,6 +141,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+__pmac
 int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 				   unsigned char offset, unsigned char val)
 {
@@ -159,6 +163,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+__pmac
 int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 				   unsigned char offset, unsigned short val)
 {
@@ -182,6 +187,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+__pmac
 int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 				    unsigned char offset, unsigned int val)
 {
@@ -406,7 +412,7 @@
 				ioremap(0xfec00000, 0x1000);
 			bp->cfg_data = (volatile unsigned char *)
 				ioremap(0xfee00000, 0x1000);
-			bp->io_base = (void *) ioremap(0xfe000000, 0x10000);
+                        bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
 		}
 		if (isa_io_base == 0)
 			isa_io_base = (unsigned long) bp->io_base;
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.1.128/linux/arch/ppc/kernel/pmac_setup.c	Fri Oct 23 22:01:20 1998
+++ linux/arch/ppc/kernel/pmac_setup.c	Sun Nov 15 10:51:43 1998
@@ -49,9 +49,9 @@
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
-#include <asm/mediabay.h>
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
+#include <asm/feature.h>
 #include "time.h"
 
 unsigned char drive_info;
@@ -64,7 +64,6 @@
 static void ohare_init(void);
 
 __pmac
-
 int
 pmac_get_cpuinfo(char *buffer)
 {
@@ -151,6 +150,7 @@
 #define MKDEV_SD_PARTITION(i)	MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i))
 #define MKDEV_SD(index)		MKDEV_SD_PARTITION((index) << 4)
 
+__init
 kdev_t sd_find_target(void *host, int tgt)
 {
     Scsi_Disk *dp;
@@ -168,13 +168,13 @@
  * Dummy mksound function that does nothing.
  * The real one is in the dmasound driver.
  */
+__pmac
 static void
 pmac_mksound(unsigned int hz, unsigned int ticks)
 {
 }
 
 static volatile u32 *sysctrl_regs;
-static volatile u32 *feature_addr;
 
 __initfunc(void
 pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
@@ -206,10 +206,11 @@
 	   and some registers used by smp boards */
 	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
 	__ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY));
+	ohare_init();
 
 	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
 
-	ohare_init();
+	feature_init();
 
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
@@ -234,39 +235,19 @@
 
 __initfunc(static void ohare_init(void))
 {
-	struct device_node *np;
-
-	np = find_devices("ohare");
-	if (np == 0)
-		return;
-	if (np->next != 0)
-		printk(KERN_WARNING "only using the first ohare\n");
-	if (np->n_addrs == 0) {
-		printk(KERN_ERR "No addresses for %s\n", np->full_name);
-		return;
-	}
-	feature_addr = (volatile u32 *)
-		ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4);
-
-	if (find_devices("via-pmu") == 0) {
-		printk(KERN_INFO "Twiddling the magic ohare bits\n");
-		out_le32(feature_addr, STARMAX_FEATURES);
-	} else {
-		out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES);
-		printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr));
-	}
-
 	/*
 	 * Turn on the L2 cache.
 	 * We assume that we have a PSX memory controller iff
 	 * we have an ohare I/O controller.
 	 */
-	if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
-		if (sysctrl_regs[4] & 0x10)
-			sysctrl_regs[4] |= 0x04000020;
-		else
-			sysctrl_regs[4] |= 0x04000000;
-		printk(KERN_INFO "Level 2 cache enabled\n");
+	if (find_devices("ohare") != NULL) {
+		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+			if (sysctrl_regs[4] & 0x10)
+				sysctrl_regs[4] |= 0x04000020;
+			else
+				sysctrl_regs[4] |= 0x04000000;
+			printk(KERN_INFO "Level 2 cache enabled\n");
+		}
 	}
 }
 
@@ -277,8 +258,10 @@
 int boot_part;
 kdev_t boot_dev;
 
-__initfunc(void powermac_init(void))
+void __init powermac_init(void)
 {
+  	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+		return;
 	adb_init();
 	pmac_nvram_init();
 	if (_machine == _MACH_Pmac) {
@@ -363,7 +346,9 @@
 #endif
 }
 
-__initfunc(void note_bootable_part(kdev_t dev, int part))
+/* can't be initfunc - can be called whenever a disk is first accessed */
+__pmac
+void note_bootable_part(kdev_t dev, int part)
 {
 	static int found_boot = 0;
 	char *p;
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.1.128/linux/arch/ppc/kernel/pmac_support.c	Fri May  8 23:14:45 1998
+++ linux/arch/ppc/kernel/pmac_support.c	Sun Nov 15 10:51:43 1998
@@ -25,8 +25,7 @@
 #define NVRAM_SIZE	0x2000	/* 8kB of non-volatile RAM */
 
 
-__pmac
-
+__init
 void pmac_nvram_init(void)
 {
 	struct device_node *dp;
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.1.128/linux/arch/ppc/kernel/ppc_ksyms.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Sun Nov 15 10:51:43 1998
@@ -24,6 +24,7 @@
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
+#include <asm/feature.h>
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -100,7 +101,6 @@
 EXPORT_SYMBOL(strspn);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(strnicmp);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
@@ -159,6 +159,10 @@
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
 
+#ifndef CONFIG_MACH_SPECIFIC
+EXPORT_SYMBOL(_machine);
+#endif
+
 EXPORT_SYMBOL(adb_request);
 EXPORT_SYMBOL(adb_autopoll);
 EXPORT_SYMBOL(adb_register);
@@ -174,10 +178,15 @@
 EXPORT_SYMBOL(abort);
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_compatible_devices);
 EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(find_phandle);
 EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(feature_set);
+EXPORT_SYMBOL(feature_clear);
+EXPORT_SYMBOL(feature_test);
 EXPORT_SYMBOL(note_scsi_host);
 EXPORT_SYMBOL(kd_mksound);
 #ifdef CONFIG_PMAC
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.1.128/linux/arch/ppc/kernel/prep_pci.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/prep_pci.c	Sun Nov 15 10:51:43 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.22 1998/08/05 20:11:15 cort Exp $
+ * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -462,6 +462,11 @@
 			Motherboard_map = Utah_pci_IRQ_map;
 			Motherboard_routes = Utah_pci_IRQ_routes;
 			break;
+                case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */
+                        Motherboard_map_name = "Motorola MTX";
+                        Motherboard_map = Genesis_pci_IRQ_map;
+                        Motherboard_routes = Genesis_pci_IRQ_routes;
+                        break;
 		case 0x40: /* PowerStack */
 		default: /* Can't hurt, can it? */
 			Motherboard_map_name = "Blackhawk (Powerstack)";
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.1.128/linux/arch/ppc/kernel/prep_setup.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/prep_setup.c	Sun Nov 15 10:51:44 1998
@@ -196,7 +196,7 @@
         sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line);
 	printk("Boot arguments: %s\n", cmd_line);
 	
-#ifdef CONFIG_CS4232
+#ifdef CONFIG_SOUND_CS4232
 	/*
 	 * setup proper values for the cs4232 driver so we don't have
 	 * to recompile for the motorola or ibm workstations sound systems.
@@ -233,8 +233,7 @@
 			}
 		}
 	}
-#endif /* CONFIG_CS4232 */	
-	
+#endif /* CONFIG_SOUND_CS4232 */	
 
 	/*print_residual_device_info();*/
         request_region(0x20,0x20,"pic1");
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.128/linux/arch/ppc/kernel/process.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/process.c	Sun Nov 15 10:51:44 1998
@@ -163,14 +163,19 @@
 #endif
 
 #ifdef SHOW_TASK_SWITCHES
-	printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n",
+	printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
 	       prev->comm,prev->pid,
 	       new->comm,new->pid,new->tss.regs->nip,new->processor,
-	       new->tss.smp_fork_ret,scheduler_lock.lock);
+	       scheduler_lock.lock,new->fs->root,prev->fs->root);
 #endif
 #ifdef __SMP__
 	/* avoid complexity of lazy save/restore of fpu
-	 * by just saving it every time we switch out -- Cort
+	 * by just saving it every time we switch out if
+	 * this task used the fpu during the last quantum.
+	 * 
+	 * If it tries to use the fpu again, it'll trap and
+	 * reload its fp regs.
+	 *  -- Cort
 	 */
 	if ( prev->tss.regs->msr & MSR_FP )
 		smp_giveup_fpu(prev);
@@ -383,6 +388,7 @@
 {
 
 	int res;
+	
 	lock_kernel();
 	res = do_fork(SIGCHLD, regs->gpr[1], regs);
 	/* only parent returns here */
@@ -404,18 +410,23 @@
 {
 	int error;
 	char * filename;
-	
 	lock_kernel();
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
+#ifdef __SMP__	  
+	if ( regs->msr & MSR_FP )
+		smp_giveup_fpu(current);
+#else	  
 	if ( last_task_used_math == current )
-		last_task_used_math = NULL;
+		giveup_fpu();
+#endif	
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 	putname(filename);
 out:
 	unlock_kernel();
+
 	return error;
 }
 
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.1.128/linux/arch/ppc/kernel/prom.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/prom.c	Sun Nov 15 10:51:44 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.39 1998/09/18 09:14:52 paulus Exp $
+ * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/version.h>
 #include <asm/prom.h>
 #include <asm/page.h>
 #include <asm/processor.h>
@@ -62,6 +63,13 @@
 	unsigned size;
 };
 
+struct pci_intr_map {
+	struct pci_address addr;
+	unsigned dunno;
+	phandle int_ctrler;
+	unsigned intr;
+};
+
 typedef unsigned long interpret_func(struct device_node *, unsigned long);
 static interpret_func interpret_pci_props;
 static interpret_func interpret_dbdma_props;
@@ -90,6 +98,31 @@
 
 static struct device_node *allnodes = 0;
 
+static void clearscreen(void);
+
+#ifdef CONFIG_BOOTX_TEXT
+
+static void drawchar(char c);
+static void drawstring(const char *c);
+static void scrollscreen(void);
+
+static void draw_byte(unsigned char c, long locX, long locY);
+static void draw_byte_32(unsigned char *bits, unsigned long *base);
+static void draw_byte_16(unsigned char *bits, unsigned long *base);
+static void draw_byte_8(unsigned char *bits, unsigned long *base);
+
+static long				g_loc_X;
+static long				g_loc_Y;
+static long				g_max_loc_X;
+static long				g_max_loc_Y;
+
+#define cmapsz	(16*256)
+
+static unsigned char vga_font[cmapsz];
+
+#endif
+
+
 static void *call_prom(const char *service, int nargs, int nret, ...);
 static void prom_exit(void);
 static unsigned long copy_device_tree(unsigned long, unsigned long);
@@ -100,6 +133,7 @@
 static void relocate_nodes(void);
 static unsigned long check_display(unsigned long);
 static int prom_next_node(phandle *);
+static void *early_get_property(unsigned long, unsigned long, char *);
 
 extern void enter_rtas(void *);
 extern unsigned long reloc_offset(void);
@@ -133,7 +167,7 @@
 
 #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
 
-__openfirmware
+__init
 static void
 prom_exit()
 {
@@ -148,7 +182,7 @@
 		;
 }
 
-__openfirmware
+__init
 void
 prom_enter(void)
 {
@@ -161,7 +195,7 @@
 	RELOC(prom)(&args);
 }
 
-__openfirmware
+__init
 static void *
 call_prom(const char *service, int nargs, int nret, ...)
 {
@@ -183,13 +217,23 @@
 	return prom_args.args[nargs];
 }
 
-__openfirmware
+__init
 void
 prom_print(const char *msg)
 {
 	const char *p, *q;
 	unsigned long offset = reloc_offset();
 
+	if (RELOC(prom_stdout) == 0)
+	{
+#ifdef CONFIG_BOOTX_TEXT
+		if (RELOC(boot_infos) != 0)
+			drawstring(msg);
+#endif
+		return;
+	}		
+		
+
 	for (p = msg; *p != 0; p = q) {
 		for (q = p; *q != 0 && *q != '\n'; ++q)
 			;
@@ -208,7 +252,7 @@
  * We enter here early on, when the Open Firmware prom is still
  * handling exceptions and the MMU hash table for us.
  */
-__openfirmware
+__init
 void
 prom_init(int r3, int r4, prom_entry pp)
 {
@@ -217,10 +261,6 @@
 	unsigned long offset = reloc_offset();
 	int l;
 	char *p, *d;
-#ifdef __SMP__
-	if ( RELOC(first_cpu_booted) )
-		return;
-#endif /* __SMP__ */
 	
 	/* check if we're apus, return if we are */
 	if ( r3 == 0x61707573 )
@@ -230,24 +270,45 @@
 	 * set up some pointers and return. */
 	if (r3 == 0x426f6f58 && pp == NULL) {
 		boot_infos_t *bi = (boot_infos_t *) r4;
-		unsigned int *screen;
-		int nw, ln;
 		unsigned long space;
+		unsigned long ptr, x;
+		char *model;
+
+		RELOC(boot_infos) = PTRUNRELOC(bi);
 
-		/* first clear the screen */
-		for (ln = 0; ln < bi->dispDeviceRect[3]; ++ln) {
-			screen = (unsigned int *) (bi->dispDeviceBase
-					+ ln * bi->dispDeviceRowBytes);
-			nw = bi->dispDeviceRect[2] * bi->dispDeviceDepth / 32;
-			for (; nw > 0; --nw)
-				*screen++ = 0;
+		clearscreen();
+
+#ifdef CONFIG_BOOTX_TEXT
+		RELOC(g_loc_X) = 0;
+		RELOC(g_loc_Y) = 0;
+		RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
+		RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+		prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n"));
+#endif
+
+		/*
+		 * XXX If this is an iMac, turn off the USB controller.
+		 */
+		model = (char *) early_get_property
+			(r4 + bi->deviceTreeOffset, 4, RELOC("model"));
+		if (model && strcmp(model, RELOC("iMac,1")) == 0) {
+			out_le32((unsigned *)0x80880008, 1);	/* XXX */
 		}
 
-		RELOC(boot_infos) = PTRUNRELOC(bi);
 		space = bi->deviceTreeOffset + bi->deviceTreeSize;
 		if (bi->ramDisk)
 			space = bi->ramDisk + bi->ramDiskSize;
 		RELOC(klimit) = PTRUNRELOC((char *) bi + space);
+
+		/*
+		 * Touch each page to make sure the PTEs for them
+		 * are in the hash table - the aim is to try to avoid
+		 * getting DSI exceptions while copying the kernel image.
+		 */
+		for (ptr = (KERNELBASE + offset) & PAGE_MASK;
+		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+			x = *(volatile unsigned long *)ptr;
+
 		return;
 	}
 
@@ -342,7 +403,7 @@
  * So we check whether we will need to open the display,
  * and if so, open it now.
  */
-__openfirmware
+__init
 static unsigned long
 check_display(unsigned long mem)
 {
@@ -392,7 +453,7 @@
 	return ALIGN(mem);
 }
 
-__openfirmware
+__init
 static int
 prom_next_node(phandle *nodep)
 {
@@ -415,7 +476,7 @@
 /*
  * Make a copy of the device tree from the PROM.
  */
-__openfirmware
+__init
 static unsigned long
 copy_device_tree(unsigned long mem_start, unsigned long mem_end)
 {
@@ -436,7 +497,7 @@
 	return new_start;
 }
 
-__openfirmware
+__init
 static unsigned long
 inspect_node(phandle node, struct device_node *dad,
 	     unsigned long mem_start, unsigned long mem_end,
@@ -521,7 +582,7 @@
  * It traverses the device tree and fills in the name, type,
  * {n_}addrs and {n_}intrs fields of each node.
  */
-__openfirmware
+__init
 void
 finish_device_tree(void)
 {
@@ -535,7 +596,27 @@
 	klimit = (char *) mem;
 }
 
-__openfirmware
+/*
+ * early_get_property is used to access the device tree image prepared
+ * by BootX very early on, before the pointers in it have been relocated.
+ */
+__init void *
+early_get_property(unsigned long base, unsigned long node, char *prop)
+{
+	struct device_node *np = (struct device_node *)(base + node);
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		pp = (struct property *) (base + (unsigned long)pp);
+		if (strcmp((char *)((unsigned long)pp->name + base),
+			   prop) == 0) {
+			return (void *)((unsigned long)pp->value + base);
+		}
+	}
+	return 0;
+}
+
+__init
 static unsigned long
 finish_node(struct device_node *np, unsigned long mem_start,
 	    interpret_func *ifunc)
@@ -556,16 +637,17 @@
 		ifunc = NULL;
 	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
 		ifunc = interpret_pci_props;
-	else if (!strcmp(np->type, "dbdma")
-		|| (ifunc == interpret_dbdma_props
-		    && (!strcmp(np->type, "escc")
-			|| !strcmp(np->type, "media-bay"))))
+	else if (!strcmp(np->type, "dbdma"))
 		ifunc = interpret_dbdma_props;
-	else if (!strcmp(np->type, "mac-io"))
+	else if (!strcmp(np->type, "mac-io")
+		 || ifunc == interpret_macio_props)
 		ifunc = interpret_macio_props;
 	else if (!strcmp(np->type, "isa"))
 		ifunc = interpret_isa_props;
-	else
+	else if (!((ifunc == interpret_dbdma_props
+		    || ifunc == interpret_macio_props)
+		   && (!strcmp(np->type, "escc")
+		       || !strcmp(np->type, "media-bay"))))
 		ifunc = NULL;
 
 	/* if we were booted from BootX, convert the full name */
@@ -594,7 +676,7 @@
  * are offsets from the start of the tree.
  * This procedure updates the pointers.
  */
-__openfirmware
+__init
 static void relocate_nodes(void)
 {
 	unsigned long base;
@@ -620,13 +702,14 @@
 	}
 }
 
-__openfirmware
+__init
 static unsigned long
 interpret_pci_props(struct device_node *np, unsigned long mem_start)
 {
 	struct address_range *adr;
 	struct pci_reg_property *pci_addrs;
-	int i, l, *ip;
+	int i, l, *ip, ml;
+	struct pci_intr_map *imp;
 
 	pci_addrs = (struct pci_reg_property *)
 		get_property(np, "assigned-addresses", &l);
@@ -645,6 +728,30 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	/*
+	 * If the pci host bridge has an interrupt-map property,
+	 * look for our node in it.
+	 */
+	if (np->parent != 0 && pci_addrs != 0
+	    && (imp = (struct pci_intr_map *)
+		get_property(np->parent, "interrupt-map", &ml)) != 0
+	    && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
+		unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00;
+		np->n_intrs = 0;
+		np->intrs = (struct interrupt_info *) mem_start;
+		for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
+			if (imp[i].addr.a_hi == busdevfn) {
+				np->intrs[np->n_intrs].line = imp[i].intr;
+				np->intrs[np->n_intrs].sense = 0;
+				++np->n_intrs;
+			}
+		}
+		if (np->n_intrs == 0)
+			np->intrs = 0;
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		return mem_start;
+	}
+
 	ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip == 0)
 		ip = (int *) get_property(np, "interrupts", &l);
@@ -661,7 +768,7 @@
 	return mem_start;
 }
 
-__openfirmware
+__init
 static unsigned long
 interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
 {
@@ -710,7 +817,7 @@
 	return mem_start;
 }
 
-__openfirmware
+__init
 static unsigned long
 interpret_macio_props(struct device_node *np, unsigned long mem_start)
 {
@@ -748,18 +855,28 @@
 		ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip != 0) {
 		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / (2 * sizeof(int));
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = openpic_to_irq(*ip++);
-			np->intrs[i].sense = *ip++;
+		if (_machine == _MACH_Pmac) {
+			/* for the iMac */
+			np->n_intrs = l / sizeof(int);
+			for (i = 0; i < np->n_intrs; ++i) {
+				np->intrs[i].line = *ip++;
+				np->intrs[i].sense = 0;
+			}
+		} else {
+			/* CHRP machines */
+			np->n_intrs = l / (2 * sizeof(int));
+			for (i = 0; i < np->n_intrs; ++i) {
+				np->intrs[i].line = openpic_to_irq(*ip++);
+				np->intrs[i].sense = *ip++;
+			}
 		}
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
 	}
 
 	return mem_start;
 }
 
-__openfirmware
+__init
 static unsigned long
 interpret_isa_props(struct device_node *np, unsigned long mem_start)
 {
@@ -797,7 +914,7 @@
 	return mem_start;
 }
 
-__openfirmware
+__init
 static unsigned long
 interpret_root_props(struct device_node *np, unsigned long mem_start)
 {
@@ -876,6 +993,30 @@
 	return head;
 }
 
+/* Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+__openfirmware
+int
+device_is_compatible(struct device_node *device, const char *compat)
+{
+	const char* cp;
+	int cplen, l;
+
+	cp = (char *) get_property(device, "compatible", &cplen);
+	if (cp == NULL)
+		return 0;
+	while (cplen > 0) {
+		if (strcasecmp(cp, compat) == 0)
+			return 1;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+
+	return 0;
+}
+
 /*
  * Construct and return a list of the device_nodes with a given type
  * and compatible property.
@@ -885,15 +1026,13 @@
 find_compatible_devices(const char *type, const char *compat)
 {
 	struct device_node *head, **prevp, *np;
-	const char *cp;
 
 	prevp = &head;
 	for (np = allnodes; np != 0; np = np->allnext) {
 		if (type != NULL
 		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
 			continue;
-		cp = (char *) get_property(np, "compatible", NULL);
-		if (cp != NULL && strcasecmp(cp, compat) == 0) {
+		if (device_is_compatible(np, compat)) {
 			*prevp = np;
 			prevp = &np->next;
 		}
@@ -951,6 +1090,7 @@
 	return 0;
 }
 
+#if 0
 __openfirmware
 void
 print_properties(struct device_node *np)
@@ -1001,7 +1141,9 @@
 		}
 	}
 }
+#endif
 
+/* this can be called after setup -- Cort */
 __openfirmware
 int
 call_rtas(const char *service, int nargs, int nret,
@@ -1038,7 +1180,7 @@
 	return u.words[nargs+3];
 }
 
-__openfirmware
+__init
 void
 abort()
 {
@@ -1048,3 +1190,563 @@
 #endif
 	prom_exit();
 }
+
+#define CALC_BASE(y)	(bi->dispDeviceBase + bi->dispDeviceRect[0] * \
+			(bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y))
+
+__init
+static void
+clearscreen(void)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
+	unsigned long *base	= (unsigned long *)CALC_BASE(0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		unsigned long *ptr = base;
+		for(j=width; j; --j)
+			*(ptr++) = 0;
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+
+__init
+static void
+scrollscreen(void)
+{
+	unsigned long offset		= reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	unsigned long *src		= (unsigned long *)CALC_BASE(16);
+	unsigned long *dst		= (unsigned long *)CALC_BASE(0);
+	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+						(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
+	{
+		unsigned long *src_ptr = src;
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = *(src_ptr++);
+		src += (bi->dispDeviceRowBytes >> 2);
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+	for (i=0; i<16; i++)
+	{
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = 0;
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+__init
+static void
+drawchar(char c)
+{
+	unsigned long offset = reloc_offset();
+
+	switch(c)
+	{
+		case '\r':	RELOC(g_loc_X) = 0;				break;
+		case '\n':	RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++;		break;
+		default:
+			draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
+			if (RELOC(g_loc_X) >= RELOC(g_max_loc_X))
+			{
+				RELOC(g_loc_X) = 0;
+				RELOC(g_loc_Y)++;
+			}
+	}
+	while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
+	{
+		scrollscreen();
+		RELOC(g_loc_Y)--;
+	}
+}
+
+__init
+static void
+drawstring(const char *c)
+{
+	while(*c)
+		drawchar(*(c++));
+}
+
+__init
+static void
+draw_byte(unsigned char c, long locX, long locY)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	unsigned char *base	=	bi->dispDeviceBase
+							 + (bi->dispDeviceRowBytes * ((locY * 16) +  bi->dispDeviceRect[1]))
+							 + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]);
+	unsigned char *font	=	&RELOC(vga_font)[((unsigned long)c) * 16];
+	
+	switch(bi->dispDeviceDepth)
+	{
+		case 32:
+			draw_byte_32(font, (unsigned long *)base);
+			break;
+		case 16:
+			draw_byte_16(font, (unsigned long *)base);
+			break;
+		case 8:
+			draw_byte_8(font, (unsigned long *)base);
+			break;
+		default:
+			break;
+	}
+}
+
+__init
+static unsigned long expand_bits_8[16] = {
+	0x00000000,
+	0x000000ff,
+	0x0000ff00,
+	0x0000ffff,
+	0x00ff0000,
+	0x00ff00ff,
+	0x00ffff00,
+	0x00ffffff,
+	0xff000000,
+	0xff0000ff,
+	0xff00ff00,
+	0xff00ffff,
+	0xffff0000,
+	0xffff00ff,
+	0xffffff00,
+	0xffffffff
+};
+
+__init
+static unsigned long expand_bits_16[4] = {
+	0x00000000,
+	0x0000ffff,
+	0xffff0000,
+	0xffffffff
+};
+
+
+__init
+static void
+draw_byte_32(unsigned char *font, unsigned long *base)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (-(bits >> 7) & fg) ^ bg;
+		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+		base[7] = (-(bits & 1) & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+	}
+}
+
+__init
+static void
+draw_byte_16(unsigned char *font, unsigned long *base)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	unsigned long *eb = RELOC(expand_bits_16);
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 6] & fg) ^ bg;
+		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+		base[3] = (eb[bits & 3] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+	}
+}
+
+__init
+static void
+draw_byte_8(unsigned char *font, unsigned long *base)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	int l, bits;	
+	int fg = 0x0F0F0F0FUL;
+	int bg = 0x00000000UL;
+	unsigned long *eb = RELOC(expand_bits_8);
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 4] & fg) ^ bg;
+		base[1] = (eb[bits & 0xf] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+	}
+}
+
+__init
+static unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+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, 
+};
+
+#endif /* CONFIG_BOOTX_TEXT */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c
--- v2.1.128/linux/arch/ppc/kernel/residual.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/residual.c	Sun Nov 15 10:51:44 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: residual.c,v 1.12 1998/08/27 23:15:56 paulus Exp $
+ * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $
  *
  * Code to deal with the PReP residual data.
  *
@@ -49,7 +49,7 @@
 #include <asm/ide.h>
 
 
-const char * PnP_BASE_TYPES[]= {
+const char * PnP_BASE_TYPES[] __initdata = {
   "Reserved",
   "MassStorageDevice",
   "NetworkInterfaceController",
@@ -65,7 +65,7 @@
 
 /* Device Sub Type Codes */
 
-const unsigned char * PnP_SUB_TYPES[] = {
+const unsigned char * PnP_SUB_TYPES[] __initdata = {
   "\001\000SCSIController",
   "\001\001IDEController",
   "\001\002FloppyController",
@@ -122,7 +122,7 @@
 
 /* Device Interface Type Codes */
 
-const  unsigned char * PnP_INTERFACES[]= {
+const  unsigned char * PnP_INTERFACES[] __initdata = {
   "\000\000\000General",
   "\001\000\000GeneralSCSI",
   "\001\001\000GeneralIDE",
@@ -240,7 +240,7 @@
   NULL
   };
 
-static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, 
+static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 
 					     unsigned char SubType) {
 	const unsigned char ** s=PnP_SUB_TYPES;
 	while (*s && !((*s)[0]==BaseType 
@@ -249,7 +249,7 @@
 	else return("Unknown !");
 };
 
-static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, 
+static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 
 					      unsigned char SubType,
 					      unsigned char Interface) {
 	const unsigned char ** s=PnP_INTERFACES;
@@ -260,7 +260,7 @@
 	else return NULL;
 };
 
-static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
+static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
 	int i, c;
 	char decomp[4];
 #define p pkt->S14_Pack.S14_Data.S14_PPCPack
@@ -285,7 +285,7 @@
 #undef p
 }
 
-static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
+static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
 	static const unsigned char * intlevel[] = {"high", "low"};
 	static const unsigned char * intsense[] = {"edge", "level"};
 
@@ -352,7 +352,7 @@
 	}
 }
 
-static void printlargevendor(PnP_TAG_PACKET * pkt, int size) {
+static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
 	static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
 	static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
 	static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
@@ -462,7 +462,7 @@
 	}
 }
 
-static void printlargepacket(PnP_TAG_PACKET * pkt, int size) {
+static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
 	switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
 	case LargeVendorItem:
 	  printlargevendor(pkt, size);
@@ -473,7 +473,7 @@
 	  break;
 	}
 }
-static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
+static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
 	if (pkt->S1_Pack.Tag== END_TAG) {
 		printk("  No packets describing %s resources.\n", cat);
 		return;
@@ -494,7 +494,7 @@
 	} while (pkt->S1_Pack.Tag != END_TAG);
 }
 
-void print_residual_device_info(void)
+void __init print_residual_device_info(void)
 {
 	int i;
 	PPC_DEVICE *dev;
@@ -562,8 +562,8 @@
 }
 
 
-
-static void printVPD(void) {
+#if 0
+static void __init printVPD(void) {
 #define vpd res->VitalProductData
 	int ps=vpd.PageSize, i, j;
 	static const char* Usage[]={
@@ -628,7 +628,6 @@
 /*
  * Spit out some info about residual data
  */
-#if 0
 void print_residual_device_info(void)
 {
 	int i;
@@ -764,7 +763,7 @@
 little endian in the heap, so we use two parameters to avoid writing
 two very similar functions */
 
-static int same_DevID(unsigned short vendor,
+static int __init same_DevID(unsigned short vendor,
 	       unsigned short Number,
 	       char * str) 
 {
@@ -780,7 +779,7 @@
 	return 0;
 }
 
-PPC_DEVICE *residual_find_device(unsigned long BusMask,
+PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
 			 unsigned char * DevID,
 			 int BaseType,
 			 int SubType,
@@ -803,7 +802,7 @@
 	return 0;
 }
 
-PPC_DEVICE *residual_find_device_id(unsigned long BusMask,
+PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
 			 unsigned short DevID,
 			 int BaseType,
 			 int SubType,
@@ -844,7 +843,7 @@
 	return 0; /* not found */
 }
 
-PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
+PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
 					     unsigned packet_type,
 					     int n)
 {
@@ -858,7 +857,7 @@
 	return 0; /* not found */
 }
 
-PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
+PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
 					   unsigned packet_type,
 					   int n)
 {
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.1.128/linux/arch/ppc/kernel/setup.c	Fri Oct  9 13:27:06 1998
+++ linux/arch/ppc/kernel/setup.c	Sun Nov 15 10:51:44 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.103 1998/09/18 09:14:56 paulus Exp $
+ * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -24,6 +24,7 @@
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/amigappc.h>
+#include <asm/smp.h>
 #ifdef CONFIG_MBX
 #include <asm/mbx.h>
 #endif
@@ -131,9 +132,7 @@
 				cuda_poll();
 			break;
 		case ADB_VIAPMU:
-			pmu_request(&req, NULL, 1, PMU_RESET);
-			for (;;)
-				pmu_poll();
+			pmu_restart();
 			break;
 		default:
 		}
@@ -206,10 +205,7 @@
 				cuda_poll();
 			break;
 		case ADB_VIAPMU:
-			pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
-				    'M', 'A', 'T', 'T');
-			for (;;)
-				pmu_poll();
+			pmu_shutdown();
 			break;
 		default:
 		}
@@ -250,9 +246,11 @@
 {
 #if !defined(CONFIG_MBX) && !defined(CONFIG_APUS)
 	switch (_machine) {
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
 	case _MACH_Pmac:
-		pmac_ide_init_hwif_ports(p,base,irq);
+	  	pmac_ide_init_hwif_ports(p,base,irq);
 		break;
+#endif		
 	case _MACH_chrp:
 		chrp_ide_init_hwif_ports(p,base,irq);
 		break;
@@ -267,68 +265,31 @@
 
 unsigned long cpu_temp(void)
 {
-#if 0	
-	unsigned long i, temp, thrm1, dir;
-	int sanity;
+	unsigned char thres = 0;
 	
-	/*
-	 * setup thrm3 - need to give TAU at least 20us
-	 * to do the compare so assume a 300MHz clock.
-	 * We need 300*20 ticks then.
-	 * -- Cort
-	 */
-	asm("mtspr 1020, %1\n\t"
-	    "mtspr 1021, %1\n\t"
-	    "mtspr 1022, %0\n\t"::
-	    "r" ( ((300*20)<<18) | THRM3_E), "r" (0) );
-		
-#if 0
-	for ( i = 127 ; i >= 0 ; i-- )
-	{
-		asm("mtspr 1020, %0\n\t"::
-		    "r" (THRM1_TID|THRM1_V|(i<<2)) );
-		/* check value */
-		while ( !( thrm1 & THRM1_TIV) )
-			asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );
-		if ( thrm1 & THRM1_TIN )
-		{
-			printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV);
-			goto out;
-		}
-
-	}
-#endif
 #if 0
-	i = 32;			/* increment */
-	dir = 1;		/* direction we're checking 0=up 1=down */
-	temp = 64;		/* threshold checking against */
-	while ( i )
-	{
-		_set_THRM1((1<<29) | THRM1_V | (temp<<2) );
-		printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir,
-		       ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1());
-		/* check value */
-		sanity = 0x0fffffff;
-		while ( (!( thrm1 & THRM1_TIV)) && (sanity--) )
-			thrm1 = _get_THRM1();
-			/*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/
-		if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n");
-		/* temp is not in that direction */
-		if ( !(thrm1 & THRM1_TIN) )
-		{
-			printk("not in that dir thrm1 %x\n",thrm1);
-			if ( dir == 0 ) dir = 1;
-			else dir = 0;
-		}
-		if ( dir ) temp -= i;
-		else temp += i;
-		i /= 2;
-	}
-	asm("mtspr 1020, %0\n\t"
-	    "mtspr 1022, %0\n\t" ::"r" (0) );
+	/* disable thrm2 */
+	_set_THRM2( 0 );
+	/* threshold 0 C, tid: exceeding threshold, tie: don't generate interrupt */
+	_set_THRM1( THRM1_V );
+
+	/* we need 20us to do the compare - assume 300MHz processor clock */
+	_set_THRM3(0);
+	_set_THRM3(THRM3_E | (300*30)<<18 );
+
+	udelay(100);
+	/* wait for the compare to complete */
+	/*while ( !(_get_THRM1() & THRM1_TIV) ) ;*/
+	if ( !(_get_THRM1() & THRM1_TIV) )
+		printk("no tiv\n");
+	if ( _get_THRM1() & THRM1_TIN )
+		printk("crossed\n");
+	/* turn everything off */
+	_set_THRM3(0);
+	_set_THRM1(0);
 #endif
-#endif	
-	return 0;
+		
+	return thres;
 }
 
 int get_cpuinfo(char *buffer)
@@ -342,12 +303,11 @@
 	unsigned long i;
 	
 #ifdef __SMP__
-	extern unsigned long cpu_present_map;	
-	extern struct cpuinfo_PPC cpu_data[NR_CPUS];
+#define CPU_PRESENT(x) (cpu_callin_map[(x)])
 #define GET_PVR ((long int)(cpu_data[i].pvr))
 #define CD(x) (cpu_data[i].x)
 #else
-#define cpu_present_map 1L
+#define CPU_PRESENT(x) ((x)==0)
 #define smp_num_cpus 1
 #define GET_PVR ((long int)_get_PVR())
 #define CD(x) (x)
@@ -355,7 +315,7 @@
 
 	for ( i = 0; i < smp_num_cpus ; i++ )
 	{
-		if ( ! ( cpu_present_map & (1<<i) ) )
+		if ( !CPU_PRESENT(i) )
 			continue;
 		if ( i )
 			len += sprintf(len+buffer,"\n");
@@ -509,9 +469,13 @@
 		 unsigned long r6, unsigned long r7))
 {
 	extern void setup_pci_ptrs(void);
+	
+#ifdef __SMP__
+	if ( first_cpu_booted ) return 0;
+#endif /* __SMP__ */
+	
 #ifndef CONFIG_MBX
 #ifndef CONFIG_MACH_SPECIFIC
-	char *model;
 	/* boot loader will tell us if we're APUS */
 	if ( r3 == 0x61707573 )
 	{
@@ -524,13 +488,22 @@
 		_machine = _MACH_prep;
 		have_of = 0;
 	} else {
+		char *model;
+
 		have_of = 1;
 		/* ask the OF info if we're a chrp or pmac */
-		model = get_property(find_path_device("/"), "type", NULL);
-		if ( !strncmp("chrp",model,4) )
+		model = get_property(find_path_device("/"), "device_type", NULL);
+		if ( model && !strncmp("chrp",model,4) )
 			_machine = _MACH_chrp;
-		else 
-			_machine = _MACH_Pmac;
+		else
+		{
+			model = get_property(find_path_device("/"),
+					     "model", NULL);
+			if ( model && !strncmp(model, "IBM", 3))
+				_machine = _MACH_chrp;
+			else
+				_machine = _MACH_Pmac;
+		}
 
 	}
 #endif /* CONFIG_MACH_SPECIFIC */		
@@ -714,6 +687,12 @@
 		strcpy(cmd_line, (char *)(r6+KERNELBASE));
 	}
 #endif /* CONFIG_MBX */
+
+	/* Check for nobats option (used in mapin_ram). */
+	if (strstr(cmd_line, "nobats")) {
+		extern int __map_without_bats;
+		__map_without_bats = 1;
+	}
 	return 0;
 }
 
@@ -753,20 +732,6 @@
 	*memory_start_p = find_available_memory();
 	*memory_end_p = (unsigned long) end_of_DRAM;
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
-	if ( initrd_start )
-	{
-		if (initrd_end > *memory_end_p)
-		{
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-			       initrd_end,*memory_end_p);
-			initrd_start = 0;
-		}
-	}
-#endif
-	
 #ifdef CONFIG_MBX
 	mbx_setup_arch(memory_start_p,memory_end_p);
 #else /* CONFIG_MBX */	
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.1.128/linux/arch/ppc/kernel/signal.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/signal.c	Sun Nov 15 10:51:44 1998
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/ppc/kernel/signal.c
  *
- *  $Id: signal.c,v 1.20 1998/09/28 16:47:09 cort Exp $
+ *  $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -245,7 +245,7 @@
 			goto badframe;
 		sr = (struct sigregs *) sigctx.regs;
 		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sr;
+		regs->gpr[4] = (unsigned long) sc;
 		regs->link = (unsigned long) &sr->tramp;
 		regs->nip = sigctx.handler;
 
@@ -293,7 +293,7 @@
 	    || get_user(regs->gpr[3], &sc->signal))
 		goto badframe;
 	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long) frame;
+	regs->gpr[4] = (unsigned long) sc;
 	regs->link = (unsigned long) frame->tramp;
 
 	return;
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.1.128/linux/arch/ppc/kernel/smp.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/smp.c	Sun Nov 15 10:51:45 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.33 1998/09/25 04:32:30 cort Exp $
+ * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $
  *
  * Smp support for ppc.
  *
@@ -35,24 +35,20 @@
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
 int smp_num_cpus = 1;
-unsigned long cpu_present_map = 0;
-volatile int cpu_number_map[NR_CPUS];
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile int __cpu_logical_map[NR_CPUS];
-static unsigned char boot_cpu_id = 0;
 struct cpuinfo_PPC cpu_data[NR_CPUS];
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 volatile unsigned char active_kernel_processor = NO_PROC_ID;	/* Processor holding kernel spinlock		*/
 volatile unsigned long ipi_count;
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
-
 int first_cpu_booted = 0;
 
-int start_secondary(void *);
+/* all cpu mappings are 1-1 -- Cort */
+int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
+int start_secondary(void *);
 extern int cpu_idle(void *unused);
 
 void smp_local_timer_interrupt(struct pt_regs * regs)
@@ -60,7 +56,6 @@
 	int cpu = smp_processor_id();
 	extern void update_one_process(struct task_struct *,unsigned long,
 				       unsigned long,unsigned long,int);
-
 	if (!--prof_counter[cpu]) {
 		int user=0,system=0;
 		struct task_struct * p = current;
@@ -106,7 +101,7 @@
  * Right now it only works for stop cpu's but will be setup
  * later for more general message passing.
  *
- * As it is now, if we're sending two message as the same time
+ * As it is now, if we're sending two message at the same time
  * we have race conditions.  I avoided doing locks here since
  * all that works right now is the stop cpu message.
  *
@@ -117,17 +112,25 @@
 {
 	int msg = smp_message[smp_processor_id()];
 	
-	printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);
+	/* clear interrupt */
+	*(volatile unsigned long *)(0xf80000c0) = ~0L;
+	eieio();
 	
 	/* make sure msg is for us */
 	if ( msg == -1 ) return;
 
+	ipi_count++;
+	/*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/
+	
 	switch( msg )
 	{
 	case MSG_STOP_CPU:
 		__cli();
 		while (1) ;
 		break;
+	case MSG_RESCHEDULE: 
+		current->need_resched = 1;
+		break;
 	case 0xf0f0: /* syncing time bases - just return */
 		break;
 	default:
@@ -141,19 +144,17 @@
 
 void smp_send_reschedule(int cpu)
 {
-	/* for now, nothing */
+	smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
 }
 
-
 spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-	printk("SMP %d: sending smp message\n", current->processor);
-
-	spin_lock(&mesg_pass_lock);
 	if ( _machine != _MACH_Pmac )
 		return;
-
+	/*printk("SMP %d: sending smp message\n", current->processor);*/
+if (smp_processor_id() ) printk("pass from cpu 1\n");
+	spin_lock(&mesg_pass_lock);
 #define OTHER (~smp_processor_id() & 1)
 	
 	switch( target )
@@ -169,9 +170,10 @@
 		break;
 	}
 	/* interrupt secondary processor */
-	/**(volatile unsigned long *)(0xf80000c0) = 0xffffffff;
-	eieio();*/
-	*(volatile unsigned long *)(0xf80000c0) = 0;
+	*(volatile unsigned long *)(0xf80000c0) = ~0L;
+	eieio();
+	*(volatile unsigned long *)(0xf80000c0) = 0L;
+	eieio();
 	/* interrupt primary */
 	/**(volatile unsigned long *)(0xf3019000);*/
 	spin_unlock(&mesg_pass_lock);	
@@ -180,6 +182,7 @@
 __initfunc(void smp_boot_cpus(void))
 {
 	extern struct task_struct *current_set[NR_CPUS];
+	extern void __secondary_start(void);
 	int i;
 	struct task_struct *p;
 	
@@ -189,21 +192,14 @@
 	dcbf(&first_cpu_booted);
 
 	for (i = 0; i < NR_CPUS; i++) {
-		cpu_number_map[i] = -1;
 		prof_counter[i] = 1;
 		prof_multiplier[i] = 1;
 	}
-	
-	cpu_present_map = 0;
-	for(i=0; i < NR_CPUS; i++)
-		__cpu_logical_map[i] = -1;
-
-        smp_store_cpu_info(boot_cpu_id);
-        active_kernel_processor = boot_cpu_id;
-	current->processor = boot_cpu_id;
-        cpu_present_map |= 1;
-        cpu_number_map[boot_cpu_id] = 0;
-	__cpu_logical_map[0] = boot_cpu_id;
+
+	cpu_callin_map[0] = 1;
+        smp_store_cpu_info(0);
+        active_kernel_processor = 0;
+	current->processor = 0;
 	
 	if ( _machine != _MACH_Pmac )
 	{
@@ -211,10 +207,6 @@
 		return;
 	}
 	
-        /* assume a 2nd processor for now */	
-        cpu_present_map |= (1 << 1); 
-	smp_num_cpus = 2;
-	
 	/* create a process for second processor */
         kernel_thread(start_secondary, NULL, CLONE_PID);
 	p = task[1];
@@ -222,15 +214,16 @@
 		panic("No idle task for secondary processor\n");
 	p->processor = 1;
 	current_set[1] = p;
+
 	/* need to flush here since secondary bat's aren't setup */
 	dcbf((void *)&current_set[1]);
-	
 	/* setup entry point of secondary processor */
-	/*	*(volatile unsigned long *)(0xf2800000)
-		= (unsigned long)secondary_entry-KERNELBASE;*/
-	*(volatile unsigned long *)(0xf2800000) = 0x100;
+	*(volatile unsigned long *)(0xf2800000) =
+		(unsigned long)__secondary_start-KERNELBASE;
 	eieio();
 	/* interrupt secondary to begin executing code */
+	*(volatile unsigned long *)(0xf80000c0) = ~0L;
+	eieio();
 	*(volatile unsigned long *)(0xf80000c0) = 0L;
 	eieio();
 	/*
@@ -241,24 +234,21 @@
 	 */
 	for ( i = 1000; i && !cpu_callin_map[1] ; i-- )
 		udelay(100);
-	  
+	
 	if(cpu_callin_map[1]) {
-		cpu_number_map[1] = 1;
-		__cpu_logical_map[i] = 1;
-		printk("Processor 1 found.\n");
-
+		printk("Processor %d found.\n", smp_num_cpus);
+		smp_num_cpus++;
 #if 0 /* this sync's the decr's, but we don't want this now -- Cort */
 		set_dec(decrementer_count);
 #endif
-		/* interrupt secondary to start decr's on both cpus */
-		smp_message_pass(1,0xf0f0, 0, 0);
-		/* interrupt secondary to begin executing code */
-		/**(volatile unsigned long *)(0xf80000c0) = 0L;
-		eieio();*/
 	} else {
-		smp_num_cpus--;
-		printk("Processor %d is stuck.\n", 1);
+		printk("Processor %d is stuck. \n", smp_num_cpus);
 	}
+	/* reset the entry point so if we get another intr we won't
+	 * try to startup again */
+	*(volatile unsigned long *)(0xf2800000) = 0x100;
+	/* send interrupt to other processors to start decr's on all cpus */
+	smp_message_pass(1,0xf0f0, 0, 0);
 }
 
 __initfunc(void smp_commence(void))
@@ -278,7 +268,7 @@
 }
 
 /* Activate a secondary processor. */
-__initfunc(int start_secondary(void *unused))
+asmlinkage int __init start_secondary(void *unused)
 {
 	printk("SMP %d: start_secondary()\n",current->processor);
 	smp_callin();
@@ -288,16 +278,14 @@
 __initfunc(void smp_callin(void))
 {
 	printk("SMP %d: smp_callin()\n",current->processor);
-        smp_store_cpu_info(1);
+        smp_store_cpu_info(current->processor);
 	set_dec(decrementer_count);
 	
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
 	current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
-	
-	/* assume we're just the secondary processor for now */
-	cpu_callin_map[1] = 1;
 
+	cpu_callin_map[current->processor] = current->processor;
 	while(!smp_commenced)
 		barrier();
 	__sti();
@@ -317,6 +305,7 @@
 {
         struct cpuinfo_PPC *c = &cpu_data[id];
 
+	/* assume bogomips are same for everything */
         c->loops_per_sec = loops_per_sec;
         c->pvr = _get_PVR();
 }
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.1.128/linux/arch/ppc/kernel/time.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/kernel/time.c	Sun Nov 15 10:51:45 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: time.c,v 1.35 1998/07/24 11:05:47 geert Exp $
+ * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -106,7 +106,12 @@
 #ifdef __SMP__
 	smp_local_timer_interrupt(regs);
 #endif		
-	
+#ifdef CONFIG_APUS
+	{
+		extern void apus_heartbeat (void);
+		apus_heartbeat ();
+	}
+#endif
 	hardirq_exit(cpu);
 	/* restore the HID0 in case dcache was off - see idle.c
 	 * this hack should leave for a better solution -- Cort */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c
--- v2.1.128/linux/arch/ppc/lib/locks.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/lib/locks.c	Sun Nov 15 10:51:45 1998
@@ -1,5 +1,5 @@
 /*
- * $Id: locks.c,v 1.18 1998/07/28 03:50:27 cort Exp $
+ * $Id: locks.c,v 1.20 1998/10/08 01:17:32 cort Exp $
  *
  * Locks for smp ppc 
  * 
@@ -18,13 +18,13 @@
 #define DEBUG_LOCKS 1
 
 #undef INIT_STUCK
-#define INIT_STUCK 10000
+#define INIT_STUCK 0xffffffff
 
 void _spin_lock(spinlock_t *lock)
 {
 	int cpu = smp_processor_id();
 #ifdef DEBUG_LOCKS
-	int stuck = INIT_STUCK;
+	unsigned int stuck = INIT_STUCK;
 #endif /* DEBUG_LOCKS */
 	/* try expensive atomic load/store to get lock */
 	while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) {
@@ -67,13 +67,13 @@
 void _spin_unlock(spinlock_t *lp)
 {
 #ifdef DEBUG_LOCKS
-	if ( !lp->lock )
-		panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
-		       smp_processor_id(),current->comm,current->pid);
+  	if ( !lp->lock )
+		printk("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
+		      smp_processor_id(),current->comm,current->pid);
 	if ( lp->owner_cpu != smp_processor_id() )
-		panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
-		       lp, smp_processor_id(), (int)lp->owner_cpu,
-		       lp->owner_pc,lp->lock);
+		printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
+		      lp, smp_processor_id(), (int)lp->owner_cpu,
+		      lp->owner_pc,lp->lock);
 #endif /* DEBUG_LOCKS */
 	lp->owner_pc = lp->owner_cpu = 0;
 	eieio();
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.1.128/linux/arch/ppc/mm/fault.c	Wed Sep  9 14:51:06 1998
+++ linux/arch/ppc/mm/fault.c	Sun Nov 15 10:51:45 1998
@@ -38,7 +38,7 @@
 extern void (*debugger)(struct pt_regs *);
 extern void (*debugger_fault_handler)(struct pt_regs *);
 extern int (*debugger_dabr_match)(struct pt_regs *);
-int debugger_kernel_faults = 0;
+int debugger_kernel_faults = 1;
 #endif
 
 unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.128/linux/arch/ppc/mm/init.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/mm/init.c	Sun Nov 15 10:51:45 1998
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.123 1998/09/19 19:03:55 geert Exp $
+ *  $Id: init.c,v 1.130 1998/11/10 10:09:20 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -114,7 +114,8 @@
  * (i.e. page tables) instead of the bats.
  * -- Cort
  */
-#undef MAP_RAM_WITH_SEGREGS 1
+int __map_without_bats = 0;
+
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
@@ -243,20 +244,24 @@
 			printk("%3d ", p->processor);
 			if ( (p->processor != NO_PROC_ID) &&
 			     (p == current_set[p->processor]) )
-			
+			{
+				iscur = 1;
+				printk("current");
+			}
 #else		
 			if ( p == current )
-#endif /* __SMP__ */
 			{
 				iscur = 1;
 				printk("current");
 			}
+			
 			if ( p == last_task_used_math )
 			{
 				if ( iscur )
 					printk(",");
 				printk("last math");
 			}			
+#endif /* __SMP__ */
 			printk("\n");
 		}
 	}
@@ -677,18 +682,21 @@
 
 __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp))
 {
-	unsigned long a, e;
+	unsigned long a, s, ns;
 	int i, j, d;
 
 	d = 0;
 	for (i = 0; i < mp->n_regions; i = j) {
 		a = mp->regions[i].address;
-		e = a + mp->regions[i].size;
+		s = mp->regions[i].size;
 		for (j = i + 1; j < mp->n_regions
-			     && mp->regions[j].address <= e; ++j)
-			e = mp->regions[j].address + mp->regions[j].size;
+			     && mp->regions[j].address - a <= s; ++j) {
+			ns = mp->regions[j].address + mp->regions[j].size - a;
+			if (ns > s)
+				s = ns;
+		}
 		mp->regions[d].address = a;
-		mp->regions[d].size = e - a;
+		mp->regions[d].size = s;
 		++d;
 	}
 	mp->n_regions = d;
@@ -800,28 +808,41 @@
 	int i;
 	unsigned long v, p, s, f;
 #ifndef CONFIG_8xx
-	unsigned long tot, mem_base, bl, done;
 
-#ifndef MAP_RAM_WITH_SEGREGS
-	/* Set up BAT2 and if necessary BAT3 to cover RAM. */
-	mem_base = __pa(KERNELBASE);
-	tot = (unsigned long)end_of_DRAM - KERNELBASE;
-	for (bl = 128<<10; bl < 256<<20; bl <<= 1) {
-		if (bl * 2 > tot)
-			break;
-	}
+	if (!__map_without_bats) {
+		unsigned long tot, mem_base, bl, done;
+		unsigned long max_size = (256<<20);
+		unsigned long align;
+
+		/* Set up BAT2 and if necessary BAT3 to cover RAM. */
+		mem_base = __pa(KERNELBASE);
+
+		/* Make sure we don't map a block larger than the
+		   smallest alignment of the physical address. */
+		/* alignment of mem_base */
+		align = ~(mem_base-1) & mem_base;
+		/* set BAT block size to MIN(max_size, align) */
+		if (align && align < max_size)
+			max_size = align;
 
-	setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
-	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-	if (done < tot) {
-		/* use BAT3 to cover a bit more */
-		tot -= done;
-		for (bl = 128<<10; bl < 256<<20; bl <<= 1)
+		tot = (unsigned long)end_of_DRAM - KERNELBASE;
+		for (bl = 128<<10; bl < max_size; bl <<= 1) {
 			if (bl * 2 > tot)
 				break;
-		setbat(3, KERNELBASE+done, mem_base+done, bl, RAM_PAGE);
+		}
+
+		setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
+		done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
+		if (done < tot) {
+			/* use BAT3 to cover a bit more */
+			tot -= done;
+			for (bl = 128<<10; bl < max_size; bl <<= 1)
+				if (bl * 2 > tot)
+					break;
+			setbat(3, KERNELBASE+done, mem_base+done, bl, 
+			       RAM_PAGE);
+		}
 	}
-#endif
 
 	v = KERNELBASE;
 	for (i = 0; i < phys_mem.n_regions; ++i) {
@@ -897,7 +918,10 @@
 	switch (_machine)
 	{
 	case _MACH_Pmac:
+		FREESEC(__prep_begin,__prep_end,num_prep_pages);
+		break;
 	case _MACH_chrp:
+		FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
 		FREESEC(__prep_begin,__prep_end,num_prep_pages);
 		break;
 	case _MACH_prep:
@@ -965,8 +989,14 @@
 		setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE);
 		break;
 	case _MACH_Pmac:
-		setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE);
-		ioremap_base = 0xf0000000;
+		{
+			unsigned long base = 0xf3000000;
+			struct device_node *macio = find_devices("mac-io");
+			if (macio && macio->n_addrs)
+				base = macio->addrs[0].address;
+			setbat(0, base, base, 0x100000, IO_PAGE);
+			ioremap_base = 0xf0000000;
+		}
 		break;
 	case _MACH_apus:
 		/* Map PPC exception vectors. */
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- v2.1.128/linux/arch/ppc/pmac_defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/pmac_defconfig	Sun Nov 15 10:51:45 1998
@@ -35,16 +35,20 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
-CONFIG_MACMOUSE=y
+CONFIG_ADBMOUSE=y
+CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+# CONFIG_TOTALMP is not set
+CONFIG_BOOTX_TEXT=y
 
 #
 # Plug and Play support
@@ -70,6 +74,10 @@
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
@@ -159,7 +167,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC7XXX=y
 # CONFIG_OVERRIDE_CMDS is not set
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
@@ -216,23 +224,26 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-CONFIG_DE4X5=m
+CONFIG_DE4X5=y
 CONFIG_DEC_ELCP=m
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_DLCI is not set
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
-CONFIG_PPP=m
+CONFIG_PPP=y
 
 #
 # CCP compressors for PPP are only built as modules.
@@ -241,6 +252,7 @@
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
 
 #
 # Amateur Radio support
@@ -264,11 +276,12 @@
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
 CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA is not set
+# CONFIG_FB_MATROX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -293,8 +306,9 @@
 CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_MOUSE is not set
-# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
@@ -322,6 +336,7 @@
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_CODA_FS is not set
@@ -330,12 +345,16 @@
 # CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=m
+CONFIG_HFS_FS=y
 # CONFIG_ROMFS_FS is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
-# CONFIG_ADFS_FS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
 CONFIG_DEVPTS_FS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
 CONFIG_MAC_PARTITION=y
 CONFIG_NLS=y
 
@@ -374,3 +393,9 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
diff -u --recursive --new-file v2.1.128/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig
--- v2.1.128/linux/arch/ppc/prep_defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/prep_defconfig	Sun Nov 15 10:51:45 1998
@@ -41,7 +41,7 @@
 # CONFIG_MAC_KEYBOARD is not set
 # CONFIG_MAC_FLOPPY is not set
 # CONFIG_MAC_SERIAL is not set
-# CONFIG_MACMOUSE is not set
+# CONFIG_ADBMOUSE is not set
 # CONFIG_PROC_DEVICETREE is not set
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.128/linux/arch/sparc/defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/sparc/defconfig	Wed Nov 18 09:06:05 1998
@@ -69,6 +69,7 @@
 # CONFIG_SPARCAUDIO_AMD7930 is not set
 # CONFIG_SPARCAUDIO_CS4231 is not set
 # CONFIG_SPARCAUDIO_DBRI is not set
+# CONFIG_SPARCAUDIO_DUMMY is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.1.128/linux/arch/sparc/kernel/entry.S	Thu Aug  6 14:06:30 1998
+++ linux/arch/sparc/kernel/entry.S	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.152 1998/07/29 16:32:24 jj Exp $
+/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -313,7 +313,8 @@
 patch_handler_irq:
 	call	C_LABEL(handler_irq)
 	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
-	wr	%l0, PSR_ET, %psr
+	or	%l0, PSR_PIL, %g2	! restore PIL after handler_irq
+	wr	%g2, PSR_ET, %psr	! keep ET up
 	WRITE_PAUSE
 
 	RESTORE_ALL
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.1.128/linux/arch/sparc/kernel/sparc_ksyms.c	Sun Nov  8 14:02:45 1998
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $
+/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -41,6 +41,7 @@
 #endif
 #include <asm/a.out.h>
 #include <asm/spinlock.h>
+#include <asm/io-unit.h>
 
 struct poll {
 	int fd;
@@ -157,6 +158,8 @@
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
 EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(iounit_map_dma_init);
+EXPORT_SYMBOL(iounit_map_dma_page);
 
 /* Btfixup stuff cannot have versions, it would be complicated too much */
 #ifndef __SMP__
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.1.128/linux/arch/sparc/kernel/sun4d_smp.c	Fri Oct  9 13:27:06 1998
+++ linux/arch/sparc/kernel/sun4d_smp.c	Mon Nov 16 10:37:28 1998
@@ -168,10 +168,6 @@
 
 	printk("Entering SMP Mode...\n");
 	
-	smp_penguin_ctable.which_io = 0;
-	smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-	smp_penguin_ctable.reg_size = 0;
-
 	for (i = 0; i < NR_CPUS; i++)
 		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
 		
@@ -220,7 +216,16 @@
 			for (no = 0; no < linux_num_cpus; no++)
 				if (linux_cpus[no].mid == i)
 					break;
-			
+
+			/*
+			 * Initialize the contexts table
+			 * Since the call to prom_startcpu() trashes the structure,
+			 * we need to re-initialize it for each cpu
+			 */
+			smp_penguin_ctable.which_io = 0;
+			smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+			smp_penguin_ctable.reg_size = 0;
+
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
 			local_flush_cache_all();
@@ -230,10 +235,10 @@
 			SMP_PRINTK(("prom_startcpu returned :)\n"));
 
 			/* wheee... it's going... */
-			for(timeout = 0; timeout < 5000000; timeout++) {
+			for(timeout = 0; timeout < 10000; timeout++) {
 				if(cpu_callin_map[i])
 					break;
-				udelay(100);
+				udelay(200);
 			}
 			
 			if(cpu_callin_map[i]) {
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.1.128/linux/arch/sparc/kernel/sun4m_smp.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/sun4m_smp.c	Mon Nov 16 10:37:28 1998
@@ -143,10 +143,6 @@
 
 	printk("Entering SMP Mode...\n");
 
-	smp_penguin_ctable.which_io = 0;
-	smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-	smp_penguin_ctable.reg_size = 0;
-
 	for (i = 0; i < NR_CPUS; i++)
 		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
 
@@ -189,6 +185,15 @@
 			/* See trampoline.S for details... */
 			entry += ((i-1) * 3);
 
+			/*
+			 * Initialize the contexts table
+			 * Since the call to prom_startcpu() trashes the structure,
+			 * we need to re-initialize it for each cpu
+			 */
+			smp_penguin_ctable.which_io = 0;
+			smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+			smp_penguin_ctable.reg_size = 0;
+
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			printk("Starting CPU %d at %p\n", i, entry);
 			mid_xlate[i] = (linux_cpus[i].mid & ~8);
@@ -197,10 +202,10 @@
 				      &smp_penguin_ctable, 0, (char *)entry);
 
 			/* wheee... it's going... */
-			for(timeout = 0; timeout < 5000000; timeout++) {
+			for(timeout = 0; timeout < 10000; timeout++) {
 				if(cpu_callin_map[i])
 					break;
-				udelay(100);
+				udelay(200);
 			}
 			if(cpu_callin_map[i]) {
 				/* Another "Red Snapper". */
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.1.128/linux/arch/sparc/mm/fault.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/mm/fault.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.95 1998/09/18 19:50:32 davem Exp $
+/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -231,7 +231,8 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	handle_mm_fault(current, vma, address, write);
+	if (!handle_mm_fault(current, vma, address, write))
+		goto do_sigbus;
 	up(&mm->mmap_sem);
 	return;
 	/*
@@ -241,7 +242,7 @@
 bad_area:
 	up(&mm->mmap_sem);
 	/* Is this in ex_table? */
-	
+do_kernel_fault:
 	g2 = regs->u_regs[UREG_G2];
 	if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
 		if (fixup > 10) { /* Values below are reserved for other things */
@@ -279,6 +280,15 @@
 		return;
 	}
 	unhandled_fault (address, tsk, regs);
+	return;
+
+do_sigbus:
+	up(&mm->mmap_sem);
+	tsk->tss.sig_address = address;
+	tsk->tss.sig_desc = SUBSIG_MISCERROR;
+	force_sig(SIGBUS, tsk);
+	if (! from_user)
+		goto do_kernel_fault;
 }
 
 asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
@@ -372,7 +382,8 @@
 	else
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
-	handle_mm_fault(current, vma, address, write);
+	if (!handle_mm_fault(current, vma, address, write))
+		goto do_sigbus;
 	up(&mm->mmap_sem);
 	return;
 bad_area:
@@ -385,6 +396,12 @@
 	tsk->tss.sig_desc = SUBSIG_NOMAPPING;
 	send_sig(SIGSEGV, tsk, 1);
 	return;
+
+do_sigbus:
+	up(&mm->mmap_sem);
+	tsk->tss.sig_address = address;
+	tsk->tss.sig_desc = SUBSIG_MISCERROR;
+	force_sig(SIGBUS, tsk);
 }
 
 void window_overflow_fault(void)
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c
--- v2.1.128/linux/arch/sparc/mm/generic.c	Thu Dec 19 01:03:32 1996
+++ linux/arch/sparc/mm/generic.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.5 1996/12/18 06:43:23 tridge Exp $
+/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -41,10 +41,11 @@
 		unsigned long addr = pte_page(page);
 		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
 			return;
-		free_page(addr);
-		if (current->mm->rss <= 0)
-			return;
-		current->mm->rss--;
+		/* 
+		 * free_page() used to be able to clear swap cache
+		 * entries.  We may now have to do it manually.  
+		 */
+		free_page_and_swap_cache(addr);
 		return;
 	}
 	swap_free(pte_val(page));
diff -u --recursive --new-file v2.1.128/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c
--- v2.1.128/linux/arch/sparc/mm/io-unit.c	Fri May  8 23:14:46 1998
+++ linux/arch/sparc/mm/io-unit.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.11 1998/04/13 07:26:37 davem Exp $
+/* $Id: io-unit.c,v 1.13 1998/11/08 11:13:57 davem Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
@@ -230,4 +230,52 @@
 #ifdef CONFIG_SBUS
 	BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
 #endif
+}
+
+__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size)
+{
+	int i, j, k, npages;
+	unsigned long rotor, scan, limit;
+	unsigned long flags;
+	__u32 ret;
+	struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+
+        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+	i = 0x0213;
+	spin_lock_irqsave(&iounit->lock, flags);
+next:	j = (i & 15);
+	rotor = iounit->rotor[j - 1];
+	limit = iounit->limit[j];
+	scan = rotor;
+nexti:	scan = find_next_zero_bit(iounit->bmap, limit, scan);
+	if (scan + npages > limit) {
+		if (limit != rotor) {
+			limit = rotor;
+			scan = iounit->limit[j - 1];
+			goto nexti;
+		}
+		i >>= 4;
+		if (!(i & 15))
+			panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
+		goto next;
+	}
+	for (k = 1, scan++; k < npages; k++)
+		if (test_bit(scan++, iounit->bmap))
+			goto nexti;
+	iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
+	scan -= npages;
+	ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
+	for (k = 0; k < npages; k++, scan++)
+		set_bit(scan, iounit->bmap);
+	spin_unlock_irqrestore(&iounit->lock, flags);
+	return ret;
+}
+
+__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus)
+{
+	int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+	struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+	
+	iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK));
+	return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
 }
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.1.128/linux/arch/sparc64/config.in	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/config.in	Wed Nov 18 09:06:05 1998
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.57 1998/09/17 11:05:14 jj Exp $
+# $Id: config.in,v 1.58 1998/11/16 04:47:30 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -224,7 +224,10 @@
 		tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
 		if [ "$CONFIG_PCI" = "y" ]; then
 			tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
-			tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
+# Turned off until updated 3c59x.c driver
+# gets approved by Linus...  --DAVEM
+#
+#			tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
 		fi
 #		bool 'FDDI driver support' CONFIG_FDDI
 #		if [ "$CONFIG_FDDI" = "y" ]; then
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.128/linux/arch/sparc64/defconfig	Sun Nov  8 14:02:46 1998
+++ linux/arch/sparc64/defconfig	Wed Nov 18 09:06:05 1998
@@ -74,6 +74,7 @@
 # CONFIG_SPARCAUDIO_AMD7930 is not set
 # CONFIG_SPARCAUDIO_CS4231 is not set
 # CONFIG_SPARCAUDIO_DBRI is not set
+# CONFIG_SPARCAUDIO_DUMMY is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
@@ -198,7 +199,7 @@
 # CONFIG_AIC7XXX_PROC_STATS is not set
 CONFIG_AIC7XXX_RESET_DELAY=5
 CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=10
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
@@ -238,7 +239,6 @@
 CONFIG_SUNQE=m
 CONFIG_MYRI_SBUS=m
 CONFIG_DE4X5=m
-CONFIG_VORTEX=m
 
 #
 # Filesystems
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.128/linux/arch/sparc64/kernel/ioctl32.c	Sun Nov  8 14:02:46 1998
+++ linux/arch/sparc64/kernel/ioctl32.c	Wed Nov 18 09:06:05 1998
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $
+/* $Id: ioctl32.c,v 1.55 1998/11/17 07:43:17 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -34,6 +34,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <linux/fb.h>
+#include <linux/ext2_fs.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -52,6 +53,8 @@
 #include <asm/envctrl.h>
 #include <asm/audioio.h>
 
+#include <linux/soundcard.h>
+
 /* Use this to get at 32-bit user passed pointers. 
    See sys_sparc32.c for description about these. */
 #define A(__x) ((unsigned long)(__x))
@@ -63,6 +66,12 @@
 	__ret;				\
 })
 
+/* Aiee. Someone does not find a difference between int and long */
+#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
+
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -94,6 +103,18 @@
 		return -EFAULT;
 	return err;
 }
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* These are just misnamed, they actually get/put from/to user an int */
+	switch (cmd) {
+	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+	}
+	return sys_ioctl(fd, cmd, arg);
+}
  
 struct timeval32 {
 	int tv_sec;
@@ -1551,6 +1572,13 @@
 		error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg);
 		goto out;
 		
+	case EXT2_IOC32_GETFLAGS:
+	case EXT2_IOC32_SETFLAGS:
+	case EXT2_IOC32_GETVERSION:
+	case EXT2_IOC32_SETVERSION:
+		error = do_ext2_ioctl(fd, cmd, arg);
+		goto out;
+		
 	/* List here exlicitly which ioctl's are known to have
 	 * compatable types passed or none at all...
 	 */
@@ -1859,13 +1887,159 @@
 	case AUDIO_GETDEV_SUNOS:
 	case AUDIO_FLUSH:
 
+	/* Big Q for sound/OSS */
+	case SNDCTL_SEQ_RESET:
+	case SNDCTL_SEQ_SYNC:
+	case SNDCTL_SYNTH_INFO:
+	case SNDCTL_SEQ_CTRLRATE:
+	case SNDCTL_SEQ_GETOUTCOUNT:
+	case SNDCTL_SEQ_GETINCOUNT:
+	case SNDCTL_SEQ_PERCMODE:
+	case SNDCTL_FM_LOAD_INSTR:
+	case SNDCTL_SEQ_TESTMIDI:
+	case SNDCTL_SEQ_RESETSAMPLES:
+	case SNDCTL_SEQ_NRSYNTHS:
+	case SNDCTL_SEQ_NRMIDIS:
+	case SNDCTL_MIDI_INFO:
+	case SNDCTL_SEQ_THRESHOLD:
+	case SNDCTL_SYNTH_MEMAVL:
+	case SNDCTL_FM_4OP_ENABLE:
+	case SNDCTL_SEQ_PANIC:
+	case SNDCTL_SEQ_OUTOFBAND:
+	case SNDCTL_SEQ_GETTIME:
+	case SNDCTL_SYNTH_ID:
+	case SNDCTL_SYNTH_CONTROL:
+	case SNDCTL_SYNTH_REMOVESAMPLE:
+
+	/* Big T for sound/OSS */
+	case SNDCTL_TMR_TIMEBASE:
+	case SNDCTL_TMR_START:
+	case SNDCTL_TMR_STOP:
+	case SNDCTL_TMR_CONTINUE:
+	case SNDCTL_TMR_TEMPO:
+	case SNDCTL_TMR_SOURCE:
+	case SNDCTL_TMR_METRONOME:
+	case SNDCTL_TMR_SELECT:
+
+	/* Little m for sound/OSS */
+	case SNDCTL_MIDI_PRETIME:
+	case SNDCTL_MIDI_MPUMODE:
+	case SNDCTL_MIDI_MPUCMD:
+
+	/* Big P for sound/OSS */
+	case SNDCTL_DSP_RESET:
+	case SNDCTL_DSP_SYNC:
+	case SNDCTL_DSP_SPEED:
+	case SNDCTL_DSP_STEREO:
+	case SNDCTL_DSP_GETBLKSIZE:
+	case SNDCTL_DSP_CHANNELS:
+	case SOUND_PCM_WRITE_FILTER:
+	case SNDCTL_DSP_POST:
+	case SNDCTL_DSP_SUBDIVIDE:
+	case SNDCTL_DSP_SETFRAGMENT:
+	case SNDCTL_DSP_GETFMTS:
+	case SNDCTL_DSP_SETFMT:
+	case SNDCTL_DSP_GETOSPACE:
+	case SNDCTL_DSP_GETISPACE:
+	case SNDCTL_DSP_NONBLOCK:
+	case SNDCTL_DSP_GETCAPS:
+	case SNDCTL_DSP_GETTRIGGER:
+	case SNDCTL_DSP_SETTRIGGER:
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+	/* case SNDCTL_DSP_MAPINBUF: XXX needs translation */
+	/* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */
+	case SNDCTL_DSP_SETSYNCRO:
+	case SNDCTL_DSP_SETDUPLEX:
+	case SNDCTL_DSP_GETODELAY:
+	case SNDCTL_DSP_PROFILE:
+
+	case SOUND_PCM_READ_RATE:
+	case SOUND_PCM_READ_CHANNELS:
+	case SOUND_PCM_READ_BITS:
+	case SOUND_PCM_READ_FILTER:
+
+	/* Big C for sound/OSS */
+	case SNDCTL_COPR_RESET:
+	case SNDCTL_COPR_LOAD:
+	case SNDCTL_COPR_RDATA:
+	case SNDCTL_COPR_RCODE:
+	case SNDCTL_COPR_WDATA:
+	case SNDCTL_COPR_WCODE:
+	case SNDCTL_COPR_RUN:
+	case SNDCTL_COPR_HALT:
+	case SNDCTL_COPR_SENDMSG:
+	case SNDCTL_COPR_RCVMSG:
+
+	/* Big M for sound/OSS */
+	case SOUND_MIXER_READ_VOLUME:
+	case SOUND_MIXER_READ_BASS:
+	case SOUND_MIXER_READ_TREBLE:
+	case SOUND_MIXER_READ_SYNTH:
+	case SOUND_MIXER_READ_PCM:
+	case SOUND_MIXER_READ_SPEAKER:
+	case SOUND_MIXER_READ_LINE:
+	case SOUND_MIXER_READ_MIC:
+	case SOUND_MIXER_READ_CD:
+	case SOUND_MIXER_READ_IMIX:
+	case SOUND_MIXER_READ_ALTPCM:
+	case SOUND_MIXER_READ_RECLEV:
+	case SOUND_MIXER_READ_IGAIN:
+	case SOUND_MIXER_READ_OGAIN:
+	case SOUND_MIXER_READ_LINE1:
+	case SOUND_MIXER_READ_LINE2:
+	case SOUND_MIXER_READ_LINE3:
+	case SOUND_MIXER_READ_MUTE:
+	/* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */
+	/* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */
+	case SOUND_MIXER_READ_RECSRC:
+	case SOUND_MIXER_READ_DEVMASK:
+	case SOUND_MIXER_READ_RECMASK:
+	case SOUND_MIXER_READ_STEREODEVS:
+	case SOUND_MIXER_READ_CAPS:
+
+	case SOUND_MIXER_WRITE_VOLUME:
+	case SOUND_MIXER_WRITE_BASS:
+	case SOUND_MIXER_WRITE_TREBLE:
+	case SOUND_MIXER_WRITE_SYNTH:
+	case SOUND_MIXER_WRITE_PCM:
+	case SOUND_MIXER_WRITE_SPEAKER:
+	case SOUND_MIXER_WRITE_LINE:
+	case SOUND_MIXER_WRITE_MIC:
+	case SOUND_MIXER_WRITE_CD:
+	case SOUND_MIXER_WRITE_IMIX:
+	case SOUND_MIXER_WRITE_ALTPCM:
+	case SOUND_MIXER_WRITE_RECLEV:
+	case SOUND_MIXER_WRITE_IGAIN:
+	case SOUND_MIXER_WRITE_OGAIN:
+	case SOUND_MIXER_WRITE_LINE1:
+	case SOUND_MIXER_WRITE_LINE2:
+	case SOUND_MIXER_WRITE_LINE3:
+	case SOUND_MIXER_WRITE_MUTE:
+	/* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */
+	/* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */
+	case SOUND_MIXER_WRITE_RECSRC:
+
+	case SOUND_MIXER_INFO:
+	case SOUND_OLD_MIXER_INFO:
+	case SOUND_MIXER_ACCESS:
+	case SOUND_MIXER_PRIVATE1:
+	case SOUND_MIXER_PRIVATE2:
+	case SOUND_MIXER_PRIVATE3:
+	case SOUND_MIXER_PRIVATE4:
+	case SOUND_MIXER_PRIVATE5:
+	case SOUND_MIXER_GETLEVELS:
+	case SOUND_MIXER_SETLEVELS:
+
+	case OSS_GETVERSION:
+
 	/* AUTOFS */
 	case AUTOFS_IOC_READY:
 	case AUTOFS_IOC_FAIL:
 	case AUTOFS_IOC_CATATONIC:
 	case AUTOFS_IOC_PROTOVER:
 	case AUTOFS_IOC_EXPIRE:
-
+	
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
 
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- v2.1.128/linux/arch/sparc64/kernel/psycho.c	Sun Nov  8 14:02:46 1998
+++ linux/arch/sparc64/kernel/psycho.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $
+/* $Id: psycho.c,v 1.66 1998/11/02 22:27:45 davem Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1406,9 +1406,9 @@
 	dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device);
 	for(preg = 0; preg < 6; preg++) {
 		if(pdev->base_address[preg] != 0)
-			prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]);
+			dprintf("%d[%016lx] ", preg, pdev->base_address[preg]);
 	}
-	prom_printf("\n");
+	dprintf("\n");
 #endif
 }
 
@@ -1930,8 +1930,8 @@
 out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn)
 {
 	return ((pbm->parent == 0) ||
-		((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 4) ||
-		((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 6) ||
+		((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) ||
+		((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) ||
 		(pci_probe_enable == 0));
 }
 
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.128/linux/arch/sparc64/kernel/rtrap.S	Sun Nov  8 14:02:47 1998
+++ linux/arch/sparc64/kernel/rtrap.S	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $
+/* $Id: rtrap.S,v 1.45 1998/11/09 15:33:29 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -172,7 +172,13 @@
 		wrpr			%l7, PSTATE_IE, %pstate
 		call			update_perfctrs
 		 nop
-		ba,a,pt			%xcc, check_user_wins
+		wrpr			%l7, 0x0, %pstate
+		lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+		brz,pt			%o2, 1f
+		 sethi			%hi(TSTATE_PEF), %l6
+		wrpr			%l7, PSTATE_IE, %pstate
+		call			fault_in_user_windows
+		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
 
 1:
 		andcc			%l1, %l6, %g0
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.1.128/linux/arch/sparc64/kernel/sparc64_ksyms.c	Sun Nov  8 14:02:47 1998
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.49 1998/10/28 08:11:28 jj Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -257,6 +257,9 @@
 EXPORT_SYMBOL(prom_cpu_nodes);
 EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys32_ioctl);
+EXPORT_SYMBOL(get_unmapped_area);
+EXPORT_SYMBOL(move_addr_to_kernel);
+EXPORT_SYMBOL(move_addr_to_user);
 #endif
 
 /* Special internal versions of library functions. */
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sys32.S linux/arch/sparc64/kernel/sys32.S
--- v2.1.128/linux/arch/sparc64/kernel/sys32.S	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/sys32.S	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.7 1998/09/11 10:39:46 jj Exp $
+/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
@@ -13,16 +13,10 @@
 	.align		32
 	.globl		sys32_mmap
 sys32_mmap:
-	srl		%o0, 0, %o0			! IEU0	Group
-	sethi		%hi(0xffffffff), %g2		! IEU1
-	srl		%o1, 0, %o1			! IEU0	Group
-	or		%g2, %lo(0xffffffff), %g2	! IEU1
-	srl		%o2, 0, %o2			! IEU0	Group
-	sethi		%hi(sys_mmap), %g1		! IEU1
-	and		%o3, %g2, %o3			! IEU0	Group
-	and		%o4, %g2, %o4			! IEU1
-	jmpl		%g1 + %lo(sys_mmap), %g0	! CTI	Group brk forced
-	 and		%o5, %g2, %o5			! IEU0
+	srl		%o4, 0, %o4
+	sethi		%hi(sys_mmap), %g1
+	jmpl		%g1 + %lo(sys_mmap), %g0
+	 srl		%o5, 0, %o5
 
 	.align		32
 	.globl		sys32_lseek
@@ -36,14 +30,12 @@
 	sethi		%hi(0xffff), %g2
 	sethi		%hi(sys_chmod), %g1
 	orcc		%g2, %lo(0xffff), %g2
-	srl		%o0, 0, %o0
 	jmpl		%g1 + %lo(sys_chmod), %g0
 	 and		%o1, %g2, %o1
 sys32_chown:
 	sethi		%hi(0xffff), %g2
 	sethi		%hi(sys_chown), %g1
 	orcc		%g2, %lo(0xffff), %g2
-	srl		%o0, 0, %o0
 	and		%o1, %g2, %o1
 	jmpl		%g1 + %lo(sys_chown), %g0
 	 and		%o2, %g2, %o2
@@ -51,7 +43,6 @@
 	sethi		%hi(0xffff), %g2
 	sethi		%hi(sys_lchown), %g1
 	orcc		%g2, %lo(0xffff), %g2
-	srl		%o0, 0, %o0
 	and		%o1, %g2, %o1
 	jmpl		%g1 + %lo(sys_lchown), %g0
 	 and		%o2, %g2, %o2
@@ -59,27 +50,21 @@
 	sethi		%hi(0xffff), %g2
 	sethi		%hi(sys_mknod), %g1
 	orcc		%g2, %lo(0xffff), %g2
-	srl		%o0, 0, %o0
 	jmpl		%g1 + %lo(sys_mknod), %g0
 	 and		%o2, %g2, %o2
 
 	.align		32
 	.globl		sys32_sendto, sys32_recvfrom, sys32_getsockopt
 sys32_sendto:
-	srl		%o1, 0, %o1
 	sethi		%hi(sys_sendto), %g1
-	srl		%o2, 0, %o2
 	jmpl		%g1 + %lo(sys_sendto), %g0
 	 srl		%o4, 0, %o4
 sys32_recvfrom:
-	srl		%o1, 0, %o1
-	sethi		%hi(sys_recvfrom), %g1
-	srl		%o2, 0, %o2
 	srl		%o4, 0, %o4
+	sethi		%hi(sys_recvfrom), %g1
 	jmpl		%g1 + %lo(sys_recvfrom), %g0
 	 srl		%o5, 0, %o5
 sys32_getsockopt:
-	srl		%o3, 0, %o3
 	sethi		%hi(sys_getsockopt), %g1
 	jmpl		%g1 + %lo(sys_getsockopt), %g0
 	 srl		%o4, 0, %o4
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.128/linux/arch/sparc64/kernel/sys_sparc32.c	Sun Nov  8 14:02:47 1998
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $
+/* $Id: sys_sparc32.c,v 1.100 1998/11/08 11:14:00 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1110,10 +1110,11 @@
 {
 	fd_set_buffer *fds;
 	struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x);
-	unsigned long timeout, nn;
+	unsigned long nn;
+	long timeout;
 	int ret;
 
-	timeout = ~0UL;
+	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
 
@@ -1124,8 +1125,6 @@
 
 		timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
 		timeout += sec * HZ;
-		if (timeout)
-			timeout += jiffies + 1;
 	}
 
 	ret = -ENOMEM;
@@ -1147,12 +1146,11 @@
 	zero_fd_set(n, fds->res_out);
 	zero_fd_set(n, fds->res_ex);
 
-	ret = do_select(n, fds, timeout);
+	ret = do_select(n, fds, &timeout);
 
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		unsigned long timeout = current->timeout - jiffies - 1;
 		time_t sec = 0, usec = 0;
-		if ((long) timeout > 0) {
+		if (timeout) {
 			sec = timeout / HZ;
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
@@ -1160,7 +1158,6 @@
 		put_user(sec, &tvp->tv_sec);
 		put_user(usec, &tvp->tv_usec);
 	}
-	current->timeout = 0;
 
 	if (ret < 0)
 		goto out;
@@ -3533,15 +3530,15 @@
 typedef __kernel_ssize_t32 ssize_t32;
 
 asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
-				 __kernel_size_t32 count, u32 pos)
+				 __kernel_size_t32 count, u32 poshi, u32 poslo)
 {
-	return sys_pread(fd, ubuf, count, pos);
+	return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
 asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
-				  __kernel_size_t32 count, u32 pos)
+				  __kernel_size_t32 count, u32 poshi, u32 poslo)
 {
-	return sys_pwrite(fd, ubuf, count, pos);
+	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
 
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.128/linux/arch/sparc64/mm/fault.c	Sun Nov  8 14:02:49 1998
+++ linux/arch/sparc64/mm/fault.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $
+/* $Id: fault.c,v 1.26 1998/11/08 11:14:03 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -155,7 +155,8 @@
 			goto bad_area;
 	}
 	current->mm->segments = (void *) (address & PAGE_SIZE);
-	handle_mm_fault(current, vma, address, write);
+	if (!handle_mm_fault(current, vma, address, write))
+		goto do_sigbus;
 	up(&mm->mmap_sem);
 	return;
 	/*
@@ -165,6 +166,7 @@
 bad_area:
 	up(&mm->mmap_sem);
 
+do_kernel_fault:
 	{
 		unsigned long g2 = regs->u_regs[UREG_G2];
 
@@ -204,4 +206,13 @@
 		}
 		unhandled_fault (address, current, regs);
 	}
+	return;
+
+do_sigbus:
+	up(&mm->mmap_sem);
+	current->tss.sig_address = address;
+	current->tss.sig_desc = SUBSIG_MISCERROR;
+	force_sig(SIGBUS, current);
+	if (regs->tstate & TSTATE_PRIV)
+		goto do_kernel_fault;
 }
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c
--- v2.1.128/linux/arch/sparc64/mm/generic.c	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/mm/generic.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.2 1997/07/01 09:11:42 jj Exp $
+/* $Id: generic.c,v 1.3 1998/10/27 23:28:07 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -41,10 +41,11 @@
 		unsigned long addr = pte_page(page);
 		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
 			return;
-		free_page(addr);
-		if (current->mm->rss <= 0)
-			return;
-		current->mm->rss--;
+		/* 
+		 * free_page() used to be able to clear swap cache
+		 * entries.  We may now have to do it manually.  
+		 */
+		free_page_and_swap_cache(addr);
 		return;
 	}
 	swap_free(pte_val(page));
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.1.128/linux/arch/sparc64/mm/ultra.S	Sun Nov  8 14:02:50 1998
+++ linux/arch/sparc64/mm/ultra.S	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $
+/* $Id: ultra.S,v 1.31 1998/11/07 06:39:21 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -62,35 +62,37 @@
 	and		%o4, 0x3ff, %o5
 	cmp		%o5, %o0
 	bne,pt		%icc, 2f
-	 andn		%o4, 0x3ff, %o4
-/*IC6*/	cmp		%o4, %o1
+/*IC6*/	 andn		%o4, 0x3ff, %o4
+	cmp		%o4, %o1
 	blu,pt		%xcc, 2f
 	 cmp		%o4, %o3
 	blu,pn		%xcc, 4f
 2:	 ldxa		[%g2] ASI_DTLB_TAG_READ, %o4
 	and		%o4, 0x3ff, %o5
 	cmp		%o5, %o0
-	andn		%o4, 0x3ff, %o4
-/*IC7*/	bne,pt		%icc, 3f
+/*IC7*/	andn		%o4, 0x3ff, %o4
+	bne,pt		%icc, 3f
 	 cmp		%o4, %o1
 	blu,pt		%xcc, 3f
 	 cmp		%o4, %o3
 	blu,pn		%xcc, 5f
 	 nop
 3:	brnz,pt		%g2, 1b
-	 sub		%g2, (1 << 3), %g2
-/*IC8*/	retl
+/*IC8*/	 sub		%g2, (1 << 3), %g2
+	retl
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
 	stxa		%g0, [%g2] ASI_ITLB_DATA_ACCESS
 	ba,pt		%xcc, 2b
 	 flush		%g6
 5:	stxa		%g0, [%g3] ASI_DMMU
-	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+/*IC9*/	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
 	ba,pt		%xcc, 3b
 	 flush		%g6
+
+	.align		32
 __flush_tlb_mm_slow:
-/*IC9*/	rdpr		%pstate, %g1
+/*IC10*/rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o1] ASI_DMMU
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
@@ -98,21 +100,25 @@
 	flush		%g6
 	stxa		%g2, [%o1] ASI_DMMU
 	flush		%g6
-/*IC10*/retl
+/*IC11*/retl
 	 wrpr		%g1, 0, %pstate
+
+	.align		32
 __flush_tlb_page_slow:
-	rdpr		%pstate, %g1
+/*IC12*/rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	flush		%g6
-/*IC11*/stxa		%g2, [%o2] ASI_DMMU
+	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
-	retl
+/*IC13*/retl
 	 wrpr		%g1, 0, %pstate
+
+	.align		32
 __flush_tlb_range_pbp_slow:
-	rdpr		%pstate, %g1
+/*IC13*/rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o2] ASI_DMMU
 2:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
@@ -120,7 +126,7 @@
 	brnz,pt		%o5, 2b
 	 sub		%o5, %o4, %o5
 	flush		%g6
-/*IC13*/stxa		%g2, [%o2] ASI_DMMU
+/*IC14*/stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
 	 wrpr		%g1, 0x0, %pstate
@@ -128,24 +134,26 @@
 	.align		32
 	.globl		flush_icache_page
 flush_icache_page:	/* %o0 = phys_page */
-	sethi		%hi(1 << 13), %o2	! I-cache valid/set bit
+	sethi		%hi(1 << 13), %o2	! IC_set bit
+	mov		1, %g1
 	srlx		%o0, 5, %o0		! phys-addr comparitor
-	clr		%o1			! I-cache address
+	clr		%o1			! IC_addr
+	sllx		%g1, 36, %g1
+	sub		%g1, 1, %g2
+	andn		%g2, 0xff, %g2		! IC_tag mask
+	nop
+
 1:	ldda		[%o1] ASI_IC_TAG, %o4
-	andcc		%o5, %o2, %g0
-	be,pn		%xcc, 2f
-	 andn		%o5, %o2, %o5
+	and		%o5, %g2, %o5
 	cmp		%o5, %o0
-
 	be,pn		%xcc, iflush1
-2:	 ldda		[%o1 + %o2] ASI_IC_TAG, %o4
-4:	andcc		%o5, %o2, %g0
-	be,pn		%xcc, 3f
-	 andn		%o5, %o2, %o5
+	 nop
+2:	ldda		[%o1 + %o2] ASI_IC_TAG, %o4
+	and		%o5, %g2, %o5
 	cmp		%o5, %o0
+
 	be,pn		%xcc, iflush2
 	 nop
-
 3:	add		%o1, 0x20, %o1
 	cmp		%o1, %o2
 	bne,pt		%xcc, 1b
@@ -153,11 +161,11 @@
 	retl
 	 nop
 iflush1:stxa		%g0, [%o1] ASI_IC_TAG
-	membar		#Sync
-	ba,a,pt		%xcc, 4b
+	ba,pt		%xcc, 2b
+	 flush		%g6
 iflush2:stxa		%g0, [%o1 + %o2] ASI_IC_TAG
-	membar		#Sync
-	ba,a,pt		%xcc, 3b
+	ba,pt		%xcc, 3b
+	 flush		%g6
 
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile
--- v2.1.128/linux/arch/sparc64/solaris/Makefile	Sun Nov  8 14:02:50 1998
+++ linux/arch/sparc64/solaris/Makefile	Mon Nov 16 10:37:28 1998
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := solaris.o
-O_OBJS   := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o timod.o
+O_OBJS   := entry64.o fs.o misc.o signal.o systbl.o socket.o ioctl.o ipc.o socksys.o timod.o
 ifeq ($(CONFIG_SOLARIS_EMUL),m)
 M_OBJS   := $(O_TARGET)
 CPPFLAGS = $(MODFLAGS)
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.1.128/linux/arch/sparc64/solaris/fs.c	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/solaris/fs.c	Mon Nov 16 10:37:28 1998
@@ -1,7 +1,7 @@
-/* $Id: fs.c,v 1.10 1998/05/09 06:15:45 davem Exp $
+/* $Id: fs.c,v 1.11 1998/10/28 08:12:04 jj Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/types.h>
@@ -55,6 +55,26 @@
 	s32		st_pad4[8];     /* expansion area */
 };
 
+struct sol_stat64 {
+	u32		st_dev;
+	s32		st_pad1[3];     /* network id */
+	u64		st_ino;
+	u32		st_mode;
+	u32		st_nlink;
+	u32		st_uid;
+	u32		st_gid;
+	u32		st_rdev;
+	s32		st_pad2[2];
+	s64		st_size;
+	timestruct_t	st_atime;
+	timestruct_t	st_mtime;
+	timestruct_t	st_ctime;
+	s64		st_blksize;
+	s32		st_blocks;
+	char		st_fstype[16];
+	s32		st_pad4[4];     /* expansion area */
+};
+
 #define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
 
 static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf)
@@ -80,6 +100,29 @@
 	return 0;
 }
 
+static inline int putstat64(struct sol_stat64 *ubuf, struct stat *kbuf)
+{
+	if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev)	||
+	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
+	    __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev)	||
+	    __put_user (kbuf->st_size, &ubuf->st_size)		||
+	    __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec)	||
+	    __put_user (0, &ubuf->st_atime.tv_nsec)		||
+	    __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec)	||
+	    __put_user (0, &ubuf->st_mtime.tv_nsec)		||
+	    __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec)	||
+	    __put_user (0, &ubuf->st_ctime.tv_nsec)		||
+	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->st_blocks, &ubuf->st_blocks)	||
+	    __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
+		return -EFAULT;
+	return 0;
+}
+
 asmlinkage int solaris_stat(u32 filename, u32 statbuf)
 {
 	int ret;
@@ -108,6 +151,28 @@
 	return solaris_stat(filename, statbuf);
 }
 
+asmlinkage int solaris_stat64(u32 filename, u32 statbuf)
+{
+	int ret;
+	struct stat s;
+	char *filenam;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_newstat)(char *,struct stat *) = 
+		(int (*)(char *,struct stat *))SYS(stat);
+	
+	filenam = getname32 (filename);
+	ret = PTR_ERR(filenam);
+	if (!IS_ERR(filenam)) {
+		set_fs (KERNEL_DS);
+		ret = sys_newstat(filenam, &s);
+		set_fs (old_fs);
+		putname32 (filenam);
+		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
+			return -EFAULT;
+	}
+	return ret;
+}
+
 asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
 {
 	int ret;
@@ -135,6 +200,28 @@
 	return solaris_lstat(filename, statbuf);
 }
 
+asmlinkage int solaris_lstat64(u32 filename, u32 statbuf)
+{
+	int ret;
+	struct stat s;
+	char *filenam;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_newlstat)(char *,struct stat *) = 
+		(int (*)(char *,struct stat *))SYS(lstat);
+	
+	filenam = getname32 (filename);
+	ret = PTR_ERR(filenam);
+	if (!IS_ERR(filenam)) {
+		set_fs (KERNEL_DS);
+		ret = sys_newlstat(filenam, &s);
+		set_fs (old_fs);
+		putname32 (filenam);
+		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
+			return -EFAULT;
+	}
+	return ret;
+}
+
 asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
 {
 	int ret;
@@ -156,6 +243,22 @@
 	return solaris_fstat(fd, statbuf);
 }
 
+asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_newfstat)(unsigned,struct stat *) = 
+		(int (*)(unsigned,struct stat *))SYS(fstat);
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newfstat(fd, &s);
+	set_fs (old_fs);
+	if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
+		return -EFAULT;
+	return ret;
+}
+
 asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev)
 {
 	int (*sys_mknod)(const char *,int,dev_t) = 
@@ -172,6 +275,14 @@
 	return solaris_mknod(path, mode, dev);
 }
 
+asmlinkage int solaris_getdents64(unsigned int fd, void *dirent, unsigned int count)
+{
+	int (*sys_getdents)(unsigned int, void *, unsigned int) =
+		(int (*)(unsigned int, void *, unsigned int))SYS(getdents);
+		
+	return sys_getdents(fd, dirent, count);
+}
+
 /* This statfs thingie probably will go in the near future, but... */
 
 struct sol_statfs {
@@ -276,6 +387,23 @@
 	u32	f_filler[16];
 };
 
+struct sol_statvfs64 {
+	u32	f_bsize;
+	u32	f_frsize;
+	u64	f_blocks;
+	u64	f_bfree;
+	u64	f_bavail;
+	u64	f_files;
+	u64	f_ffree;
+	u64	f_favail;
+	u32	f_fsid;
+	char	f_basetype[16];
+	u32	f_flag;
+	u32	f_namemax;
+	char	f_fstr[32];
+	u32	f_filler[16];
+};
+
 static int report_statvfs(struct inode *inode, u32 buf)
 {
 	struct statfs s;
@@ -313,6 +441,43 @@
 	return error;
 }
 
+static int report_statvfs64(struct inode *inode, u32 buf)
+{
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	int error;
+	struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
+			
+	set_fs (KERNEL_DS);
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
+	set_fs (old_fs);
+	if (!error) {
+		const char *p = inode->i_sb->s_type->name;
+		int i = 0;
+		int j = strlen (p);
+		
+		if (j > 15) j = 15;
+		if (IS_RDONLY(inode)) i = 1;
+		if (IS_NOSUID(inode)) i |= 2;
+		if (put_user (s.f_bsize, &ss->f_bsize)		||
+		    __put_user (0, &ss->f_frsize)		||
+		    __put_user (s.f_blocks, &ss->f_blocks)	||
+		    __put_user (s.f_bfree, &ss->f_bfree)	||
+		    __put_user (s.f_bavail, &ss->f_bavail)	||
+		    __put_user (s.f_files, &ss->f_files)	||
+		    __put_user (s.f_ffree, &ss->f_ffree)	||
+		    __put_user (s.f_ffree, &ss->f_favail)	||
+		    __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+		    __copy_to_user (ss->f_basetype,p,j)		||
+		    __put_user (0, (char *)&ss->f_basetype[j])	||
+		    __put_user (s.f_namelen, &ss->f_namemax)	||
+		    __put_user (i, &ss->f_flag)			||		    
+		    __clear_user (&ss->f_fstr, 32))
+			return -EFAULT;
+	}
+	return error;
+}
+
 asmlinkage int solaris_statvfs(u32 path, u32 buf)
 {
 	struct dentry * dentry;
@@ -362,12 +527,62 @@
 	return error;
 }
 
+asmlinkage int solaris_statvfs64(u32 path, u32 buf)
+{
+	struct dentry * dentry;
+	int error;
+
+	lock_kernel();
+	dentry = namei((const char *)A(path));
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+
+		error = -ENOSYS;
+		if (inode->i_sb->s_op->statfs)
+			error = report_statvfs64(inode, buf);
+		dput(dentry);
+	}
+	unlock_kernel();
+	return error;
+}
+
+asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
+{
+	struct inode * inode;
+	struct dentry * dentry;
+	struct file * file;
+	int error;
+
+	lock_kernel();
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	if (!(dentry = file->f_dentry))
+		error = -ENOENT;
+	else if (!(inode = dentry->d_inode))
+		error = -ENOENT;
+	else if (!inode->i_sb)
+		error = -ENODEV;
+	else if (!inode->i_sb->s_op->statfs)
+		error = -ENOSYS;
+	else
+		error = report_statvfs64(inode, buf);
+	fput(file);
+out:
+	unlock_kernel();
+	return error;
+}
+
 asmlinkage int solaris_open(u32 filename, int flags, u32 mode)
 {
 	int (*sys_open)(const char *,int,int) = 
 		(int (*)(const char *,int,int))SYS(open);
 	int fl = flags & 0xf;
-	
+
+/*	if (flags & 0x2000) - allow LFS			*/
 	if (flags & 0x8050) fl |= O_SYNC;
 	if (flags & 0x80) fl |= O_NONBLOCK;
 	if (flags & 0x100) fl |= O_CREAT;
@@ -558,78 +773,20 @@
 	return -ENOSYS;
 }
 
-asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset)
+asmlinkage int solaris_pread(unsigned int fd, char *buf, u32 count, u32 pos)
 {
-	off_t temp;
-	int retval;
-	struct file * file;
-	long (*sys_read)(unsigned int, char *, unsigned long) =
-		(long (*)(unsigned int, char *, unsigned long))SYS(read);
-	long (*sys_lseek)(unsigned int, off_t, unsigned int) =
-		(long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
-	
-	lock_kernel();
-	retval = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto bad;
-
-	temp = file->f_pos;
-	if (temp != offset) {
-		retval = sys_lseek(fd, offset, 0);
-		if (retval < 0)
-			goto out_putf;
-	}
-	retval = sys_read(fd, (char *)A(buf), nbyte);
-	if (file->f_pos != temp) {
-		if (!retval)
-			retval = sys_lseek(fd, temp, 0);
-		else
-			sys_lseek(fd, temp, 0);
-	}
-
-out_putf:
-	fput(file);
-bad:
-	unlock_kernel();
-	return retval;
+	ssize_t (*sys_pread)(unsigned int, char *, size_t, loff_t) =
+		(ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pread);
+		
+	return sys_pread(fd, buf, count, (loff_t)pos);
 }
 
-asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset)
+asmlinkage int solaris_pwrite(unsigned int fd, char *buf, u32 count, u32 pos)
 {
-	off_t temp;
-	int retval;
-	struct file * file;
-	long (*sys_write)(unsigned int, char *, unsigned long) =
-		(long (*)(unsigned int, char *, unsigned long))SYS(read);
-	long (*sys_lseek)(unsigned int, off_t, unsigned int) =
-		(long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
-	
-	lock_kernel();
-	retval = -EBADF;
-        file = fget(fd);
-	if (!file)
-		goto bad;
-
-	temp = file->f_pos;
-	if (temp != offset) {
-		retval = sys_lseek(fd, offset, 0);
-		if (retval < 0)
-			goto out_putf;
-	}
-	retval = sys_write(fd, (char *)A(buf), nbyte);
-	if (file->f_pos != temp) {
-		if (!retval)
-			retval = sys_lseek(fd, temp, 0);
-		else
-			sys_lseek(fd, temp, 0);
-	}
-
-out_putf:
-	fput(file);
-bad:
-	unlock_kernel();
-	return retval;
+	ssize_t (*sys_pwrite)(unsigned int, char *, size_t, loff_t) =
+		(ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pwrite);
+		
+	return sys_pwrite(fd, buf, count, (loff_t)pos);
 }
 
 /* POSIX.1 names */
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.1.128/linux/arch/sparc64/solaris/misc.c	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/solaris/misc.c	Mon Nov 16 10:37:28 1998
@@ -1,7 +1,7 @@
-/* $Id: misc.c,v 1.12 1998/06/16 04:37:08 davem Exp $
+/* $Id: misc.c,v 1.13 1998/10/28 08:11:58 jj Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/module.h> 
@@ -11,6 +11,9 @@
 #include <linux/limits.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/timex.h>
 
 #include <asm/uaccess.h>
 #include <asm/string.h>
@@ -43,16 +46,86 @@
 /* 120 */ 22, 22, 88, 86, 85, 22, 22,
 };
 
+#define SOLARIS_NR_OPEN	256
+
+static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 off)
+{
+	struct file *file = NULL;
+	unsigned long retval, ret_type;
+
+	lock_kernel();
+	current->personality |= PER_SVR4;
+	if (flags & MAP_NORESERVE) {
+		static int cnt = 0;
+		
+		if (cnt < 5) {
+			printk("%s:  unimplemented Solaris MAP_NORESERVE mmap() flag\n",
+			       current->comm);
+			cnt++;
+		}
+		flags &= ~MAP_NORESERVE;
+	}
+	retval = -EBADF;
+	if(!(flags & MAP_ANONYMOUS)) {
+		if(fd >= SOLARIS_NR_OPEN)
+			goto out;
+ 		file = fget(fd);
+		if (!file)
+			goto out;
+		if (file->f_dentry && file->f_dentry->d_inode) {
+			struct inode * inode = file->f_dentry->d_inode;
+			if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
+			   MINOR(inode->i_rdev) == 5) {
+				flags |= MAP_ANONYMOUS;
+				fput(file);
+				file = NULL;
+			}
+		}
+	}
+
+	retval = -ENOMEM;
+	if(!(flags & MAP_FIXED) && !addr) {
+		unsigned long attempt = get_unmapped_area(addr, len);
+		if(!attempt || (attempt >= 0xf0000000UL))
+			goto out_putf;
+		addr = (u32) attempt;
+	}
+	if(!(flags & MAP_FIXED))
+		addr = 0;
+	ret_type = flags & _MAP_NEW;
+	flags &= ~_MAP_NEW;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	retval = do_mmap(file,
+			 (unsigned long) addr, (unsigned long) len,
+			 (unsigned long) prot, (unsigned long) flags, off);
+	if(!ret_type)
+		retval = ((retval < 0xf0000000) ? 0 : retval);
+out_putf:
+	if (file)
+		fput(file);
+out:
+	unlock_kernel();
+	return (u32) retval;
+}
+
 asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
 {
-	u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) = 
-		(u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71);
-	u32 ret;
+	return do_solaris_mmap(addr, len, prot, flags, fd, (u64) off);
+}
+
+asmlinkage u32 solaris_mmap64(struct pt_regs *regs, u32 len, u32 prot, u32 flags, u32 fd, u32 offhi)
+{
+	u32 offlo;
 	
-	ret = sunos_mmap(addr,len,prot,flags,fd,off);
-	/* sunos_mmap sets personality to PER_BSD */
-	current->personality = PER_SVR4;
-	return ret;
+	if (regs->u_regs[UREG_G1]) {
+		if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x5c)))
+			return -EFAULT;
+	} else {
+		if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x60)))
+			return -EFAULT;
+	}
+	return do_solaris_mmap((u32)regs->u_regs[UREG_I0], len, prot, flags, fd, (((u64)offhi)<<32)|offlo);
 }
 
 asmlinkage int solaris_brk(u32 brk)
@@ -326,6 +399,18 @@
 	}
 }
 
+asmlinkage int solaris_setreuid(s32 ruid, s32 euid)
+{
+	int (*sys_setreuid)(uid_t, uid_t) = (int (*)(uid_t, uid_t))SYS(setreuid);
+	return sys_setreuid(ruid, euid);
+}
+
+asmlinkage int solaris_setregid(s32 rgid, s32 egid)
+{
+	int (*sys_setregid)(gid_t, gid_t) = (int (*)(gid_t, gid_t))SYS(setregid);
+	return sys_setregid(rgid, egid);
+}
+
 asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
 {
 	int ret;
@@ -376,6 +461,257 @@
 		(int (*)(struct timeval *, struct timezone *))SYS(gettimeofday);
 		
 	return sys_gettimeofday((struct timeval *)(u64)tim, NULL);
+}
+
+#define RLIM_SOL_INFINITY32	0x7fffffff
+#define RLIM_SOL_SAVED_MAX32	0x7ffffffe
+#define RLIM_SOL_SAVED_CUR32	0x7ffffffd
+#define RLIM_SOL_INFINITY	((u64)-3)
+#define RLIM_SOL_SAVED_MAX	((u64)-2)
+#define RLIM_SOL_SAVED_CUR	((u64)-1)
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+#define RLIMIT_SOL_NOFILE	5
+#define RLIMIT_SOL_VMEM		6
+
+struct rlimit32 {
+	s32	rlim_cur;
+	s32	rlim_max;
+};
+
+asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_INFINITY)
+			r.rlim_cur = RLIM_SOL_INFINITY32;
+		else if ((u64)r.rlim_cur > RLIM_SOL_INFINITY32)
+			r.rlim_cur = RLIM_SOL_SAVED_CUR32;
+		if (r.rlim_max == RLIM_INFINITY)
+			r.rlim_max = RLIM_SOL_INFINITY32;
+		else if ((u64)r.rlim_max > RLIM_SOL_INFINITY32)
+			r.rlim_max = RLIM_SOL_SAVED_MAX32;
+		ret = put_user (r.rlim_cur, &rlim->rlim_cur);
+		ret |= __put_user (r.rlim_max, &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage int solaris_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r, rold;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
+	int (*sys_setrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(setrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &rold);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_SOL_INFINITY32)
+			r.rlim_cur = RLIM_INFINITY;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_CUR32)
+			r.rlim_cur = rold.rlim_cur;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_MAX32)
+			r.rlim_cur = rold.rlim_max;
+		if (r.rlim_max == RLIM_SOL_INFINITY32)
+			r.rlim_max = RLIM_INFINITY;
+		else if (r.rlim_max == RLIM_SOL_SAVED_CUR32)
+			r.rlim_max = rold.rlim_cur;
+		else if (r.rlim_max == RLIM_SOL_SAVED_MAX32)
+			r.rlim_max = rold.rlim_max;
+		ret = sys_setrlimit(resource, &r);
+	}
+	set_fs (old_fs);
+	return ret;
+}
+
+asmlinkage int solaris_getrlimit64(unsigned int resource, struct rlimit *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_INFINITY)
+			r.rlim_cur = RLIM_SOL_INFINITY;
+		if (r.rlim_max == RLIM_INFINITY)
+			r.rlim_max = RLIM_SOL_INFINITY;
+		ret = put_user (r.rlim_cur, &rlim->rlim_cur);
+		ret |= __put_user (r.rlim_max, &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage int solaris_setrlimit64(unsigned int resource, struct rlimit *rlim)
+{
+	struct rlimit r, rold;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
+	int (*sys_setrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(setrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &rold);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_SOL_INFINITY)
+			r.rlim_cur = RLIM_INFINITY;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_CUR)
+			r.rlim_cur = rold.rlim_cur;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_MAX)
+			r.rlim_cur = rold.rlim_max;
+		if (r.rlim_max == RLIM_SOL_INFINITY)
+			r.rlim_max = RLIM_INFINITY;
+		else if (r.rlim_max == RLIM_SOL_SAVED_CUR)
+			r.rlim_max = rold.rlim_cur;
+		else if (r.rlim_max == RLIM_SOL_SAVED_MAX)
+			r.rlim_max = rold.rlim_max;
+		ret = sys_setrlimit(resource, &r);
+	}
+	set_fs (old_fs);
+	return ret;
+}
+
+struct timeval32 {
+	int tv_sec, tv_usec;
+};
+
+struct sol_ntptimeval {
+	struct timeval32 time;
+	s32 maxerror;
+	s32 esterror;
+};
+
+struct sol_timex {
+	u32 modes;
+	s32 offset;
+	s32 freq;
+	s32 maxerror;
+	s32 esterror;
+	s32 status;
+	s32 constant;
+	s32 precision;
+	s32 tolerance;
+	s32 ppsfreq;
+	s32 jitter;
+	s32 shift;
+	s32 stabil;
+	s32 jitcnt;
+	s32 calcnt;
+	s32 errcnt;
+	s32 stbcnt;
+};
+
+asmlinkage int solaris_ntp_gettime(struct sol_ntptimeval *ntp)
+{
+	int (*sys_adjtimex)(struct timex *) =
+		(int (*)(struct timex *))SYS(adjtimex);
+	struct timex t;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs(KERNEL_DS);
+	t.modes = 0;
+	ret = sys_adjtimex(&t);
+	set_fs(old_fs);
+	if (ret < 0)
+		return ret;
+	ret = put_user (t.time.tv_sec, &ntp->time.tv_sec);
+	ret |= __put_user (t.time.tv_usec, &ntp->time.tv_usec);
+	ret |= __put_user (t.maxerror, &ntp->maxerror);
+	ret |= __put_user (t.esterror, &ntp->esterror);
+	return ret;	                        
+}
+
+asmlinkage int solaris_ntp_adjtime(struct sol_timex *txp)
+{
+	int (*sys_adjtimex)(struct timex *) =
+		(int (*)(struct timex *))SYS(adjtimex);
+	struct timex t;
+	int ret, err;
+	mm_segment_t old_fs = get_fs();
+
+	ret = get_user (t.modes, &txp->modes);
+	ret |= __get_user (t.offset, &txp->offset);
+	ret |= __get_user (t.freq, &txp->freq);
+	ret |= __get_user (t.maxerror, &txp->maxerror);
+	ret |= __get_user (t.esterror, &txp->esterror);
+	ret |= __get_user (t.status, &txp->status);
+	ret |= __get_user (t.constant, &txp->constant);
+	set_fs(KERNEL_DS);
+	ret = sys_adjtimex(&t);
+	set_fs(old_fs);
+	if (ret < 0)
+		return ret;
+	err = put_user (t.offset, &txp->offset);
+	err |= __put_user (t.freq, &txp->freq);
+	err |= __put_user (t.maxerror, &txp->maxerror);
+	err |= __put_user (t.esterror, &txp->esterror);
+	err |= __put_user (t.status, &txp->status);
+	err |= __put_user (t.constant, &txp->constant);
+	err |= __put_user (t.precision, &txp->precision);
+	err |= __put_user (t.tolerance, &txp->tolerance);
+	err |= __put_user (t.ppsfreq, &txp->ppsfreq);
+	err |= __put_user (t.jitter, &txp->jitter);
+	err |= __put_user (t.shift, &txp->shift);
+	err |= __put_user (t.stabil, &txp->stabil);
+	err |= __put_user (t.jitcnt, &txp->jitcnt);
+	err |= __put_user (t.calcnt, &txp->calcnt);
+	err |= __put_user (t.errcnt, &txp->errcnt);
+	err |= __put_user (t.stbcnt, &txp->stbcnt);
+	if (err)
+		return -EFAULT;
+	return ret;
 }
 
 asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/socket.c linux/arch/sparc64/solaris/socket.c
--- v2.1.128/linux/arch/sparc64/solaris/socket.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/solaris/socket.c	Mon Nov 16 10:37:28 1998
@@ -0,0 +1,463 @@
+/* $Id: socket.c,v 1.1 1998/10/28 08:12:11 jj Exp $
+ * socket.c: Socket syscall emulation for Solaris 2.6+
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/socket.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#include "conv.h"
+
+#define SOCK_SOL_STREAM		2
+#define SOCK_SOL_DGRAM		1
+#define SOCK_SOL_RAW		4
+#define SOCK_SOL_RDM		5
+#define SOCK_SOL_SEQPACKET	6
+
+static int socket_check(int family, int type)
+{
+	if (family != PF_UNIX && family != PF_INET)
+		return -ESOCKTNOSUPPORT;
+	switch (type) {
+	case SOCK_SOL_STREAM: type = SOCK_STREAM; break;
+	case SOCK_SOL_DGRAM: type = SOCK_DGRAM; break;
+	case SOCK_SOL_RAW: type = SOCK_RAW; break;
+	case SOCK_SOL_RDM: type = SOCK_RDM; break;
+	case SOCK_SOL_SEQPACKET: type = SOCK_SEQPACKET; break;
+	default: return -EINVAL;
+	}
+	return type;
+}
+
+asmlinkage int solaris_socket(int family, int type, int protocol)
+{
+	int (*sys_socket)(int, int, int) =
+		(int (*)(int, int, int))SYS(socket);
+
+	type = socket_check (family, type);
+	if (type < 0) return type;
+	return sys_socket(family, type, protocol);
+}
+
+asmlinkage int solaris_socketpair(int family, int type, int protocol, int *usockvec)
+{
+	int (*sys_socketpair)(int, int, int, int *) =
+		(int (*)(int, int, int, int *))SYS(socketpair);
+
+	type = socket_check (family, type);
+	if (type < 0) return type;
+	return sys_socketpair(family, type, protocol, usockvec);
+}
+
+asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen)
+{
+	int (*sys_bind)(int, struct sockaddr *, int) =
+		(int (*)(int, struct sockaddr *, int))SUNOS(104);
+
+	return sys_bind(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+{
+	int (*sunos_setsockopt)(int, int, int, u32, int) =
+		(int (*)(int, int, int, u32, int))SUNOS(105);
+
+	return sunos_setsockopt(fd, level, optname, optval, optlen);
+}
+
+asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+{
+	int (*sunos_getsockopt)(int, int, int, u32, u32) =
+		(int (*)(int, int, int, u32, u32))SUNOS(118);
+
+	return sunos_getsockopt(fd, level, optname, optval, optlen);
+}
+
+asmlinkage int solaris_connect(int fd, struct sockaddr *addr, int addrlen)
+{
+	int (*sys_connect)(int, struct sockaddr *, int) =
+		(int (*)(int, struct sockaddr *, int))SYS(connect);
+
+	return sys_connect(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_accept(int fd, struct sockaddr *addr, int *addrlen)
+{
+	int (*sys_accept)(int, struct sockaddr *, int *) =
+		(int (*)(int, struct sockaddr *, int *))SYS(accept);
+
+	return sys_accept(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_listen(int fd, int backlog)
+{
+	int (*sys_listen)(int, int) =
+		(int (*)(int, int))SUNOS(106);
+
+	return sys_listen(fd, backlog);
+}
+
+asmlinkage int solaris_shutdown(int fd, int how)
+{
+	int (*sys_shutdown)(int, int) =
+		(int (*)(int, int))SYS(shutdown);
+
+	return sys_shutdown(fd, how);
+}
+
+#define MSG_SOL_OOB		0x1
+#define MSG_SOL_PEEK		0x2
+#define MSG_SOL_DONTROUTE	0x4
+#define MSG_SOL_EOR		0x8
+#define MSG_SOL_CTRUNC		0x10
+#define MSG_SOL_TRUNC		0x20
+#define MSG_SOL_WAITALL		0x40
+#define MSG_SOL_DONTWAIT	0x80
+
+static int solaris_to_linux_msgflags(int flags)
+{
+	int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
+	
+	if (flags & MSG_SOL_EOR) fl |= MSG_EOR;
+	if (flags & MSG_SOL_CTRUNC) fl |= MSG_CTRUNC;
+	if (flags & MSG_SOL_TRUNC) fl |= MSG_TRUNC;
+	if (flags & MSG_SOL_WAITALL) fl |= MSG_WAITALL;
+	if (flags & MSG_SOL_DONTWAIT) fl |= MSG_DONTWAIT;
+	return fl;
+}
+
+static int linux_to_solaris_msgflags(int flags)
+{
+	int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
+	
+	if (flags & MSG_EOR) fl |= MSG_SOL_EOR;
+	if (flags & MSG_CTRUNC) fl |= MSG_SOL_CTRUNC;
+	if (flags & MSG_TRUNC) fl |= MSG_SOL_TRUNC;
+	if (flags & MSG_WAITALL) fl |= MSG_SOL_WAITALL;
+	if (flags & MSG_DONTWAIT) fl |= MSG_SOL_DONTWAIT;
+	return fl;
+}
+
+asmlinkage int solaris_recvfrom(int s, char *buf, int len, int flags, u32 from, u32 fromlen)
+{
+	int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
+		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
+	
+	return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(from), (int *)A(fromlen));
+}
+
+asmlinkage int solaris_recv(int s, char *buf, int len, int flags)
+{
+	int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
+		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
+	
+	return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
+}
+
+asmlinkage int solaris_sendto(int s, char *buf, int len, int flags, u32 to, u32 tolen)
+{
+	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
+		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto);
+	
+	return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(to), (int *)A(tolen));
+}
+
+asmlinkage int solaris_send(int s, char *buf, int len, int flags)
+{
+	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
+		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto);
+	
+	return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
+}
+
+asmlinkage int solaris_getpeername(int fd, struct sockaddr *addr, int *addrlen)
+{
+	int (*sys_getpeername)(int, struct sockaddr *, int *) =
+		(int (*)(int, struct sockaddr *, int *))SYS(getpeername);
+
+	return sys_getpeername(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_getsockname(int fd, struct sockaddr *addr, int *addrlen)
+{
+	int (*sys_getsockname)(int, struct sockaddr *, int *) =
+		(int (*)(int, struct sockaddr *, int *))SYS(getsockname);
+
+	return sys_getsockname(fd, addr, addrlen);
+}
+
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+/* XXX These as well... */
+extern __inline__ struct socket *socki_lookup(struct inode *inode)
+{
+	return &inode->u.socket_i;
+}
+
+extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
+{
+	struct file *file;
+	struct inode *inode;
+
+	if (!(file = fget(fd))) {
+		*err = -EBADF;
+		return NULL;
+	}
+
+	inode = file->f_dentry->d_inode;
+	if (!inode || !inode->i_sock || !socki_lookup(inode)) {
+		*err = -ENOTSOCK;
+		fput(file);
+		return NULL;
+	}
+
+	return socki_lookup(inode);
+}
+
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+struct sol_nmsghdr {
+	u32		msg_name;
+	int		msg_namelen;
+	u32		msg_iov;
+	u32		msg_iovlen;
+	u32		msg_control;
+	u32		msg_controllen;
+	u32		msg_flags;
+};
+
+struct sol_cmsghdr {
+	u32		cmsg_len;
+	int		cmsg_level;
+	int		cmsg_type;
+	unsigned char	cmsg_data[0];
+};
+
+struct iovec32 {
+	u32		iov_base;
+	u32 iov_len;
+};
+
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+					  struct iovec32 *uiov32,
+					  int niov)
+{
+	int tot_len = 0;
+
+	while(niov > 0) {
+		u32 len, buf;
+
+		if(get_user(len, &uiov32->iov_len) ||
+		   get_user(buf, &uiov32->iov_base)) {
+			tot_len = -EFAULT;
+			break;
+		}
+		tot_len += len;
+		kiov->iov_base = (void *)A(buf);
+		kiov->iov_len = (__kernel_size_t) len;
+		uiov32++;
+		kiov++;
+		niov--;
+	}
+	return tot_len;
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+					     struct sol_nmsghdr *umsg)
+{
+	u32 tmp1, tmp2, tmp3;
+	int err;
+
+	err = get_user(tmp1, &umsg->msg_name);
+	err |= __get_user(tmp2, &umsg->msg_iov);
+	err |= __get_user(tmp3, &umsg->msg_control);
+	if (err)
+		return -EFAULT;
+
+	kmsg->msg_name = (void *)A(tmp1);
+	kmsg->msg_iov = (struct iovec *)A(tmp2);
+	kmsg->msg_control = (void *)A(tmp3);
+
+	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+	
+	kmsg->msg_flags = solaris_to_linux_msgflags(kmsg->msg_flags);
+	
+	return err;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+			  char *kern_address, int mode)
+{
+	int tot_len;
+
+	if(kern_msg->msg_namelen) {
+		if(mode==VERIFY_READ) {
+			int err = move_addr_to_kernel(kern_msg->msg_name,
+						      kern_msg->msg_namelen,
+						      kern_address);
+			if(err < 0)
+				return err;
+		}
+		kern_msg->msg_name = kern_address;
+	} else
+		kern_msg->msg_name = NULL;
+
+	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+				   GFP_KERNEL);
+		if(!kern_iov)
+			return -ENOMEM;
+	}
+
+	tot_len = iov_from_user32_to_kern(kern_iov,
+					  (struct iovec32 *)kern_msg->msg_iov,
+					  kern_msg->msg_iovlen);
+	if(tot_len >= 0)
+		kern_msg->msg_iov = kern_iov;
+	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+		kfree(kern_iov);
+
+	return tot_len;
+}
+
+asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr *user_msg, unsigned user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	unsigned char *ctl_buf = ctl;
+	struct msghdr kern_msg;
+	int err, total_len;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	if(kern_msg.msg_controllen) {
+		struct sol_cmsghdr *ucmsg = (struct sol_cmsghdr *)kern_msg.msg_control;
+		unsigned long *kcmsg;
+		__kernel_size_t32 cmlen;
+
+		if(kern_msg.msg_controllen > sizeof(ctl) &&
+		   kern_msg.msg_controllen <= 256) {
+			err = -ENOBUFS;
+			ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
+			if(!ctl_buf)
+				goto out_freeiov;
+		}
+		__get_user(cmlen, &ucmsg->cmsg_len);
+		kcmsg = (unsigned long *) ctl_buf;
+		*kcmsg++ = (unsigned long)cmlen;
+		err = -EFAULT;
+		if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
+				  kern_msg.msg_controllen - sizeof(__kernel_size_t32)))
+			goto out_freectl;
+		kern_msg.msg_control = ctl_buf;
+	}
+	kern_msg.msg_flags = solaris_to_linux_msgflags(user_flags);
+
+	lock_kernel();
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			kern_msg.msg_flags |= MSG_DONTWAIT;
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
+	}
+	unlock_kernel();
+
+out_freectl:
+	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+	if(ctl_buf != ctl)
+		kfree(ctl_buf);
+out_freeiov:
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	return err;
+}
+
+asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr *user_msg, unsigned int user_flags)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &user_msg->msg_namelen;
+	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	lock_kernel();
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			user_flags |= MSG_DONTWAIT;
+		err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
+		if(err >= 0)
+			len = err;
+		sockfd_put(sock);
+	}
+	unlock_kernel();
+
+	if(uaddr != NULL && err >= 0)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(err >= 0) {
+		err = __put_user(linux_to_solaris_msgflags(kern_msg.msg_flags), &user_msg->msg_flags);
+		if(!err) {
+			/* XXX Convert cmsg back into userspace 32-bit format... */
+			err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
+					 &user_msg->msg_controllen);
+		}
+	}
+
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	if(err < 0)
+		return err;
+	return len;
+}
diff -u --recursive --new-file v2.1.128/linux/arch/sparc64/solaris/systbl.S linux/arch/sparc64/solaris/systbl.S
--- v2.1.128/linux/arch/sparc64/solaris/systbl.S	Thu Apr 23 20:21:32 1998
+++ linux/arch/sparc64/solaris/systbl.S	Mon Nov 16 10:37:28 1998
@@ -1,7 +1,7 @@
-/* $Id: systbl.S,v 1.6 1998/03/26 08:46:08 jj Exp $
+/* $Id: systbl.S,v 1.7 1998/10/28 08:11:49 jj Exp $
  * systbl.S: System call entry point table for Solaris compatibility.
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  */
 
@@ -156,8 +156,8 @@
 	.word solaris_fxstat		/* fxstat	ddx	125	*/
 	.word solaris_xmknod		/* xmknod	dsox	126	*/
 	.word solaris_unimplemented	/* syslocal	d	127	*/
-	.word solaris_unimplemented	/* setrlimit		128	*/
-	.word solaris_unimplemented	/* getrlimit		129	*/
+	.word solaris_setrlimit		/* setrlimit	dp	128	*/
+	.word solaris_getrlimit		/* getrlimit	dp	129	*/
 	.word CHAIN(chown)		/* lchown	sdd	130	*/
 	.word solaris_unimplemented	/* memcntl		131	*/
 	.word solaris_getpmsg		/* getpmsg	dxxxx	132	*/
@@ -230,8 +230,8 @@
 	.word CHAIN(nanosleep)		/* nanosleep	dd	199	*/
 	.word solaris_facl		/* facl		dddp	200	*/
 	.word solaris_unimplemented	/* 			201	*/
-	.word solaris_unimplemented	/* 			202	*/
-	.word solaris_unimplemented	/* 			203	*/
+	.word solaris_setreuid		/* setreuid	dd	202	*/
+	.word solaris_setregid		/* setregid	dd	203	*/
 	.word solaris_unimplemented	/* 			204	*/
 	.word solaris_unimplemented	/* 			205	*/
 	.word solaris_unimplemented	/* 			206	*/
@@ -241,43 +241,43 @@
 	.word solaris_unimplemented	/* 			210	*/
 	.word solaris_unimplemented	/* 			211	*/
 	.word solaris_unimplemented	/* 			212	*/
-	.word solaris_unimplemented	/* 			213	*/
-	.word solaris_unimplemented	/* 			214	*/
-	.word solaris_unimplemented	/* 			215	*/
-	.word solaris_unimplemented	/* 			216	*/
-	.word solaris_unimplemented	/* 			217	*/
-	.word solaris_unimplemented	/* 			218	*/
-	.word solaris_unimplemented	/* 			219	*/
-	.word solaris_unimplemented	/* 			220	*/
-	.word solaris_unimplemented	/* 			221	*/
-	.word solaris_unimplemented	/* 			222	*/
-	.word solaris_unimplemented	/* 			223	*/
-	.word solaris_unimplemented	/* 			224	*/
-	.word solaris_unimplemented	/* 			225	*/
+	.word solaris_getdents64	/* getdents64	dpd	213	*/
+	.word REGS(solaris_mmap64)	/* mmap64	xxxxdX	214	*/
+	.word solaris_stat64		/* stat64	sP	215	*/
+	.word solaris_lstat64		/* lstat64	sP	216	*/
+	.word solaris_fstat64		/* fstat64	dP	217	*/
+	.word solaris_statvfs64		/* statvfs64	sP	218	*/
+	.word solaris_fstatvfs64	/* fstatvfs64	dP	219	*/
+	.word solaris_setrlimit64	/* setrlimit64	dP	220	*/
+	.word solaris_getrlimit64	/* getrlimit64	dP	221	*/
+	.word CHAIN(pread)		/* pread64	dpdD	222	*/
+	.word CHAIN(pwrite)		/* pwrite64	dpdD	223	*/
+	.word CHAIN(creat)		/* creat64	so	224	*/
+	.word solaris_open		/* open64	soo	225	*/
 	.word solaris_unimplemented	/* 			226	*/
 	.word solaris_unimplemented	/* 			227	*/
 	.word solaris_unimplemented	/* 			228	*/
 	.word solaris_unimplemented	/* 			229	*/
-	.word solaris_unimplemented	/* 			230	*/
-	.word solaris_unimplemented	/* 			231	*/
-	.word solaris_unimplemented	/* 			232	*/
-	.word solaris_unimplemented	/* 			233	*/
-	.word solaris_unimplemented	/* 			234	*/
-	.word solaris_unimplemented	/* 			235	*/
-	.word solaris_unimplemented	/* 			236	*/
-	.word solaris_unimplemented	/* 			237	*/
-	.word solaris_unimplemented	/* 			238	*/
-	.word solaris_unimplemented	/* 			239	*/
-	.word solaris_unimplemented	/* 			240	*/
-	.word solaris_unimplemented	/* 			241	*/
-	.word solaris_unimplemented	/* 			242	*/
-	.word solaris_unimplemented	/* 			243	*/
-	.word solaris_unimplemented	/* 			244	*/
-	.word solaris_unimplemented	/* 			245	*/
-	.word solaris_unimplemented	/* 			246	*/
+	.word solaris_socket		/* socket	ddd	230	*/
+	.word solaris_socketpair	/* socketpair	dddp	231	*/
+	.word solaris_bind		/* bind		dpd	232	*/
+	.word solaris_listen		/* listen	dd	233	*/
+	.word solaris_accept		/* accept	dpp	234	*/
+	.word solaris_connect		/* connect	dpd	235	*/
+	.word solaris_shutdown		/* shutdown	dd	236	*/
+	.word solaris_recv		/* recv		dpdd	237	*/
+	.word solaris_recvfrom		/* recvfrom	dpddpp	238	*/
+	.word solaris_recvmsg		/* recvmsg	dpd	239	*/
+	.word solaris_send		/* send		dpdd	240	*/
+	.word solaris_sendmsg		/* sendmsg	dpd	241	*/
+	.word solaris_sendto		/* sendto	dpddpd	242	*/
+	.word solaris_getpeername	/* getpeername	dpp	243	*/
+	.word solaris_getsockname	/* getsockname	dpp	244	*/
+	.word solaris_getsockopt	/* getsockopt	dddpp	245	*/
+	.word solaris_setsockopt	/* setsockopt	dddpp	246	*/
 	.word solaris_unimplemented	/* 			247	*/
-	.word solaris_unimplemented	/* 			248	*/
-	.word solaris_unimplemented	/* 			249	*/
+	.word solaris_ntp_gettime	/* ntp_gettime	p	248	*/
+	.word solaris_ntp_adjtime	/* ntp_adjtime	p	249	*/
 	.word solaris_unimplemented	/* 			250	*/
 	.word solaris_unimplemented	/* 			251	*/
 	.word solaris_unimplemented	/* 			252	*/
diff -u --recursive --new-file v2.1.128/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.1.128/linux/drivers/block/Config.in	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/Config.in	Mon Nov 16 10:32:58 1998
@@ -48,7 +48,7 @@
         fi
       fi
       if [ "$CONFIG_PPC" = "y" ]; then
-          bool '   WInbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+          bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
       fi
     fi
     if [ "$CONFIG_PMAC" = "y" ]; then
@@ -77,7 +77,7 @@
   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
-  bool 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+  tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
 fi
 if [ "$CONFIG_ZORRO" = "y" ]; then
   tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
@@ -94,7 +94,9 @@
 comment 'Additional Block Devices'
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+if [ "$CONFIG_NET" = "y" ]; then
+  tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+fi
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
   tristate '   Linear (append) mode' CONFIG_MD_LINEAR
diff -u --recursive --new-file v2.1.128/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.1.128/linux/drivers/block/amiflop.c	Wed Aug 26 11:37:34 1998
+++ linux/drivers/block/amiflop.c	Sun Nov 15 11:23:08 1998
@@ -114,7 +114,7 @@
 #define FD_HD_3 	0x55555555  /* high-density 3.5" (1760K) drive */
 #define FD_DD_5 	0xaaaaaaaa  /* double-density 5.25" (440K) drive */
 
-static long int fd_def_df0 = 0;     /* default for df0 if it doesn't identify */
+static long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */
 
 MODULE_PARM(fd_def_df0,"l");
 
@@ -1858,20 +1858,6 @@
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   blksize_size[MAJOR_NR] = floppy_blocksizes;
   blk_size[MAJOR_NR] = floppy_sizes;
-
-
-  #if 0 /* Doesn't seem to be correct */
-  if (fd_def_df0==0) {
-    if ((amiga.model == AMI_3000) || (amiga.model == AMI_3000T) ||
-        (amiga.model == AMI_3000PLUS) || (amiga.model == AMI_4000))
-      fd_def_df0=FD_HD_3;
-    else
-      fd_def_df0=FD_DD_3;
-  }
-  #else
-  /* Now we hope that every HD drive will identify itself correctly */
-  fd_def_df0 = FD_DD_3;
-  #endif
 
   for (i = 0; i < 128; i++)
 	  mfmdecode[i]=255;
diff -u --recursive --new-file v2.1.128/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.128/linux/drivers/block/genhd.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/genhd.c	Mon Nov 16 10:32:58 1998
@@ -61,6 +61,10 @@
 extern int scsi_dev_init(void);
 extern int net_dev_init(void);
 
+#ifdef CONFIG_PPC
+extern void note_bootable_part(kdev_t dev, int part);
+#endif
+
 /*
  * disk_name() is used by genhd.c and md.c.
  * It formats the devicename of the indicated disk
@@ -862,7 +866,7 @@
 	int blk, blocks_in_map;
 	int dev_bsize, dev_pos, pos;
 	unsigned secsize;
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	int first_bootable = 1;
 #endif
 	struct mac_partition *part;
@@ -916,18 +920,18 @@
 			fsec + be32_to_cpu(part->start_block) * (secsize/512),
 			be32_to_cpu(part->block_count) * (secsize/512));
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 		/*
 		 * If this is the first bootable partition, tell the
 		 * setup code, in case it wants to make this the root.
 		 */
-		if (first_bootable
+		if ( (_machine == _MACH_Pmac) && first_bootable
 		    && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
 		    && strcasecmp(part->processor, "powerpc") == 0) {
 			note_bootable_part(dev, blk);
 			first_bootable = 0;
 		}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 		++current_minor;
 	}
diff -u --recursive --new-file v2.1.128/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.1.128/linux/drivers/block/ide-pmac.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/block/ide-pmac.c	Sun Nov 15 10:51:46 1998
@@ -25,10 +25,13 @@
 #include <asm/dbdma.h>
 #include <asm/ide.h>
 #include <asm/mediabay.h>
+#include <asm/feature.h>
 #include "ide.h"
 
 ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
 int pmac_ide_irq[MAX_HWIFS];
+int pmac_ide_count;
+struct device_node *pmac_ide_node[MAX_HWIFS];
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 #define MAX_DCMDS	256	/* allow up to 256 DBDMA commands per xfer */
@@ -45,15 +48,18 @@
 void
 pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-	int i;
+	int i, r;
 
 	*p = 0;
 	if (base == 0)
 		return;
-	if (base == mb_cd_base && !check_media_bay(MB_CD)) {
-		mb_cd_index = -1;
+	/* we check only for -EINVAL meaning that we have found a matching
+	   bay but with the wrong device type */ 
+
+	r = check_media_bay_by_base(base, MB_CD);
+	if (r == -EINVAL)
 		return;
-	}
+		
 	for (i = 0; i < 8; ++i)
 		*p++ = base + i * 0x10;
 	*p = base + 0x160;
@@ -93,8 +99,8 @@
 	/* Move removable devices such as the media-bay CDROM
 	   on the PB3400 to the end of the list. */
 	for (; p != NULL; p = p->next) {
-		if (p->parent && p->parent->name
-		    && strcasecmp(p->parent->name, "media-bay") == 0) {
+		if (p->parent && p->parent->type
+		    && strcasecmp(p->parent->type, "media-bay") == 0) {
 			*rp = p;
 			rp = &p->next;
 		} else {
@@ -111,7 +117,13 @@
 			       np->full_name);
 			continue;
 		}
+		
 		base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+		
+		/* XXX This is bogus. Should be fixed in the registry by checking
+		   the kind of host interrupt controller, a bit like gatwick
+		   fixes in irq.c
+		 */
 		if (np->n_intrs == 0) {
 			printk("ide: no intrs for device %s, using 13\n",
 			       np->full_name);
@@ -121,13 +133,13 @@
 		}
 		pmac_ide_regbase[i] = base;
 		pmac_ide_irq[i] = irq;
+		pmac_ide_node[i] = np;
 
 		if (np->parent && np->parent->name
 		    && strcasecmp(np->parent->name, "media-bay") == 0) {
-			mb_cd_index = i;
-			mb_cd_base = base;
-			mb_cd_irq = irq;
-		}
+			media_bay_set_ide_infos(np->parent,base,irq,i);
+		} else
+			feature_set(np, FEATURE_IDE_enable);
 
 		hwif = &ide_hwifs[i];
 		pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq);
@@ -143,6 +155,7 @@
 
 		++i;
 	}
+	pmac_ide_count = i;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
diff -u --recursive --new-file v2.1.128/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.128/linux/drivers/block/ide-probe.c	Thu Sep 17 17:53:35 1998
+++ linux/drivers/block/ide-probe.c	Fri Nov 13 09:55:31 1998
@@ -78,8 +78,18 @@
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
 	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
-	drive->present = 1;
 	printk("%s: %s, ", drive->name, id->model);
+	drive->present = 1;
+
+	/*
+	 * Prevent long system lockup probing later for non-existant
+	 * slave drive if the hwif is actually a Kodak CompactFlash card.
+	 */
+	if (!strcmp(id->model, "KODAK ATA_FLASH")) {
+		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+		mate->present = 0;
+		mate->noprobe = 1;
+	}
 
 	/*
 	 * Check for an ATAPI device
diff -u --recursive --new-file v2.1.128/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c
--- v2.1.128/linux/drivers/block/ns87415.c	Mon Oct  5 13:13:38 1998
+++ linux/drivers/block/ns87415.c	Mon Nov 16 10:37:28 1998
@@ -31,7 +31,7 @@
 static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int bit, new, *old = (unsigned int *) hwif->select_data;
+	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned long flags;
 
@@ -39,24 +39,20 @@
 	__cli();		/* local CPU only */
 	new = *old;
 
-	/* adjust IRQ enable bit */
+	/* Adjust IRQ enable bit */
 	bit = 1 << (8 + hwif->channel);
 	new = drive->present ? (new & ~bit) : (new | bit);
 
-	/* select PIO or DMA */
-	bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
-	new = use_dma ? (new | bit) : (new & ~bit);
+	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
 	if (new != *old) {
-		if (use_dma) {
-			bit = (1 << (5 + drive->select.b.unit));
-			outb((inb(hwif->dma_base+2) & 0x60) | bit,
-			     hwif->dma_base+2);
-		}
-
 		*old = new;
 		(void) pci_write_config_dword(dev, 0x40, new);
 	}
+
 	__restore_flags(flags);	/* local CPU only */
 }
 
@@ -94,6 +90,10 @@
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned int ctrl, using_inta;
 	byte progif;
+#ifdef __sparc_v9__
+	int timeout;
+	byte stat;
+#endif
 
 	/*
 	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
@@ -126,22 +126,6 @@
 		pci_write_config_byte(dev, 0x55, 0xee);
 
 #ifdef __sparc_v9__
-{
-		int	timeout;
-		byte	stat;
-		/*
-		 * Put reasonable values in the timing registers
-		 * for DMA2 mode performance.
-		 */
-		pci_write_config_byte(dev, 0x44, 0xfe);
-		pci_write_config_byte(dev, 0x45, 0xfe);
-		pci_write_config_byte(dev, 0x48, 0xfe);
-		pci_write_config_byte(dev, 0x49, 0xfe);
-		pci_write_config_byte(dev, 0x4c, 0xfe);
-		pci_write_config_byte(dev, 0x4d, 0xfe);
-		pci_write_config_byte(dev, 0x50, 0xfe);
-		pci_write_config_byte(dev, 0x51, 0xfe);
-
 		/*
 		 * XXX: Reset the device, if we don't it will not respond
 		 *      to SELECT_DRIVE() properly during first probe_hwif().
@@ -156,9 +140,11 @@
                 	if (stat == 0xff)
                         	break;
         	} while ((stat & BUSY_STAT) && --timeout);
-}
 #endif
 	}
+
+	outb(0x60, hwif->dma_base + 2);
+
 	if (!using_inta)
 		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
diff -u --recursive --new-file v2.1.128/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c
--- v2.1.128/linux/drivers/block/sl82c105.c	Thu Aug  6 14:06:31 1998
+++ linux/drivers/block/sl82c105.c	Sun Nov 15 10:51:46 1998
@@ -14,11 +14,6 @@
 #include "ide.h"
 #include "ide_modes.h"
 
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
-
 void ide_init_sl82c105(ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
@@ -36,38 +31,4 @@
 	pci_read_config_dword(dev, 0x40, &t32);
 	printk("IDE control/status register: %08x\n",t32);
 	pci_write_config_dword(dev, 0x40, 0x10ff08a1);
-}
-
-/* nobody ever calls these.. ??  -mlord
- *
- * Yes somebody certainly does, check asm-ppc/ide.h for the place.  -DaveM
- */
-void chrp_ide_probe(void) {
-
-	struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
-
-	chrp_ide_ports_known = 1;
-
-        if(pdev) {
-		chrp_ide_regbase[0]=pdev->base_address[0] &
-			PCI_BASE_ADDRESS_IO_MASK;
-		chrp_ide_regbase[1]=pdev->base_address[2] &
-			PCI_BASE_ADDRESS_IO_MASK;
-		chrp_idedma_regbase=pdev->base_address[4] &
-			PCI_BASE_ADDRESS_IO_MASK;
-		chrp_ide_irq=pdev->irq;
-        }
-}
-
-
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
-        ide_ioreg_t port = base;
-        int i = 8;
-
-        while (i--)
-                *p++ = port++;
-        *p++ = port;
-        if (irq != NULL)
-                *irq = chrp_ide_irq;
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.1.128/linux/drivers/block/swim3.c	Sun Nov  8 14:02:51 1998
+++ linux/drivers/block/swim3.c	Sun Nov 15 10:51:46 1998
@@ -22,12 +22,15 @@
 #include <asm/prom.h>
 #include <asm/uaccess.h>
 #include <asm/mediabay.h>
+#include <asm/feature.h>
 
 #define MAJOR_NR	FLOPPY_MAJOR
 #include <linux/blk.h>
 
-static int floppy_blocksizes[2] = {512};
-static int floppy_sizes[2] = {2880};
+static int floppy_blocksizes[2] = {512,512};
+static int floppy_sizes[2] = {2880,2880};
+
+#define MAX_FLOPPIES	2
 
 enum swim_state {
 	idle,
@@ -139,11 +142,12 @@
 	int	ejected;
 	struct wait_queue *wait;
 	int	wanted;
-	int	in_media_bay;
+	struct device_node*	media_bay; /* NULL when not in bay */
 	char	dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
 };
 
-static struct floppy_state floppy_states[1];
+static struct floppy_state floppy_states[MAX_FLOPPIES];
+static int floppy_count = 0;
 
 static unsigned short write_preamble[] = {
 	0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,	/* gap field */
@@ -175,7 +179,7 @@
 static void seek_timeout(unsigned long data);
 static void xfer_timeout(unsigned long data);
 static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
 static int grab_drive(struct floppy_state *fs, enum swim_state state,
 		      int interruptible);
 static void release_drive(struct floppy_state *fs);
@@ -190,6 +194,7 @@
 			    size_t count, loff_t *ppos);
 static int floppy_check_change(kdev_t dev);
 static int floppy_revalidate(kdev_t dev);
+static int swim3_add_device(struct device_node *swims);
 int swim3_init(void);
 
 #define IOCTL_MODE_BIT	8
@@ -212,11 +217,11 @@
 	volatile struct swim3 *sw = fs->swim3;
 
 	swim3_select(fs, action);
-	udelay(1);
+	udelay(10);
 	sw->select |= LSTRB; eieio();
-	udelay(2);
+	udelay(20);
 	sw->select &= ~LSTRB; eieio();
-	udelay(1);
+	udelay(10);
 	out_8(&sw->select, RELAX);
 }
 
@@ -226,7 +231,7 @@
 	int stat;
 
 	swim3_select(fs, bit);
-	udelay(1);
+	udelay(10);
 	stat = in_8(&sw->status);
 	out_8(&sw->select, RELAX);
 	return (stat & DATA) == 0;
@@ -234,13 +239,19 @@
 
 static void do_fd_request(void)
 {
-	start_request(&floppy_states[0]);
+	int i;
+	for(i=0;i<floppy_count;i++)
+	{
+		if (floppy_states[i].media_bay &&
+			check_media_bay(floppy_states[i].media_bay, MB_FD))
+			continue;
+		start_request(&floppy_states[i]);
+	}
 	sti();
 }
 
 static void start_request(struct floppy_state *fs)
 {
-	int drive;
 	unsigned long x;
 
 	if (fs->state == idle && fs->wanted) {
@@ -261,11 +272,6 @@
 		       CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
 #endif
 
-		drive = MINOR(CURRENT->rq_dev);
-		if (drive != 0) {
-			end_request(0);
-			continue;
-		}
 		if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
 			end_request(0);
 			continue;
@@ -438,7 +444,7 @@
 		case settling:
 			/* wait for SEEK_COMPLETE to become true */
 			swim3_select(fs, SEEK_COMPLETE);
-			udelay(1);
+			udelay(10);
 			out_8(&sw->intr_enable, ERROR | DATA_CHANGED);
 			in_8(&sw->intr);	/* clear DATA_CHANGED */
 			if (in_8(&sw->status) & DATA) {
@@ -560,7 +566,7 @@
 	err = in_8(&sw->error);
 	intr = in_8(&sw->intr);
 #if 0
-	printk(KERN_DEBUG "swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err);
+	printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err);
 #endif
 	if ((intr & ERROR) && fs->state != do_transfer)
 		printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n",
@@ -685,9 +691,11 @@
 	}
 }
 
+/*
 static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 }
+*/
 
 static int grab_drive(struct floppy_state *fs, enum swim_state state,
 		      int interruptible)
@@ -755,12 +763,20 @@
 {
 	struct floppy_state *fs;
 	int err;
+	int devnum = MINOR(inode->i_rdev);
 
+	if (devnum >= floppy_count)
+		return -ENODEV;
+		
 	if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
 	    ((cmd & 0x80) && !suser()))
 		return -EPERM;
 
-	fs = &floppy_states[0];
+	fs = &floppy_states[devnum];
+
+	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
+		return -ENXIO;
+
 	switch (cmd) {
 	case FDEJECT:
 		if (fs->ref_count != 1)
@@ -780,19 +796,21 @@
 	struct floppy_state *fs;
 	volatile struct swim3 *sw;
 	int n, err;
+	int devnum = MINOR(inode->i_rdev);
 
-	if (MINOR(inode->i_rdev) != 0)
+	if (devnum >= floppy_count)
 		return -ENODEV;
-	fs = &floppy_states[0];
+		
+	fs = &floppy_states[devnum];
 	sw = fs->swim3;
 	err = 0;
 	if (fs->ref_count == 0) {
-		if (fs->in_media_bay && !check_media_bay(MB_FD))
+		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 			return -ENXIO;
 		out_8(&sw->mode, 0x95);
 		out_8(&sw->control_bic, 0xff);
 		out_8(&sw->reg5, 0x28);
-		udelay(1);
+		udelay(10);
 		out_8(&sw->intr_enable, 0);
 		out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
 		swim3_action(fs, MOTOR_ON);
@@ -856,9 +874,11 @@
 {
 	struct floppy_state *fs;
 	volatile struct swim3 *sw;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
 
-	if (MINOR(inode->i_rdev) != 0)
-		return -ENXIO;
 	/*
 	 * If filp is NULL, we're being called from blkdev_release
 	 * or after a failed mount attempt.  In the former case the
@@ -868,7 +888,7 @@
 	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
 		block_fsync (filp, filp->f_dentry);
 
-	fs = &floppy_states[0];
+	fs = &floppy_states[devnum];
 	sw = fs->swim3;
 	if (fs->ref_count > 0 && --fs->ref_count == 0) {
 		swim3_action(fs, MOTOR_OFF);
@@ -880,10 +900,12 @@
 static int floppy_check_change(kdev_t dev)
 {
 	struct floppy_state *fs;
+	int devnum = MINOR(dev);
 
-	if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+	if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count))
 		return 0;
-	fs = &floppy_states[0];
+		
+	fs = &floppy_states[devnum];
 	return fs->ejected;
 }
 
@@ -892,10 +914,16 @@
 	struct floppy_state *fs;
 	volatile struct swim3 *sw;
 	int ret, n;
+	int devnum = MINOR(dev);
 
-	if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+	if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count))
 		return 0;
-	fs = &floppy_states[0];
+
+	fs = &floppy_states[devnum];
+
+	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
+		return -ENXIO;
+
 	sw = fs->swim3;
 	grab_drive(fs, revalidating, 0);
 	out_8(&sw->intr_enable, 0);
@@ -929,10 +957,12 @@
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct floppy_state *fs;
+	int devnum = MINOR(inode->i_rdev);
 
-	if (MINOR(inode->i_rdev) != 0)
+	if (devnum >= floppy_count)
 		return -ENODEV;
-	fs = &floppy_states[0];
+		
+	fs = &floppy_states[devnum];
 	if (fs->ejected)
 		return -ENXIO;
 	return block_read(filp, buf, count, ppos);
@@ -943,10 +973,12 @@
 {
 	struct inode * inode = filp->f_dentry->d_inode;
 	struct floppy_state *fs;
+	int devnum = MINOR(inode->i_rdev);
 
-	if (MINOR(inode->i_rdev) != 0)
+	if (devnum >= floppy_count)
 		return -ENODEV;
-	fs = &floppy_states[0];
+
+	fs = &floppy_states[devnum];
 	if (fs->ejected)
 		return -ENXIO;
 	return block_write(filp, buf, count, ppos);
@@ -975,50 +1007,72 @@
 
 int swim3_init(void)
 {
-	struct device_node *swims;
-	struct floppy_state *fs = &floppy_states[0];
-	int is_3400 = 0;
-
-	if (find_devices("media-bay") != NULL) {
-		/* assume this is a PB3400 */
-		swims = find_devices("floppy");
-		is_3400 = 1;
-	} else {
-		swims = find_devices("swim3");
+	struct device_node *swim;
+
+	swim = find_devices("floppy");
+	while (swim && (floppy_count < MAX_FLOPPIES))
+	{
+		swim3_add_device(swim);
+		swim = swim->next;
+	}
+
+	swim = find_devices("swim3");
+	while (swim && (floppy_count < MAX_FLOPPIES))
+	{
+		swim3_add_device(swim);
+		swim = swim->next;
+	}
+
+	if (floppy_count > 0)
+	{
+		if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+			printk(KERN_ERR "Unable to get major %d for floppy\n",
+			       MAJOR_NR);
+			return -EBUSY;
+		}
+		blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+		blksize_size[MAJOR_NR] = floppy_blocksizes;
+		blk_size[MAJOR_NR] = floppy_sizes;
 	}
 
-	if (swims == NULL)
-		return 0;
+	return 0;
+}
 
-	if (swims->next != NULL)
-		printk(KERN_ERR "Warning: only using first SWIM3 floppy controller\n");
-	if (swims->n_addrs != 2 || swims->n_intrs != 2) {
-		printk(KERN_ERR "swim3: expecting 2 addrs and 2 intrs! (%d, %d)\n",
-		       swims->n_addrs, swims->n_intrs);
+static int swim3_add_device(struct device_node *swim)
+{
+	struct device_node *mediabay;
+	struct floppy_state *fs = &floppy_states[floppy_count];
+	
+	if (swim->n_addrs < 2)
+	{
+		printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
+		       swim->n_addrs, swim->n_intrs);
 		return -EINVAL;
 	}
 
-	if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
-		printk(KERN_ERR "Unable to get major %d for floppy\n",
-		       MAJOR_NR);
-		return -EBUSY;
+	if (swim->n_intrs < 2)
+	{
+		printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
+		       swim->n_addrs, swim->n_intrs);
+		return -EINVAL;
 	}
-	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
-	blk_size[MAJOR_NR] = floppy_sizes;
 
+	mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL;
+	if (mediabay == NULL)
+		feature_set(swim, FEATURE_SWIM3_enable);
+	
 	memset(fs, 0, sizeof(*fs));
 	fs->state = idle;
-	fs->swim3 = (volatile struct swim3 *) swims->addrs[0].address;
-	fs->dma = (struct dbdma_regs *) swims->addrs[1].address;
-	fs->swim3_intr = swims->intrs[0].line;
-	fs->dma_intr = swims->intrs[1].line;
+	fs->swim3 = (volatile struct swim3 *) ioremap(swim->addrs[0].address, 0x200);
+	fs->dma = (struct dbdma_regs *) ioremap(swim->addrs[1].address, 0x200);
+	fs->swim3_intr = swim->intrs[0].line;
+	fs->dma_intr = swim->intrs[1].line;
 	fs->cur_cyl = -1;
 	fs->cur_sector = -1;
 	fs->secpercyl = 36;
 	fs->secpertrack = 18;
 	fs->total_secs = 2880;
-	fs->in_media_bay = is_3400;
+	fs->media_bay = mediabay;
 
 	fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
 	memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
@@ -1026,19 +1080,26 @@
 
 	if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
 		printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+		feature_clear(swim, FEATURE_SWIM3_enable);
 		return -EBUSY;
 	}
+/*
 	if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
 		printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
 		       fs->dma_intr);
+		feature_clear(swim, FEATURE_SWIM3_enable);
 		return -EBUSY;
 	}
+*/
 
 	init_timer(&fs->timeout);
 
 	do_floppy = NULL;
 
-	printk(KERN_INFO "fd0: SWIM3 floppy controller\n");
+	printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
+		mediabay ? "in media bay" : "");
 
+	floppy_count++;
+	
 	return 0;
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c
--- v2.1.128/linux/drivers/block/via82c586.c	Thu Sep 17 17:53:35 1998
+++ linux/drivers/block/via82c586.c	Fri Nov 13 10:29:44 1998
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/via82C586.c	Version 0.01	Aug 16, 1998
+ * linux/drivers/block/via82c586.c	Version 0.01	Aug 16, 1998
  *
  *  Copyright (C) 1998 Michel Aubry
  *  Copyright (C) 1998 Andre Hedrick
diff -u --recursive --new-file v2.1.128/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.128/linux/drivers/cdrom/cdrom.c	Sun Nov  8 14:02:52 1998
+++ linux/drivers/cdrom/cdrom.c	Fri Nov 13 10:29:44 1998
@@ -174,7 +174,9 @@
 			 struct cdrom_device_ops * cdo);
 static void sanitize_format(union cdrom_addr *addr, 
 		u_char * curr, u_char requested);
+#ifdef CONFIG_SYSCTL
 static void cdrom_sysctl_register(void);
+#endif /* CONFIG_SYSCTL */ 
 static struct cdrom_device_info *topCdromPtr = NULL;
 
 struct file_operations cdrom_fops =
diff -u --recursive --new-file v2.1.128/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.128/linux/drivers/char/Makefile	Sun Nov  8 14:02:53 1998
+++ linux/drivers/char/Makefile	Mon Nov 16 10:32:58 1998
@@ -224,11 +224,11 @@
   endif
 endif
 
-ifeq ($(CONFIG_MACMOUSE),y)
-L_OBJS += macmouse.o
+ifeq ($(CONFIG_ADBMOUSE),y)
+L_OBJS += adbmouse.o
 else
-  ifeq ($(CONFIG_MACMOUSE),m)
-    M_OBJS += macmouse.o
+  ifeq ($(CONFIG_ADBMOUSE),m)
+    M_OBJS += adbmouse.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.128/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.1.128/linux/drivers/char/adbmouse.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/char/adbmouse.c	Sun Nov 15 10:51:46 1998
@@ -3,6 +3,7 @@
  *
  * 27 Oct 1997 Michael Schmitz
  * logitech fixes by anthony tong
+ * further hacking by Paul Mackerras
  *
  * Apple mouse protocol according to:
  *
@@ -33,14 +34,21 @@
 #include <linux/init.h>
 
 #include <asm/adb_mouse.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
+#ifdef __powerpc__
 #include <asm/processor.h>
+#endif
+#ifdef __mc68000__
+#include <asm/setup.h>
+#endif
 
 static struct mouse_status mouse;
-static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2;
-static int adb_mouse_buttons = 0;
+static unsigned char adb_mouse_buttons[16];
 
-extern void (*adb_mouse_interrupt_hook) (char *, int);
+extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
+extern int adb_emulate_buttons;
+extern int adb_button2_keycode;
+extern int adb_button3_keycode;
 
 extern int console_loglevel;
 
@@ -48,11 +56,11 @@
  *	XXX: need to figure out what ADB mouse packets mean ... 
  *	This is the stuff stolen from the Atari driver ...
  */
-static void adb_mouse_interrupt(char *buf, int nb)
+static void adb_mouse_interrupt(unsigned char *buf, int nb)
 {
-    static int buttons = 7;
+    int buttons, id;
 
-  /*
+/*
     Handler 1 -- 100cpi original Apple mouse protocol.
     Handler 2 -- 200cpi original Apple mouse protocol.
 
@@ -60,76 +68,62 @@
     contain the following values:
 
                 BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = ???? ???? (?)
-    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
-    data[3] = bxxx xxxx First button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
-
-    NOTE: data[0] is confirmed by the parent function and need not be
-    checked here.
-  */
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx First button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
 
-  /*
     Handler 4 -- Apple Extended mouse protocol.
 
     For Apple's 3-button mouse protocol the data array will contain the
     following values:
 
 		BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = 0100 0000 Extended protocol register.
-	      Bits 6-7 are the device id, which should be 1.
-	      Bits 4-5 are resolution which is in "units/inch".
-	      The Logitech MouseMan returns these bits clear but it has
-	      200/300cpi resolution.
-	      Bits 0-3 are unique vendor id.
-    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
-	      Bits 2-3 should be 8 + 4.
-		      Bits 4-7 should be 3 for a mouse device.
-    data[3] = bxxx xxxx Left button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
-    data[5] = byyy bxxx Third button and fourth button.  
-    	      Y is additiona. high bits of y-axis motion.  
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx Left button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
+    data[3] = byyy bxxx Third button and fourth button.  
+    	      Y is additional high bits of y-axis motion.  
     	      X is additional high bits of x-axis motion.
 
-    NOTE: data[0] and data[2] are confirmed by the parent function and
-    need not be checked here.
-  */
-
-    /*
-     * 'buttons' here means 'button down' states!
-     * Button 1 (left)  : bit 2, busmouse button 3
-     * Button 2 (right) : bit 0, busmouse button 1
-     * Button 3 (middle): bit 1, busmouse button 2
-     */
+    This procedure also gets called from the keyboard code if we
+    are emulating mouse buttons with keys.  In this case data[0] == 0
+    (data[0] cannot be 0 for a real ADB packet).
+
+    'buttons' here means 'button down' states!
+    Button 1 (left)  : bit 2, busmouse button 3
+    Button 2 (middle): bit 1, busmouse button 2
+    Button 3 (right) : bit 0, busmouse button 1
+*/
 
     /* x/y and buttons swapped */
     
-    if (nb > 0)	{				/* real packet : use buttons? */
-	if (console_loglevel >= 8)
-	    printk("adb_mouse: real data; "); 
-	/* button 1 (left, bit 2) : always significant ! */
-	buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
-	/* button 2 (middle) */
-	buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
-	/* button 3 (right) present?
-	 *  on a logitech mouseman, the right and mid buttons sometimes behave
-	 *  strangely until they both have been pressed after booting. */
-	/* data valid only if extended mouse format ! (buf[3] = 0 else) */
-	if ( nb == 6 )
-	    buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
-    } else {					/* fake packet : use 2+3 */
-	if (console_loglevel >= 8)
-	    printk("adb_mouse: fake data; "); 
-	/* we only see state changes here, but the fake driver takes care
-	 * to preserve state... button 1 state must stay unchanged! */
-	buttons = (buttons&4) | ((buf[2] & 0x80 ? 1 : 0) |
-		  (buf[3] & 0x80 ? 2 : 0));
-    }
+    if (console_loglevel >= 8)
+	printk("KERN_DEBUG adb_mouse: %s data; ", buf[0]? "real": "fake"); 
+
+    id = (buf[0] >> 4) & 0xf;
+    buttons = adb_mouse_buttons[id];
+
+    /* button 1 (left, bit 2) */
+    buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+
+    /* button 2 (middle) */
+    buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
+
+    /* button 3 (right) present?
+     *  on a logitech mouseman, the right and mid buttons sometimes behave
+     *  strangely until they both have been pressed after booting. */
+    /* data valid only if extended mouse format ! */
+    if (nb == 4)
+	buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+
+    add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+
+    adb_mouse_buttons[id] = buttons;
+    /* a button is down if it is down on any mouse */
+    for (id = 0; id < 16; ++id)
+	buttons &= adb_mouse_buttons[id];
 
-    add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
-    mouse.buttons = buttons & 7;
+    mouse.buttons = buttons;
     mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
     mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
 
@@ -141,7 +135,6 @@
     wake_up_interruptible(&mouse.wait);
     if (mouse.fasyncptr)
 	kill_fasync(mouse.fasyncptr, SIGIO);
-
 }
 
 static int fasync_mouse(int fd, struct file *filp, int on)
@@ -167,13 +160,16 @@
 
 static int open_mouse(struct inode *inode, struct file *file)
 {
+    int id;
+
     if (mouse.active++)
 	return 0;
 	
     mouse.ready = 0;
 
     mouse.dx = mouse.dy = 0;
-    adb_mouse_buttons = 0;
+    for (id = 0; id < 16; ++id)
+	adb_mouse_buttons[id] = 7;	/* all buttons up */
     MOD_INC_USE_COUNT;
     adb_mouse_interrupt_hook = adb_mouse_interrupt;
     return 0;
@@ -198,24 +194,24 @@
     dy = mouse.dy;
     buttons = mouse.buttons;
     if (dx > 127)
-      dx = 127;
+	dx = 127;
     else if (dx < -128)
-      dx = -128;
+	dx = -128;
     if (dy > 127)
-      dy = 127;
+	dy = 127;
     else if (dy < -128)
-      dy = -128;
+	dy = -128;
     mouse.dx -= dx;
     mouse.dy -= dy;
     if (mouse.dx == 0 && mouse.dy == 0)
-      mouse.ready = 0;
+	mouse.ready = 0;
     if (put_user(buttons | 0x80, buffer++) ||
 	put_user((char) dx, buffer++) ||
 	put_user((char) dy, buffer++))
-      return -EFAULT;
-    if (count > 3)
-      if (clear_user(buffer, count - 3))
 	return -EFAULT;
+    if (count > 3)
+	if (clear_user(buffer, count - 3))
+	    return -EFAULT;
     return count;
 }
 
@@ -254,40 +250,35 @@
     mouse.ready = 0;
     mouse.wait = NULL;
 
+#ifdef __powerpc__
     if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 	    return -ENODEV;
-    printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+#endif
+#ifdef __mc68000__
+    if (!MACH_IS_MAC)
+	return -ENODEV;
+#endif
+    printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
     misc_register(&adb_mouse);
     return 0;
 }
 
 
-#define	MIN_THRESHOLD 1
-#define	MAX_THRESHOLD 20	/* more seems not reasonable... */
-
+/*
+ * XXX this function is misnamed.
+ * It is called if the kernel is booted with the adb_buttons=xxx
+ * option, which is about using ADB keyboard buttons to emulate
+ * mouse buttons. -- paulus
+ */
 __initfunc(void adb_mouse_setup(char *str, int *ints))
 {
-    if (ints[0] < 1) {
-	printk( "adb_mouse_setup: no arguments!\n" );
-	return;
-    }
-    else if (ints[0] > 2) {
-	printk( "adb_mouse_setup: too many arguments\n" );
-    }
-
-    if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
-	printk( "adb_mouse_setup: bad threshold value (ignored)\n" );
-    else {
-	adb_mouse_x_threshold = ints[1];
-	adb_mouse_y_threshold = ints[1];
-	if (ints[0] > 1) {
-	    if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
-		printk("adb_mouse_setup: bad threshold value (ignored)\n" );
-	    else
-		adb_mouse_y_threshold = ints[2];
+	if (ints[0] >= 1) {
+		adb_emulate_buttons = ints[1] > 0;
+		if (ints[1] > 1)
+			adb_button2_keycode = ints[1];
+		if (ints[0] >= 2)
+			adb_button3_keycode = ints[2];
 	}
-    }
-	
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.128/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.128/linux/drivers/char/cyclades.c	Sun Nov  8 14:02:54 1998
+++ linux/drivers/char/cyclades.c	Sun Nov 15 21:41:11 1998
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define	Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.1.7 $$Date: 1998/09/03 12:07:28 $";
+"$Revision: 2.2.1.8 $$Date: 1998/11/13 12:46:20 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -31,6 +31,10 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.1.8  1998/11/13 12:46:20 ivan
+ * cy_close function now resets (correctly) the tty->closing flag;
+ * JIFFIES_DIFF macro fixed.
+ *
  * Revision 2.2.1.7  1998/09/03 12:07:28 ivan
  * Fixed bug in cy_close function, which was not informing HW of
  * which port should have the reception disabled before doing so;
@@ -612,7 +616,7 @@
 
 #define STD_COM_FLAGS (0)
 
-#define	JIFFIES_DIFF(n, j)	((n) - (j))
+#define	JIFFIES_DIFF(n, j)	((j) - (n))
 
 static DECLARE_TASK_QUEUE(tq_cyclades);
 
@@ -2730,6 +2734,7 @@
         tty->driver.flush_buffer(tty);
     if (tty->ldisc.flush_buffer)
         tty->ldisc.flush_buffer(tty);
+    tty->closing = 0;
     info->event = 0;
     info->tty = 0;
     if (info->blocked_open) {
diff -u --recursive --new-file v2.1.128/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.1.128/linux/drivers/char/lp_m68k.c	Wed Aug 26 11:37:37 1998
+++ linux/drivers/char/lp_m68k.c	Sun Nov 15 11:23:23 1998
@@ -477,7 +477,7 @@
 EXPORT_SYMBOL(register_parallel);
 EXPORT_SYMBOL(unregister_parallel);
 
-__initfunc(int lp_init(void))
+__initfunc(int lp_m68k_init(void))
 {
 	extern char m68k_debug_device[];
 
@@ -517,12 +517,12 @@
 #ifdef MODULE
 int init_module(void)
 {
-return lp_init();
+	return lp_m68k_init();
 }
 
 void cleanup_module(void)
 {
-unregister_chrdev(LP_MAJOR, "lp");
+	unregister_chrdev(LP_MAJOR, "lp");
 }
 #endif
 
diff -u --recursive --new-file v2.1.128/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.128/linux/drivers/char/mem.c	Sun Nov  8 14:02:55 1998
+++ linux/drivers/char/mem.c	Mon Nov 16 10:32:58 1998
@@ -53,6 +53,9 @@
 #ifdef CONFIG_MDA_CONSOLE
 extern void mda_console_init(void);
 #endif
+#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+extern void adbdev_init(void);
+#endif
 
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
@@ -509,9 +512,11 @@
 		case 3:
 			filp->f_op = &null_fops;
 			break;
+#ifndef CONFIG_PPC
 		case 4:
 			filp->f_op = &port_fops;
 			break;
+#endif
 		case 5:
 			filp->f_op = &zero_fops;
 			break;
@@ -595,6 +600,9 @@
 #endif
 #ifdef CONFIG_VIDEO_BT848
 	i2c_init();
+#endif
+#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+	adbdev_init();
 #endif
 #ifdef CONFIG_VIDEO_DEV
 	videodev_init();
diff -u --recursive --new-file v2.1.128/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.128/linux/drivers/char/misc.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/misc.c	Mon Nov 16 10:32:58 1998
@@ -64,14 +64,12 @@
 #define DYNAMIC_MINORS 64 /* like dynamic majors */
 static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 
-extern int adbdev_init(void);
 extern int bus_mouse_init(void);
 extern int qpmouse_init(void);
 extern int ms_bus_mouse_init(void);
 extern int atixl_busmouse_init(void);
 extern int amiga_mouse_init(void);
 extern int atari_mouse_init(void);
-extern int mac_mouse_init(void);
 extern int sun_mouse_init(void);
 extern int adb_mouse_init(void);
 extern void watchdog_init(void);
@@ -196,9 +194,6 @@
 	if (proc_misc)
 		proc_misc->read_proc = misc_read_proc;
 #endif /* PROC_FS */
-#ifdef CONFIG_MAC
-	adbdev_init();
-#endif
 #ifdef CONFIG_BUSMOUSE
 	bus_mouse_init();
 #endif
@@ -217,13 +212,10 @@
 #ifdef CONFIG_ATARIMOUSE
 	atari_mouse_init();
 #endif
-#ifdef CONFIG_MACMOUSE
-	mac_mouse_init();
-#endif
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
 #endif
-#ifdef CONFIG_MACMOUSE
+#ifdef CONFIG_ADBMOUSE
 	adb_mouse_init();
 #endif
 #ifdef CONFIG_PC110_PAD
diff -u --recursive --new-file v2.1.128/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.1.128/linux/drivers/char/random.c	Fri Oct  9 13:27:08 1998
+++ linux/drivers/char/random.c	Fri Nov 13 10:29:44 1998
@@ -1407,19 +1407,15 @@
 	
 	switch (cmd) {
 	case RNDGETENTCNT:
-		retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-		if (retval)
-			return(retval);
 		ent_count = random_state.entropy_count;
-		put_user(ent_count, (int *) arg);
+		if (put_user(ent_count, (int *) arg))
+			return -EFAULT;
 		return 0;
 	case RNDADDTOENTCNT:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
-		if (retval)
-			return(retval);
-		get_user(ent_count, (int *) arg);
+		if (get_user(ent_count, (int *) arg))
+			return -EFAULT;
 		/*
 		 * Add i to entropy_count, limiting the result to be
 		 * between 0 and POOLBITS.
@@ -1446,16 +1442,14 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		p = (int *) arg;
-		retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
-		if (retval)
-			return(retval);
 		ent_count = random_state.entropy_count;
-		put_user(ent_count, p++);
-		retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
-		if (retval)
-			return(retval);
-		get_user(size, p);
-		put_user(POOLWORDS, p++);
+		if (put_user(ent_count, p++))
+			return -EFAULT;
+			
+		if (get_user(size, p))
+			return -EFAULT;
+		if (put_user(POOLWORDS, p++))
+			return -EFAULT;
 		if (size < 0)
 			return -EINVAL;
 		if (size > POOLWORDS)
@@ -1467,16 +1461,12 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		p = (int *) arg;
-		retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int));
-		if (retval)
-			return(retval);
-		get_user(ent_count, p++);
+		if (get_user(ent_count, p++))
+			return -EFAULT;
 		if (ent_count < 0)
 			return -EINVAL;
-		get_user(size, p++);
-		retval = verify_area(VERIFY_READ, (void *) p, size);
-		if (retval)
-			return retval;
+		if (get_user(size, p++))
+			return -EFAULT;
 		retval = random_write(file, (const char *) p,
 				      size, &file->f_pos);
 		if (retval < 0)
diff -u --recursive --new-file v2.1.128/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.128/linux/drivers/char/vt.c	Mon Sep 28 10:51:33 1998
+++ linux/drivers/char/vt.c	Sun Nov 15 11:24:14 1998
@@ -57,6 +57,11 @@
 
 struct vt_struct *vt_cons[MAX_NR_CONSOLES];
 
+/* Keyboard type: Default is KB_101, but can be set by machine
+ * specific code.
+ */
+unsigned char keyboard_type = KB_101;
+
 #ifndef __alpha__
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
 #endif
@@ -462,7 +467,7 @@
 		/*
 		 * this is naive.
 		 */
-		ucval = KB_101;
+		ucval = keyboard_type;
 		goto setchar;
 
 #ifndef __alpha__
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.1.128/linux/drivers/macintosh/Makefile	Thu Aug  6 14:06:32 1998
+++ linux/drivers/macintosh/Makefile	Sun Nov 15 10:51:46 1998
@@ -16,14 +16,15 @@
 M_OBJS   :=
 
 ifndef CONFIG_MBX
-L_OBJS   := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o
+L_OBJS   := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o
+LX_OBJS  := adb.o
 endif
 
 ifeq ($(CONFIG_MAC_SERIAL),y)
-  LX_OBJS += macserial.o
+  L_OBJS += macserial.o
 else
   ifeq ($(CONFIG_MAC_SERIAL),m)
-    MX_OBJS += macserial.o
+    M_OBJS += macserial.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.1.128/linux/drivers/macintosh/adb.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/macintosh/adb.c	Sun Nov 15 10:51:46 1998
@@ -8,6 +8,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -19,10 +20,13 @@
 #include <asm/hydra.h>
 #include <asm/init.h>
 
+EXPORT_SYMBOL(adb_hardware);
+
 enum adb_hw adb_hardware = ADB_NONE;
 int (*adb_send_request)(struct adb_request *req, int sync);
-int (*adb_autopoll)(int on);
-static void adb_scan_bus(void);
+int (*adb_autopoll)(int devs);
+int (*adb_reset_bus)(void);
+static int adb_scan_bus(void);
 
 static struct adb_handler {
 	void (*handler)(unsigned char *, int, struct pt_regs *, int);
@@ -50,13 +54,13 @@
 }
 #endif
 
-static void adb_scan_bus(void)
+static int adb_scan_bus(void)
 {
 	int i, highFree=0, noMovement;
+	int devmask = 0;
 	struct adb_request req;
 	
-	/* reset ADB bus */
-	/*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/
+	adb_reset_bus();	/* reset ADB bus */
 
 	/* assumes adb_handler[] is all zeroes at this point */
 	for (i = 1; i < 16; i++) {
@@ -134,24 +138,27 @@
 		adb_handler[i].handler_id = req.reply[2];
 		printk(" [%d]: %d %x", i, adb_handler[i].original_address,
 		       adb_handler[i].handler_id);
+		devmask |= 1 << i;
 	}
 	printk("\n");
+	return devmask;
 }
 
 void adb_init(void)
 {
 	adb_send_request = (void *) adb_nodev;
 	adb_autopoll = (void *) adb_nodev;
+	adb_reset_bus = adb_nodev;
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;		
+		return;
 	via_cuda_init();
 	via_pmu_init();
 	macio_adb_init();
 	if (adb_hardware == ADB_NONE)
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
 	else {
-		adb_scan_bus();
-		adb_autopoll(1);
+		int devs = adb_scan_bus();
+		adb_autopoll(devs);
 	}
 }
 
@@ -187,8 +194,7 @@
 
 	ids->nids = 0;
 	for (i = 1; i < 16; i++) {
-		if ((adb_handler[i].original_address == default_id) ||
-		    (adb_handler[i].handler_id == handler_id)) {
+		if (adb_handler[i].original_address == default_id) {
 			if (adb_handler[i].handler != 0) {
 				printk(KERN_ERR
 				       "Two handlers for ADB device %d\n",
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.1.128/linux/drivers/macintosh/mac_keyb.c	Thu Aug  6 14:06:32 1998
+++ linux/drivers/macintosh/mac_keyb.c	Sun Nov 15 10:51:46 1998
@@ -16,6 +16,8 @@
 #include <linux/signal.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
 
 #include <asm/bitops.h>
 #include <asm/adb.h>
@@ -170,16 +172,22 @@
 static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
 static void input_keycode(int, int);
 static void leds_done(struct adb_request *);
+static void mac_put_queue(int);
 
+#ifdef CONFIG_ADBMOUSE
 /* XXX: Hook for mouse driver */
-void (*adb_mouse_interrupt_hook) (char *, int);
-static int adb_emulate_buttons = 0;
+void (*adb_mouse_interrupt_hook)(unsigned char *, int);
+int adb_emulate_buttons = 0;
+int adb_button2_keycode = 0x7d;	/* right control key */
+int adb_button3_keycode = 0x7c; /* right option key */
+#endif
+
 extern int console_loglevel;
 
 extern struct kbd_struct kbd_table[];
+extern struct wait_queue * keypress_wait;
 
 extern void handle_scancode(unsigned char);
-extern void put_queue(int);
 
 static struct adb_ids keyboard_ids;
 static struct adb_ids mouse_ids;
@@ -264,6 +272,7 @@
 	if (!repeat)
 		del_timer(&repeat_timer);
 
+#ifdef CONFIG_ADBMOUSE
 	/*
 	 * XXX: Add mouse button 2+3 fake codes here if mouse open.
 	 *	Keep track of 'button' states here as we only send 
@@ -273,52 +282,27 @@
 	 *	Might also want to know how many buttons need to be emulated.
 	 *	-> hide this as function in arch/m68k/mac ?
 	 */
-	if ( (adb_emulate_buttons) &&
-	     (adb_mouse_interrupt_hook || console_loglevel == 10) ) {
-		unsigned char button, button2, button3, fake_event;
-		static unsigned char button2state=0, button3state=0; /* up */
+	if (adb_emulate_buttons
+	    && (keycode == adb_button2_keycode
+		|| keycode == adb_button3_keycode)
+	    && (adb_mouse_interrupt_hook || console_loglevel == 10)) {
+		int button;
 		/* faked ADB packet */
-		static char data[4] = { 0, 0x80, 0x80, 0x80 };
+		static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 };
 
-		button = 0;
-		fake_event = 0;
-		switch (keycode) {	/* which 'button' ? */
-			case 0x7c:	/* R-option */
-				button3 = (!up_flag);		/* new state */
-				if (button3 != button3state)	/* change ? */ 
-					button = 3; 
-				button3state = button3; 	/* save state */
-				fake_event = 3;
-				break; 
-			case 0x7d:	/* R-control */
-				button2 = (!up_flag);		/* new state */
-				if (button2 != button2state)	/* change ? */
-					button = 2; 
-				button2state = button2;		/* save state */
-				fake_event = 2;
-				break; 
-		}
-		if (fake_event && console_loglevel >= 8)
-			printk("fake event: button2 %d button3 %d button %d\n",
-				 button2state, button3state, button);
-		if (button) {		/* there's been a button state change */
-			/* fake a mouse packet : send all bytes, change one! */
-			data[button] = (up_flag ? 0x80 : 0);
+		button = keycode == adb_button2_keycode? 2: 3;
+		if (data[button] != up_flag) {
+			/* send a fake mouse packet */
+			data[button] = up_flag;
+			if (console_loglevel >= 8)
+				printk("fake mouse event: %x %x %x\n",
+				       data[1], data[2], data[3]);
 			if (adb_mouse_interrupt_hook)
-				adb_mouse_interrupt_hook(data, -1);
-			else
-				printk("mouse_fake: data %x %x %x buttons %x \n", 
-					data[1], data[2], data[3],
-					~( (data[1] & 0x80 ? 0 : 4) 
-					 | (data[2] & 0x80 ? 0 : 1) 
-					 | (data[3] & 0x80 ? 0 : 2) )&7 );
+				adb_mouse_interrupt_hook(data, 4);
 		}
-		/*
-		 * XXX: testing mouse emulation ... don't process fake keys!
-		 */
-		if (fake_event)
-			return;
+		return;
 	}
+#endif /* CONFIG_ADBMOUSE */
 
 	if (kbd->kbdmode != VC_RAW) {
 		if (!up_flag && !dont_repeat[keycode]) {
@@ -361,6 +345,20 @@
 	restore_flags(flags);
 }
 
+static void mac_put_queue(int ch)
+{
+	extern struct tty_driver console_driver;
+	struct tty_struct *tty;
+
+	tty = console_driver.table? console_driver.table[fg_console]: NULL;
+	wake_up(&keypress_wait);
+	if (tty) {
+		tty_insert_flip_char(tty, ch, 0);
+		con_schedule_flip(tty);
+	}
+}
+
+#ifdef CONFIG_ADBMOUSE
 static void
 mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
 {
@@ -399,33 +397,6 @@
   */
 
   /*
-    Handler 4 -- Apple Extended mouse protocol.
-
-    For Apple's 3-button mouse protocol the data array will contain the
-    following values:
-
-		BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = 0100 0000 Extended protocol register.
-	      Bits 6-7 are the device id, which should be 1.
-	      Bits 4-5 are resolution which is in "units/inch".
-	      The Logitech MouseMan returns these bits clear but it has
-	      200/300cpi resolution.
-	      Bits 0-3 are unique vendor id.
-    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
-	      Bits 2-3 should be 8 + 4.
-		      Bits 4-7 should be 3 for a mouse device.
-    data[3] = bxxx xxxx Left button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
-    data[5] = byyy bxxx Third button and fourth button.  Y is additional
-	      high bits of y-axis motion.  XY is additional
-	      high bits of x-axis motion.
-
-    NOTE: data[0] and data[2] are confirmed by the parent function and
-    need not be checked here.
-  */
-
-  /*
     Handler 1 -- 100cpi original Apple mouse protocol.
     Handler 2 -- 200cpi original Apple mouse protocol.
 
@@ -433,28 +404,27 @@
     contain the following values:
 
                 BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = ???? ???? (?)
-    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
-    data[3] = bxxx xxxx First button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx First button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
+
+    Handler 4 -- Apple Extended mouse protocol.
 
-    NOTE: data[0] is confirmed by the parent function and need not be
-    checked here.
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx Left button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
+    data[3] = byyy bxxx Third button and fourth button.  Y is additional
+	      high bits of y-axis motion.  XY is additional
+	      high bits of x-axis motion.
   */
 	struct kbd_struct *kbd;
 
 	if (adb_mouse_interrupt_hook)
 		adb_mouse_interrupt_hook(data, nb);
-	else
-		if (console_loglevel == 10)
-		    printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", 
-			data[1], data[2], data[3],
-			~((data[1] & 0x80 ? 0 : 4) 
-			| (data[2] & 0x80 ? 0 : 1)
-			| (data[3] & 0x80 ? 0 : 2))&7,
-			((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ),
-			((data[1]&0x7f) < 64 ? -(data[1]&0x7f) : 128-(data[1]&0x7f) ) );
 
 	kbd = kbd_table + fg_console;
 
@@ -464,9 +434,9 @@
 		unsigned char uchButtonSecond;
 
 		/* Send first button, second button and movement. */
-		put_queue( 0x7e );
-		put_queue( data[1] );
-		put_queue( data[2] );
+		mac_put_queue(0x7e);
+		mac_put_queue(data[1]);
+		mac_put_queue(data[2]);
 
 		/* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
 
@@ -475,12 +445,12 @@
 
 		/* Send second button. */
 		if (uchButtonSecond != uch_ButtonStateSecond) {
-			put_queue( 0x3f | uchButtonSecond );
+			mac_put_queue(0x3f | uchButtonSecond);
 			uch_ButtonStateSecond = uchButtonSecond;
 		}
 
 		/* Macintosh 3-button mouse (handler 4). */
-		if ((nb == 4) && autopoll /*?*/) {
+		if (nb == 4) {
 			static unsigned char uch_ButtonStateThird = 0x80;
 			unsigned char uchButtonThird;
 
@@ -489,12 +459,13 @@
 
 			/* Send third button. */
 			if (uchButtonThird != uch_ButtonStateThird) {
-				put_queue( 0x40 | uchButtonThird );
+				mac_put_queue(0x40 | uchButtonThird);
 				uch_ButtonStateThird = uchButtonThird;
 			}
 		}
 	}
 }
+#endif /* CONFIG_ADBMOUSE */
 
 /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
 static unsigned char mac_ledmap[8] = {
@@ -571,11 +542,14 @@
 	memcpy(key_maps[8], macalt_map, sizeof(plain_map));
 	memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map));
 
+#ifdef CONFIG_ADBMOUSE
 	/* initialize mouse interrupt hook */
 	adb_mouse_interrupt_hook = NULL;
 
-	adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input);
 	adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input);
+#endif /* CONFIG_ADBMOUSE */
+
+	adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input);
 
 	for(i = 0; i < keyboard_ids.nids; i++) {
 	    /* turn off all leds */
@@ -633,10 +607,4 @@
 		ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38);
 	    }
 	}
-}
-
-void adb_setup_mouse( char *s, int *ints )
-{
-       if (ints[0] >= 1)
-	       adb_emulate_buttons = ints[1];
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- v2.1.128/linux/drivers/macintosh/macio-adb.c	Fri May  8 23:14:47 1998
+++ linux/drivers/macintosh/macio-adb.c	Sun Nov 15 10:51:46 1998
@@ -61,8 +61,9 @@
 
 static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
 static int macio_adb_send_request(struct adb_request *req, int sync);
-static int macio_adb_autopoll(int on);
+static int macio_adb_autopoll(int devs);
 static void macio_adb_poll(void);
+static int macio_reset_bus(void);
 static void completed(void);
 
 __openfirmware
@@ -108,14 +109,30 @@
 	adb_hardware = ADB_MACIO;
 	adb_send_request = macio_adb_send_request;
 	adb_autopoll = macio_adb_autopoll;
+	adb_reset_bus = macio_reset_bus;
 }
 
-static int macio_adb_autopoll(int on)
+static int macio_adb_autopoll(int devs)
 {
-	out_8(&adb->autopoll.r, on? APE: 0);
+	out_8(&adb->active_hi.r, devs >> 8);
+	out_8(&adb->active_lo.r, devs);
+	out_8(&adb->autopoll.r, devs? APE: 0);
 	return 0;
 }
 
+static int macio_reset_bus(void)
+{
+	int timeout = 1000000;
+
+	out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
+	while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
+		if (--timeout == 0) {
+			out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST);
+			return -1;
+		}
+	}
+	return 0;
+}
 
 /* Send an ADB command */
 static int macio_adb_send_request(struct adb_request *req, int sync)
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.1.128/linux/drivers/macintosh/macserial.c	Sun Nov  8 14:02:58 1998
+++ linux/drivers/macintosh/macserial.c	Tue Nov 17 14:57:24 1998
@@ -33,6 +33,7 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
+#include <asm/feature.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -165,25 +166,35 @@
 				       unsigned char reg)
 {
 	unsigned char retval;
+	unsigned long flags;
 
+	/*
+	 * We have to make this atomic.
+	 */
+	spin_lock_irqsave(&channel->lock, flags);
 	if (reg != 0) {
 		*channel->control = reg;
 		RECOVERY_DELAY;
 	}
 	retval = *channel->control;
 	RECOVERY_DELAY;
+	spin_unlock_irqrestore(&channel->lock, flags);
 	return retval;
 }
 
 static inline void write_zsreg(struct mac_zschannel *channel,
 			       unsigned char reg, unsigned char value)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->lock, flags);
 	if (reg != 0) {
 		*channel->control = reg;
 		RECOVERY_DELAY;
 	}
 	*channel->control = value;
 	RECOVERY_DELAY;
+	spin_unlock_irqrestore(&channel->lock, flags);
 	return;
 }
 
@@ -434,6 +445,10 @@
 
 	for (;;) {
 		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+#ifdef SERIAL_DEBUG_INTR
+//		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+#endif	
+
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
@@ -1261,6 +1276,15 @@
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
+
+	if (info->is_cobalt_modem) {
+		/* Power down modem */
+		feature_set(info->dev_node, FEATURE_Modem_Reset);
+		mdelay(15);
+		feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+		mdelay(15);
+	}
+
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
@@ -1271,6 +1295,7 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	
 	restore_flags(flags);
 }
 
@@ -1508,9 +1533,25 @@
 	/*
 	 * Start up serial port
 	 */
+
+	if (info->is_cobalt_modem) {
+		/* Power up modem */
+		feature_set(info->dev_node, FEATURE_Modem_PowerOn);
+		mdelay(250);
+		feature_clear(info->dev_node, FEATURE_Modem_Reset);
+		mdelay(10);
+	}
 	retval = startup(info);
-	if (retval)
+	if (retval) {
+		if (info->is_cobalt_modem) {
+			/* Power down modem */
+			feature_set(info->dev_node, FEATURE_Modem_Reset);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+			mdelay(15);
+		}
 		return retval;
+	}
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
@@ -1518,6 +1559,13 @@
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
 #endif
+		if (info->is_cobalt_modem) {
+			/* Power down modem */
+			feature_set(info->dev_node, FEATURE_Modem_Reset);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+			mdelay(15);
+		}
 		return retval;
 	}
 
@@ -1568,8 +1616,14 @@
 			       dev->full_name);
 			continue;
 		}
+		feature_clear(dev, FEATURE_Serial_reset);
+		mdelay(5);
+		feature_set(dev, FEATURE_Serial_enable);
+		feature_set(dev, FEATURE_Serial_IO_A);
+		feature_set(dev, FEATURE_Serial_IO_B);
+		mdelay(5);
 		for (ch = dev->child; ch != 0; ch = ch->sibling) {
-			if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+			if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
 				printk("Can't use %s: %d addrs %d intrs\n",
 				      ch->full_name, ch->n_addrs, ch->n_intrs);
 				continue;
@@ -1578,8 +1632,20 @@
 				ioremap(ch->addrs[0].address, 0x1000);
 			zs_channels[n].data = zs_channels[n].control
 				+ ch->addrs[0].size / 2;
+			spin_lock_init(&zs_channels[n].lock);
 			zs_soft[n].zs_channel = &zs_channels[n];
+			zs_soft[n].dev_node = ch;
 			zs_soft[n].irq = ch->intrs[0].line;
+			zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
+			if (zs_soft[n].is_cobalt_modem)
+			{
+				/* Just in case the modem is up, shut it down */
+				feature_set(ch, FEATURE_Modem_Reset);
+				mdelay(15);
+				feature_clear(ch, FEATURE_Modem_PowerOn);
+				mdelay(15);
+			}
+
 			/* XXX this assumes the prom puts chan A before B */
 			if (n & 1)
 				zs_soft[n].zs_chan_a = &zs_channels[n-1];
@@ -1696,6 +1762,9 @@
 
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 	{
+		unsigned char* connector;
+		int lenp;
+
 #ifdef CONFIG_KGDB
 		if (info->kgdb_channel) {
 			continue;
@@ -1719,8 +1788,14 @@
 		info->open_wait = 0;
 		info->close_wait = 0;
 		printk("tty%02d at 0x%08x (irq = %d)", info->line, 
-		       info->port, info->irq);
-		printk(" is a Z8530 ESCC\n");
+			info->port, info->irq);
+		printk(" is a Z8530 ESCC");
+		connector = get_property(info->dev_node, "AAPL,connector", &lenp);
+		if (connector)
+			printk(", port = %s", connector);
+		if (info->is_cobalt_modem)
+			printk(" (cobalt modem)");
+		printk("\n");
 	}
 
 	restore_flags(flags);
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- v2.1.128/linux/drivers/macintosh/macserial.h	Sat Aug 16 09:53:08 1997
+++ linux/drivers/macintosh/macserial.h	Sun Nov 15 10:51:47 1998
@@ -84,6 +84,7 @@
 struct mac_zschannel {
 	volatile unsigned char *control;
 	volatile unsigned char *data;
+	spinlock_t	lock;
 };
 
 struct mac_serial {
@@ -91,11 +92,13 @@
 	struct mac_zschannel *zs_channel; /* Channel registers */
 	struct mac_zschannel *zs_chan_a;	/* A side registers */
 	unsigned char read_reg_zero;
+	struct device_node* dev_node;
 
 	char soft_carrier;  /* Use soft carrier on this channel */
 	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. */
+	char is_cobalt_modem;	/* is a gatwick-based cobalt modem */
 	unsigned char tx_active; /* character is being xmitted */
 	unsigned char tx_stopped; /* output is suspended */
 
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.1.128/linux/drivers/macintosh/mediabay.c	Sun Nov  8 14:02:59 1998
+++ linux/drivers/macintosh/mediabay.c	Sun Nov 15 10:51:47 1998
@@ -8,6 +8,8 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
+#define __KERNEL_SYSCALLS__
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -16,44 +18,54 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/hdreg.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/ohare.h>
+#include <asm/feature.h>
 #include <asm/mediabay.h>
 #include <asm/init.h>
 
+
+#undef MB_USE_INTERRUPTS
+
 struct media_bay_hw {
 	unsigned char	b0;
 	unsigned char	contents;
 	unsigned char	b2;
 	unsigned char	b3;
-	unsigned	feature;
 };
 
-static volatile struct media_bay_hw *mb_addr;
+struct media_bay_info {
+	volatile struct media_bay_hw*	addr;
+	int				content_id;
+	int				previous_id;
+	int				ready;
+	int				last_value;
+	int				value_count;
+	int				reset_timer;
+	struct device_node*		dev_node;
+#ifdef CONFIG_BLK_DEV_IDE
+	unsigned long			cd_base;
+	int 				cd_index;
+	int				cd_irq;
+	int				cd_timer;
+#endif
+};
 
-#define MB_CONTENTS()	((in_8(&mb_addr->contents) >> 4) & 7)
-#define SET_FEATURES(set, clr) \
-	out_le32(&mb_addr->feature, \
-		 (in_le32(&mb_addr->feature) & ~(clr)) | (set));
+#define MAX_BAYS	2
 
-static int media_bay_id = -1;
-static int mb_ready;
-static int mb_last_value;
-static int mb_value_count;
+static volatile struct media_bay_info media_bays[MAX_BAYS];
+int media_bay_count = 0;
 
-int media_bay_present;
+#define MB_CONTENTS(i)	((in_8(&media_bays[i].addr->contents) >> 4) & 7)
 
 #ifdef CONFIG_BLK_DEV_IDE
-unsigned long mb_cd_base;
-int mb_cd_index = -1;
-int mb_cd_irq;
-
 /* check the busy bit in the media-bay ide interface
    (assumes the media-bay contains an ide device) */
-#define MB_IDE_READY()	((in_8((volatile unsigned char *) \
-			       (mb_cd_base + 0x70)) & 0x80) == 0)
+#define MB_IDE_READY(i)	((in_8((volatile unsigned char *) \
+			       (media_bays[i].cd_base + 0x70)) & 0x80) == 0)
 #endif
 
 /*
@@ -66,16 +78,17 @@
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_COUNT	10
+#define MB_RESET_COUNT	20
 
 /*
  * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
  * (or until the device is ready) before registering the IDE interface.
  */
-#define MB_IDE_WAIT	500
+#define MB_IDE_WAIT	1000
 
-static void poll_media_bay(void);
-static void set_media_bay(int id);
+static void poll_media_bay(int which);
+static void set_media_bay(int which, int id);
+static int media_bay_task(void *);
 
 /*
  * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
@@ -92,29 +105,62 @@
 media_bay_init(void)
 {
 	struct device_node *np;
-
-	np = find_devices("media-bay");
-	if (np == NULL || np->n_addrs == 0)
-		return;
-	mb_addr = (volatile struct media_bay_hw *)
-		ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
-
-#if 0
-	if (np->n_intrs == 0) {
-		printk(KERN_WARNING "No interrupt for media bay?\n");
-	} else {
-		if (request_irq(np->intrs[0].line, media_bay_intr, 0,
-				"Media bay", NULL))
-			printk(KERN_WARNING "Couldn't get IRQ %d for "
-			       "media bay\n", np->intrs[0].line);
+	int		n,i;
+	
+	for (i=0; i<MAX_BAYS; i++)
+	{
+		memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
+		media_bays[i].content_id	= -1;
+#ifdef CONFIG_BLK_DEV_IDE
+		media_bays[i].cd_index		= -1;
+#endif
 	}
+	
+	np = find_devices("media-bay");
+	n = 0;
+	while(np && (n<MAX_BAYS))
+	{
+		if (np->n_addrs == 0)
+			continue;
+		media_bays[n].addr = (volatile struct media_bay_hw *)
+			ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
+
+#ifdef MB_USE_INTERRUPTS
+		if (np->n_intrs == 0)
+		{
+			printk(KERN_ERR "media bay %d has no irq\n",n);
+			continue;
+		}
+		
+		if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL))
+		{
+			printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n);
+			continue;
+		}
+#endif	
+		media_bay_count++;
+	
+		set_media_bay(n, MB_CONTENTS(n));
+		if (media_bays[n].content_id != MB_NO) {
+			feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset);
+			udelay(500);
+		}
+		media_bays[n].ready		= 1;
+		media_bays[n].previous_id	= media_bays[n].content_id;
+		media_bays[n].reset_timer	= 0;
+		media_bays[n].dev_node		= np;
+#ifdef CONFIG_BLK_DEV_IDE
+		media_bays[n].cd_timer		= 0;
 #endif
+		n++;
+		np=np->next;
+	}
+	
+	if (media_bay_count)
+	{
+		printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
 
-	media_bay_present = 1;
-	set_media_bay(MB_CONTENTS());
-	if (media_bay_id != MB_NO) {
-		SET_FEATURES(0, OH_BAY_RESET);
-		mb_ready = 1;
+		kernel_thread(media_bay_task, NULL, 0);
 	}
 }
 
@@ -130,9 +176,61 @@
 #endif
 
 int
-check_media_bay(int what)
+check_media_bay(struct device_node *which_bay, int what)
 {
-	return what == media_bay_id && mb_ready;
+#ifdef CONFIG_BLK_DEV_IDE
+	int	i;
+	
+	for (i=0; i<media_bay_count; i++)
+		if (which_bay == media_bays[i].dev_node)
+		{
+			if ((what == media_bays[i].content_id) && media_bays[i].ready)
+				return 0;
+			media_bays[i].cd_index = -1;
+			return -EINVAL;
+		}
+#endif /* CONFIG_BLK_DEV_IDE */
+	return -ENODEV;
+}
+
+int
+check_media_bay_by_base(unsigned long base, int what)
+{
+	int	i;
+
+#ifdef CONFIG_BLK_DEV_IDE
+	for (i=0; i<media_bay_count; i++)
+		if (base == media_bays[i].cd_base)
+		{
+			if ((what == media_bays[i].content_id) && media_bays[i].ready)
+				return 0;
+			media_bays[i].cd_index = -1;
+			return -EINVAL;
+		} 
+#endif
+	
+	return -ENODEV;
+}
+
+int
+media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
+	int irq, int index)
+{
+	int	i;
+	
+#ifdef CONFIG_BLK_DEV_IDE
+	for (i=0; i<media_bay_count; i++)
+		if (which_bay == media_bays[i].dev_node)
+		{
+ 			media_bays[i].cd_base	= base;
+			media_bays[i].cd_irq	= irq;
+			media_bays[i].cd_index	= index;
+			printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);			
+			return 0;
+		} 
+#endif
+	
+	return -ENODEV;
 }
 
 /*
@@ -144,95 +242,112 @@
 int
 media_bay_task(void *x)
 {
-	int prev = media_bay_id;
-	int reset_timer = 0;
-#ifdef CONFIG_BLK_DEV_IDE
-	int cd_timer = 0;
-#endif
-
+	volatile struct media_bay_info* bay;
+	int	i = 0;
+	
 	strcpy(current->comm, "media-bay");
-	for (;;) {
-		poll_media_bay();
-		if (media_bay_id != prev) {
-			reset_timer = (media_bay_id != MB_NO)?
+	for (;;)
+	{
+		bay = &media_bays[i];
+		poll_media_bay(i);
+		if (bay->content_id != bay->previous_id) {
+			bay->reset_timer = (bay->content_id != MB_NO) ?
 				MB_RESET_COUNT: 0;
-			mb_ready = 0;
+			bay->ready = 0;
 #ifdef CONFIG_BLK_DEV_IDE
-			cd_timer = 0;
-			if (media_bay_id != MB_CD && mb_cd_index >= 0) {
-				printk(KERN_DEBUG "Unregistering mb ide\n");
-				ide_unregister(mb_cd_index);
-				mb_cd_index = -1;
+			bay->cd_timer = 0;
+			if (bay->content_id != MB_CD && bay->cd_index >= 0) {
+				printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index);
+				ide_unregister(bay->cd_index);
+				bay->cd_index = -1;
 			}
 #endif
-		} else if (reset_timer) {
-			if (--reset_timer == 0) {
-				SET_FEATURES(0, OH_BAY_RESET);
-				mb_ready = 1;
+		} else if (bay->reset_timer) {
+			if (--bay->reset_timer == 0) {
+ 				feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+				bay->ready = 1;
 #ifdef CONFIG_BLK_DEV_IDE
-				if (media_bay_id == MB_CD && mb_cd_base != 0)
-					cd_timer = MB_IDE_WAIT;
+				bay->cd_timer = 0;
+				if (bay->content_id == MB_CD && bay->cd_base != 0)
+					bay->cd_timer = MB_IDE_WAIT;
 #endif
 			}
 #ifdef CONFIG_BLK_DEV_IDE
-		} else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY())
-			   && mb_cd_index < 0) {
-			mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq);
-			printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index);
+		} else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i))
+			   && bay->cd_index < 0) {
+			bay->cd_timer = 0;
+			printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
+			printk("\n");
+			bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+			if (bay->cd_index == -1)
+				printk("\nCD-ROM badly inserted. Remove it and try again !\n");
+			else
+				printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
 #endif
 		}
 
-		prev = media_bay_id;
+		bay->previous_id = bay->content_id;
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(1);
 		if (signal_pending(current))
 			return 0;
+		i = (i+1)%media_bay_count;
 	}
 }
 
 void
-poll_media_bay(void)
+poll_media_bay(int which)
 {
-	int id = MB_CONTENTS();
+	int id = MB_CONTENTS(which);
 
-	if (id == mb_last_value) {
-		if (id != media_bay_id
-		    && ++mb_value_count >= MB_STABLE_COUNT)
-			set_media_bay(id);
+	if (id == media_bays[which].last_value) {
+		if (id != media_bays[which].content_id
+		    && ++media_bays[which].value_count >= MB_STABLE_COUNT)
+ 			set_media_bay(which, id);
 	} else {
-		mb_last_value = id;
-		mb_value_count = 0;
+		media_bays[which].last_value = id;
+		media_bays[which].value_count = 0;
 	}
 }
 
 static void
-set_media_bay(int id)
+set_media_bay(int which, int id)
 {
-	u32 clr, set;
+	volatile struct media_bay_info* bay;
 
-	media_bay_id = id;
-	mb_last_value = id;
-	clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER;
-	set = 0;
+	bay = &media_bays[which];
+	
+	bay->content_id = id;
+	bay->last_value = id;
+	
 	switch (id) {
 	case MB_CD:
-		set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE;
-		printk(KERN_INFO "media bay contains a CD-ROM drive\n");
+		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+		feature_set(bay->dev_node, FEATURE_CD_power);
+		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
 		break;
 	case MB_FD:
-		set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE;
-		printk(KERN_INFO "media bay contains a floppy disk drive\n");
+		feature_clear(bay->dev_node, FEATURE_CD_power);
+		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+		feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_set(bay->dev_node, FEATURE_SWIM3_enable);
+		printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
 		break;
 	case MB_NO:
-		printk(KERN_INFO "media bay is empty\n");
+		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_clear(bay->dev_node, FEATURE_CD_power);
+		printk(KERN_INFO "media bay %d is empty\n", which);
 		break;
 	default:
-		set = OH_BAY_ENABLE;
-		printk(KERN_INFO "media bay contains an unknown device (%d)\n",
-		       id);
+		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_clear(bay->dev_node, FEATURE_CD_power);
+		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+		printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
+		       which, id);
 		break;
 	}
-
-	SET_FEATURES(set, clr);
-	printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature));
+	
+	udelay(500);
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.1.128/linux/drivers/macintosh/via-cuda.c	Sun Jun  7 11:16:31 1998
+++ linux/drivers/macintosh/via-cuda.c	Sun Nov 15 10:51:47 1998
@@ -80,7 +80,8 @@
 static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
 static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
 static int cuda_adb_send_request(struct adb_request *req, int sync);
-static int cuda_adb_autopoll(int on);
+static int cuda_adb_autopoll(int devs);
+static int cuda_reset_bus(void);
 
 __openfirmware
 
@@ -141,6 +142,7 @@
     /* Set function pointers */
     adb_send_request = cuda_adb_send_request;
     adb_autopoll = cuda_adb_autopoll;
+    adb_reset_bus = cuda_reset_bus;
 }
 
 #define WAIT_FOR(cond, what)				\
@@ -216,11 +218,23 @@
 
 /* Enable/disable autopolling */
 static int
-cuda_adb_autopoll(int on)
+cuda_adb_autopoll(int devs)
 {
     struct adb_request req;
 
-    cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, on);
+    cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0));
+    while (!req.complete)
+	cuda_poll();
+    return 0;
+}
+
+/* Reset adb bus - how do we do this?? */
+static int
+cuda_reset_bus(void)
+{
+    struct adb_request req;
+
+    cuda_request(&req, NULL, 2, ADB_PACKET, 0);		/* maybe? */
     while (!req.complete)
 	cuda_poll();
     return 0;
diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.1.128/linux/drivers/macintosh/via-pmu.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/macintosh/via-pmu.c	Sun Nov 15 10:51:47 1998
@@ -30,6 +30,7 @@
 #include <asm/system.h>
 #include <asm/init.h>
 #include <asm/irq.h>
+#include <asm/feature.h>
 
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR	154
@@ -99,7 +100,8 @@
 static void pmu_start(void);
 static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
 static int pmu_adb_send_request(struct adb_request *req, int sync);
-static int pmu_adb_autopoll(int on);
+static int pmu_adb_autopoll(int devs);
+static int pmu_reset_bus(void);
 static void send_byte(int x);
 static void recv_byte(void);
 static void pmu_sr_intr(struct pt_regs *regs);
@@ -162,6 +164,8 @@
 		return;
 	if (vias->next != 0)
 		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
+	
+	feature_set(vias, FEATURE_VIA_enable);
 
 #if 0
 	{ int i;
@@ -215,6 +219,7 @@
 	/* Set function pointers */
 	adb_send_request = pmu_adb_send_request;
 	adb_autopoll = pmu_adb_autopoll;
+	adb_reset_bus = pmu_reset_bus;
 }
 
 static int
@@ -281,11 +286,12 @@
 
 /* Enable/disable autopolling */
 static int
-pmu_adb_autopoll(int on)
+pmu_adb_autopoll(int devs)
 {
 	struct adb_request req;
 
-	if (on) {
+	if (devs) {
+		adb_dev_map = devs;
 		pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
 			    adb_dev_map >> 8, adb_dev_map);
 		pmu_adb_flags = 2;
@@ -298,6 +304,49 @@
 	return 0;
 }
 
+/* Reset the ADB bus */
+static int
+pmu_reset_bus(void)
+{
+	struct adb_request req;
+	long timeout;
+	int save_autopoll = adb_dev_map;
+
+	/* anyone got a better idea?? */
+	pmu_adb_autopoll(0);
+
+	req.nbytes = 5;
+	req.done = NULL;
+	req.data[0] = PMU_ADB_CMD;
+	req.data[1] = 0;
+	req.data[2] = 3;
+	req.data[3] = 0;
+	req.data[4] = 0;
+	req.reply_len = 0;
+	req.reply_expected = 1;
+	if (pmu_queue_request(&req) != 0)
+	{
+		printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n");
+		return 0;
+	}
+	while (!req.complete)
+		pmu_poll();
+	timeout = 100000;
+	while (!req.complete) {
+		if (--timeout < 0) {
+			printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n");
+			return 0;
+		}
+		udelay(10);
+		pmu_poll();
+	}
+
+	if (save_autopoll != 0)
+		pmu_adb_autopoll(save_autopoll);
+		
+	return 1;
+}
+
 /* Construct and send a pmu request */
 int
 pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
@@ -366,7 +415,10 @@
 			req->nbytes = 5;
 			for (i = 1; i <= 4; ++i)
 				req->data[i] = req->data[i+1];
-			req->reply_len = 0;
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_SET_TIME;
 			return pmu_queue_request(req);
 		}
 		break;
@@ -691,6 +743,44 @@
 {
 }
 
+void
+pmu_restart(void)
+{
+	struct adb_request req;
+
+	_disable_interrupts();
+	
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT);
+	while(!req.complete)
+		pmu_poll();
+	
+	pmu_request(&req, NULL, 1, PMU_RESET);
+	while(!req.complete || (pmu_state != idle))
+		pmu_poll();
+	for (;;)
+		;
+}
+
+void
+pmu_shutdown(void)
+{
+	struct adb_request req;
+
+	_disable_interrupts();
+	
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT);
+	while(!req.complete)
+		pmu_poll();
+
+	pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
+		    'M', 'A', 'T', 'T');
+	while(!req.complete || (pmu_state != idle))
+		pmu_poll();
+	for (;;)
+		;
+}
+
+
 #ifdef CONFIG_PMAC_PBOOK
 
 /*
@@ -855,11 +945,13 @@
 	notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
 
 	/* reenable ADB autopoll */
-	pmu_adb_autopoll(1);
+	pmu_adb_autopoll(adb_dev_map);
 
 	/* Turn on the screen backlight, if it was on before */
 	if (save_backlight)
 		pmu_enable_backlight(1);
+
+	/* Wait for the hard disk to spin up */
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.1.128/linux/drivers/misc/parport_arc.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/misc/parport_arc.c	Sun Nov 15 09:52:25 1998
@@ -14,6 +14,7 @@
  * a subset of the standard printer control lines connected.
  */
 
+#include <linux/config.h>
 #include <linux/tasks.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -141,7 +142,9 @@
 
 	printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
 	       p->irq);
+#ifdef	CONFIG_PROC_FS
 	parport_proc_register(p);
+#endif
 	p->flags |= PARPORT_FLAG_COMA;
 
 	if (parport_probe_hook)
diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c
--- v2.1.128/linux/drivers/misc/parport_ax.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/misc/parport_ax.c	Wed Nov 18 09:06:05 1998
@@ -1,4 +1,4 @@
-/* $Id: parport_ax.c,v 1.12 1998/07/26 03:03:31 davem Exp $
+/* $Id: parport_ax.c,v 1.14 1998/11/16 04:48:02 davem Exp $
  * Parallel-port routines for Sun Ultra/AX architecture
  * 
  * Author: Eddie C. Dost <ecd@skynet.be>
@@ -11,6 +11,7 @@
  *          Grant Guenther <grant@torque.net>
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -585,7 +586,9 @@
 		printmode(ECPPS2);
 	}
 	printk("]\n");
+#ifdef	CONFIG_PROC_FS
 	parport_proc_register(p);
+#endif
 	p->flags |= PARPORT_FLAG_COMA;
 
 	p->ops->write_control(p, 0x0c);
@@ -628,7 +631,9 @@
 		if (p->modes & PARPORT_MODE_PCSPP) { 
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
+#ifdef	CONFIG_PROC_FS
 			parport_proc_unregister(p);
+#endif
 			parport_unregister_port(p);
 		}
 		p = tmp;
diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.1.128/linux/drivers/misc/parport_init.c	Tue Apr 14 14:29:20 1998
+++ linux/drivers/misc/parport_init.c	Fri Nov 13 10:29:44 1998
@@ -98,13 +98,17 @@
 #ifdef MODULE
 int init_module(void)
 {
+#ifdef	CONFIG_PROC_FS
 	(void)parport_proc_init();	/* We can go on without it. */
+#endif
 	return 0;
 }
 
 void cleanup_module(void)
 {
+#ifdef	CONFIG_PROC_FS
 	parport_proc_cleanup();
+#endif
 }
 #else
 __initfunc(int parport_init(void))
@@ -115,7 +119,9 @@
 #ifdef CONFIG_PNP_PARPORT
 	parport_probe_hook = &parport_probe_one;
 #endif
+#ifdef	CONFIG_PROC_FS
 	parport_proc_init();
+#endif
 #ifdef CONFIG_PARPORT_PC
 	parport_pc_init(io, irq, dma);
 #endif
@@ -139,8 +145,10 @@
 EXPORT_SYMBOL(parport_enumerate);
 EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
 EXPORT_SYMBOL(parport_wait_peripheral);
+#ifdef	CONFIG_PROC_FS
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
+#endif
 EXPORT_SYMBOL(parport_probe_hook);
 EXPORT_SYMBOL(parport_parse_irqs);
 
diff -u --recursive --new-file v2.1.128/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.128/linux/drivers/misc/parport_pc.c	Sun Nov  8 14:02:59 1998
+++ linux/drivers/misc/parport_pc.c	Sun Nov 15 09:52:26 1998
@@ -34,6 +34,7 @@
  * accomodate this.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
@@ -755,9 +756,11 @@
 	}
 #undef printmode
 	printk("]\n");
+#ifdef	CONFIG_PROC_FS
 	if (probedirq != PARPORT_IRQ_NONE) 
 		printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
 	parport_proc_register(p);
+#endif
 	p->flags |= PARPORT_FLAG_COMA;
 
 	/* Done probing.  Now put the port into a sensible start-up state. */
@@ -821,7 +824,9 @@
 		if (p->modes & PARPORT_MODE_PCSPP) { 
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
+#ifdef	CONFIG_PROC_FS
 			parport_proc_unregister(p);
+#endif
 			parport_unregister_port(p);
 		}
 		p = tmp;
diff -u --recursive --new-file v2.1.128/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.1.128/linux/drivers/net/3c59x.c	Thu Nov 12 16:21:19 1998
+++ linux/drivers/net/3c59x.c	Fri Nov 13 10:29:44 1998
@@ -77,7 +77,6 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/timer.h>
 
 #include <asm/byteorder.h>
diff -u --recursive --new-file v2.1.128/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.128/linux/drivers/net/Space.c	Thu Nov 12 16:21:19 1998
+++ linux/drivers/net/Space.c	Fri Nov 13 10:29:43 1998
@@ -559,7 +559,7 @@
 #if defined(CONFIG_LTPC)
     extern int ltpc_probe(struct device *);
     static struct device dev_ltpc = {
-        "ltalk0\0   ",
+        "lt0\0   ",
                 0, 0, 0, 0,
                 0x0, 0,
                 0, 0, 0, NEXT_DEV, ltpc_probe };
diff -u --recursive --new-file v2.1.128/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.1.128/linux/drivers/net/at1700.c	Thu Nov 12 16:21:19 1998
+++ linux/drivers/net/at1700.c	Sun Nov 15 09:52:26 1998
@@ -33,6 +33,7 @@
 static const char *version =
 	"at1700.c:v1.15 4/7/98  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.128/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.1.128/linux/drivers/net/bmac.c	Sun Nov  8 14:02:59 1998
+++ linux/drivers/net/bmac.c	Sun Nov 15 10:51:47 1998
@@ -54,6 +54,7 @@
 	int rx_dma_intr;
 	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
 	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
+	struct device_node *node;
 	struct sk_buff *rx_bufs[N_RX_RING];
 	int rx_fill;
 	int rx_empty;
@@ -235,11 +236,11 @@
 	dbdma_reset(rd);
 	dbdma_reset(td);
 
-	feature_set(FEATURE_BMac_IO_enable);
+	feature_set(bp->node, FEATURE_BMac_IO_enable);
 	udelay(10000);
-	feature_set(FEATURE_BMac_reset);
+	feature_set(bp->node, FEATURE_BMac_reset);
 	udelay(10000);
-	feature_clear(FEATURE_BMac_reset);
+	feature_clear(bp->node, FEATURE_BMac_reset);
 	udelay(10000);
 }
 
@@ -374,8 +375,6 @@
 	//bmwrite(dev, TXCFG, TxMACEnable);	       	/* TxNeverGiveUp maybe later */
 	bmread(dev, STATUS);		/* read it just to clear it */
 
-	bmwrite(dev, INTDISABLE, EnableNormal);
-
 	/* zero out the chip Hash Filter registers */
 	for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
 	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); 	/* bits 15 - 0 */
@@ -387,10 +386,11 @@
 	bmwrite(dev, MADD0, *pWord16++);
 	bmwrite(dev, MADD1, *pWord16++);
 	bmwrite(dev, MADD2, *pWord16);
-    
 
 	bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
-    
+
+	bmwrite(dev, INTDISABLE, EnableNormal);
+
 	return;
 }
 
@@ -620,6 +620,8 @@
 	bp->tx_bufs[bp->tx_fill] = skb;
 	bp->tx_fill = i;
 
+	bp->stats.tx_bytes += skb->len;
+
 	dbdma_continue(td);
 
 	return 0;
@@ -669,6 +671,7 @@
 			skb_reserve(bp->rx_bufs[i], 2);
 			bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
 			++bp->stats.rx_packets;
+			bp->stats.rx_bytes += nb;
 		} else {
 			++bp->stats.rx_dropped;
 		}
@@ -1241,7 +1244,7 @@
     
 	dev->base_addr = bmacs->addrs[0].address;
 	dev->irq = bmacs->intrs[0].line;
-    
+
 	bmwrite(dev, INTDISABLE, DisableAll);
     
 	addr = get_property(bmacs, "mac-address", NULL);
@@ -1288,6 +1291,7 @@
 	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
 	skb_queue_head_init(bp->queue);
     
+	bp->node = bmacs;
 	memset(&bp->stats, 0, sizeof(bp->stats));
 	memset((char *) bp->tx_cmds, 0,
 	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
diff -u --recursive --new-file v2.1.128/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- v2.1.128/linux/drivers/net/hamradio/mkiss.c	Sun Jul 26 11:57:16 1998
+++ linux/drivers/net/hamradio/mkiss.c	Fri Nov 13 10:29:44 1998
@@ -894,7 +894,6 @@
 static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
 {
 	struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
-	int err;
 	unsigned int tmp;
 
 	/* First make sure we're connected. */
diff -u --recursive --new-file v2.1.128/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c
--- v2.1.128/linux/drivers/net/hostess_sv11.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/hostess_sv11.c	Fri Nov 13 10:29:44 1998
@@ -160,8 +160,8 @@
 
 static int hostess_ioctl(struct device *d, struct ifreq *ifr, int cmd)
 {
-	struct sv11_device *sv11=d->priv;
-	/* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
+	/* struct sv11_device *sv11=d->priv;
+	   z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
 	return sppp_do_ioctl(d, ifr,cmd);
 }
 
diff -u --recursive --new-file v2.1.128/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.1.128/linux/drivers/net/ltpc.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/ltpc.c	Fri Nov 13 10:29:43 1998
@@ -67,6 +67,25 @@
  * Hacked about a bit to clean things up - Alan Cox 
  * Probably broken it from the origina 1.8
  *
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+   and to probe for things in the standard order of i/o, irq, dma.  This
+   removes the "reset the reset" hack, because I couldn't figure out an
+   easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+   line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+   other localtalk driver, and to clear up the inconsistency between the
+   module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+   codes and the register offsets, but I'm still not sure exactly what their
+   semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+   I'm responsible for that...
+
+ *
  * Revision 1.7  1996/12/12 03:42:33  bradford
  * DMA alloc cribbed from 3c505.c.
  *
@@ -180,6 +199,9 @@
 #define DEBUG_UPPER 2
 #define DEBUG_LOWER 4
 
+static int io=0;
+static int irq=0;
+static int dma=0;
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -245,25 +267,34 @@
         return __get_dma_pages(GFP_KERNEL, order);
 }
 
+/* DMA data buffer, DMA command buffer */
 static unsigned char *ltdmabuf;
 static unsigned char *ltdmacbuf;
 
+/* private struct, holds our appletalk address */
+
 struct ltpc_private
 {
 	struct net_device_stats stats;
 	struct at_addr my_addr;
 };
 
+/* transmit queue element struct */
+
 struct xmitQel {
 	struct xmitQel *next;
+	/* command buffer */
 	unsigned char *cbuf;
 	short cbuflen;
+	/* data buffer */
 	unsigned char *dbuf;
 	short dbuflen;
 	unsigned char QWrite;	/* read or write data */
 	unsigned char mailbox;
 };
 
+/* the transmit queue itself */
+
 static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
 
 static void enQ(struct xmitQel *qel)
@@ -310,8 +341,10 @@
 	return qel;
 }
 
+/* and... the queue elements we'll be using */
 static struct xmitQel qels[16];
 
+/* and their corresponding mailboxes */
 static unsigned char mailbox[16];
 static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
@@ -331,6 +364,8 @@
 	return 1; /* timed out */
 }
 
+/* get the first free mailbox */
+
 static int getmbox(void)
 {
 	unsigned long flags;
@@ -347,6 +382,7 @@
 	return 0;
 }
 
+/* read a command from the card */
 static void handlefc(struct device *dev)
 {
 	/* called *only* from idle, non-reentrant */
@@ -370,6 +406,7 @@
 	if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
 }
 
+/* read data from the card */
 static void handlefd(struct device *dev)
 {
 	int dma = dev->dma;
@@ -463,7 +500,8 @@
 	if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
 } 
 
-static unsigned char rescbuf[2] = {0,0};
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
 static unsigned char resdbuf[2];
 
 static int QInIdle=0;
@@ -482,7 +520,7 @@
 	struct xmitQel *q=0;
 	int oops;
 	int i;
-	int statusPort = dev->base_addr+6;
+	int base = dev->base_addr;
 
 	save_flags(flags);
 	cli();
@@ -495,8 +533,8 @@
 
 	restore_flags(flags);
 
-
-	(void) inb_p(statusPort); /* this tri-states the IRQ line */
+	/* this tri-states the IRQ line */
+	(void) inb_p(base+6);
 
 	oops = 100;
 
@@ -506,19 +544,22 @@
 		goto done;
 	}
 
-	state = inb_p(statusPort);
-	if (state != inb_p(statusPort)) goto loop;
+	state = inb_p(base+6);
+	if (state != inb_p(base+6)) goto loop;
 
 	switch(state) {
-		case 0xfc: 
+		case 0xfc:
+			/* incoming command */
 			if (debug&DEBUG_LOWER) printk("idle: fc\n");
 			handlefc(dev); 
 			break;
-		case 0xfd: 
+		case 0xfd:
+			/* incoming data */
 			if(debug&DEBUG_LOWER) printk("idle: fd\n");
 			handlefd(dev); 
 			break;
-		case 0xf9: 
+		case 0xf9:
+			/* result ready */
 			if (debug&DEBUG_LOWER) printk("idle: f9\n");
 			if(!mboxinuse[0]) {
 				mboxinuse[0] = 1;
@@ -536,6 +577,7 @@
 				printk("timed out idle f9\n");
 			break;
 		case 0xf8:
+			/* ?? */
 			if (xmQhd) {
 				inb_p(dev->base_addr+1);
 				inb_p(dev->base_addr+0);
@@ -545,7 +587,8 @@
 				goto done;
 			}
 			break;
-		case 0xfa: 
+		case 0xfa:
+			/* waiting for command */
 			if(debug&DEBUG_LOWER) printk("idle: fa\n");
 			if (xmQhd) {
 				q=deQ();
@@ -561,7 +604,7 @@
 					printk("\n");
 				}
 				handlecommand(dev);
-					if(0xfa==inb_p(statusPort)) {
+					if(0xfa==inb_p(base+6)) {
 						/* we timed out, so return */
 						goto done;
 					} 
@@ -582,13 +625,17 @@
 				}
 			} 
 			break;
-		case 0xfb:
+		case 0Xfb:
+			/* data transfer ready */
 			if(debug&DEBUG_LOWER) printk("idle: fb\n");
 			if(q->QWrite) {
 				memcpy(ltdmabuf,q->dbuf,q->dbuflen);
 				handlewrite(dev);
 			} else {
 				handleread(dev);
+				/* non-zero mailbox numbers are for
+				   commmands, 0 is for GETRESULT
+				   requests */
 				if(q->mailbox) {
 					memcpy(q->dbuf,ltdmabuf,q->dbuflen);
 				} else { 
@@ -605,13 +652,14 @@
 	QInIdle=0;
 
 	/* now set the interrupts back as appropriate */
-	/* the first 7 takes it out of tri-state (but still high) */
+	/* the first read takes it out of tri-state (but still high) */
 	/* the second resets it */
-	/* note that after this point, any read of 6 will trigger an interrupt */
+	/* note that after this point, any read of base+6 will
+	   trigger an interrupt */
 
 	if (dev->irq) {
-		inb_p(dev->base_addr+7);
-		inb_p(dev->base_addr+7);
+		inb_p(base+7);
+		inb_p(base+7);
 	}
 	return;
 }
@@ -703,6 +751,8 @@
 	return do_write(dev, &c, sizeof(c.setflags),&c,0);
 }
 
+/* LLAP to DDP translation */
+
 static int sendup_buffer (struct device *dev)
 {
 	/* on entry, command is in ltdmacbuf, data in ltdmabuf */
@@ -912,23 +962,14 @@
 	if (!dev)
 		return;  /* we've been downed */
 
-	if (dev->irq) 
-	{
-		/* we're set up for interrupts */
-		if (0xf8 != inb_p(dev->base_addr+7)) {
-			/* trigger an interrupt */
-			(void) inb_p(dev->base_addr+6);
-		}
-		ltpc_timer.expires = jiffies+100;
-	} else {
-		/* we're strictly polling mode */
-		idle(dev);
-		ltpc_timer.expires = jiffies+5;
-	}
-
+	idle(dev);
+	ltpc_timer.expires = jiffies+5;
+	
 	add_timer(&ltpc_timer);
 }
 
+/* DDP to LLAP translation */
+
 static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
 {
 	/* in kernel 1.3.xx, on entry skb->data points to ddp header,
@@ -975,150 +1016,18 @@
 	return stats;
 }
 
-static unsigned short irqhitmask;
-
-__initfunc(static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr))
-{
-	irqhitmask |= 1<<irq;
-}
-
-__initfunc(int ltpc_probe(struct device *dev))
+/* initialization stuff */
+  
+__initfunc(int ltpc_probe_dma(int base))
 {
-	int err;
-	unsigned char dma=0;
-	short base=0;
-	unsigned char irq=0;
-	int x=0,y=0;
-	int timeout;
-	int probe3, probe4, probe9;
-	unsigned short straymask;
-	unsigned long flags;
-	unsigned long f;
-
-	err = ltpc_init(dev);
-	if (err) return err;
-
-	/* occasionally the card comes up with reset latched, so we need
-	 * to "reset the reset" first of all -- check the irq first also
-	 */
-
-	save_flags(flags);
-	cli();
-
-	probe3 = request_irq( 3, &lt_probe_handler, 0, "ltpc_probe",dev);
-	probe4 = request_irq( 4, &lt_probe_handler, 0, "ltpc_probe",dev);
-	probe9 = request_irq( 9, &lt_probe_handler, 0, "ltpc_probe",dev);
-
-	irqhitmask = 0;
-
-	sti();
-
-	timeout = jiffies+2;
-	while(timeout>jiffies) ;  /* wait for strays */
-
-	straymask = irqhitmask;  /* pick up any strays */
- 
-	/* if someone already owns this address, don't probe */ 
-	if (!check_region(0x220,8)) {
-		inb_p(0x227);
-		inb_p(0x227);
-		x=inb_p(0x226);
-		timeout = jiffies+2;
-		while(timeout>jiffies) ;
-		if(straymask != irqhitmask) base = 0x220;
-	}
-	if (!check_region(0x240,8)) {
-		inb_p(0x247);
-		inb_p(0x247);
-		y=inb_p(0x246);
-		timeout = jiffies+2;
-		while(timeout>jiffies) ;
-		if(straymask != irqhitmask) base = 0x240;
-	}
-
-	/* at this point, either we have an irq and the base addr, or
-	 * there isn't any irq and we don't know the base address, but
-	 * in either event the card is no longer latched in reset and
-	 * the irq request line is tri-stated.
-	 */
-
-	cli();
- 
-	if (!probe3) free_irq(3,dev);
-	if (!probe4) free_irq(4,dev);
-	if (!probe9) free_irq(9,dev);
-
-	sti();
- 
-	irqhitmask &= ~straymask;
-
-	irq = ffz(~irqhitmask);
-	if (irqhitmask != 1<<irq)
-		printk("ltpc card raised more than one interrupt!\n");
-
-	if (!base) {
-		if (!check_region(0x220,8)) {
-			x = inb_p(0x220+6);
-			if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
-		}
- 
-		if (!check_region(0x240,8)) {
-			y = inb_p(0x240+6);
-			if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
-		} 
-	}
-
-	if(base) {
-		request_region(base,8,"ltpc");
-	} else {
-		printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
-		restore_flags(flags);
-		return -1;
-	}
-
-	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
-	if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
-
-	if (!ltdmabuf) {
-		printk("ltpc: mem alloc failed\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	if(debug&DEBUG_VERBOSE) {
-		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
-	}
-
-	/* reset the card */
-
-	inb_p(base+1);
-	inb_p(base+3);
-	timeout = jiffies+2;
-	while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
-	inb_p(base+0);
-	inb_p(base+2);
-	inb_p(base+7); /* clear reset */
-	inb_p(base+4); 
-	inb_p(base+5);
-	inb_p(base+5); /* enable dma */
-	inb_p(base+6); /* tri-state interrupt line */
-
-	timeout = jiffies+100;
-	
-	while(timeout>jiffies) {
-		/* wait for the card to complete initialization */
-	}
- 
-	/* now, figure out which dma channel we're using */
-
-	/* set up both dma 1 and 3 for read call */
-
-	if (!request_dma(1,"ltpc")) {
-	
-		f=claim_dma_lock();
-		disable_dma(1);
-		clear_dma_ff(1);
+	int dma = 0;
+  	int timeout;
+  	unsigned long f;
+  
+  	if (!request_dma(1,"ltpc")) {
+  		f=claim_dma_lock();
+  		disable_dma(1);
+  		clear_dma_ff(1);
 		set_dma_mode(1,DMA_MODE_WRITE);
 		set_dma_addr(1,virt_to_bus(ltdmabuf));
 		set_dma_count(1,sizeof(struct lt_mem));
@@ -1142,26 +1051,26 @@
 
 	/* FIXME -- do timings better! */
 
-	ltdmabuf[0] = 2; /* read request */
+	ltdmabuf[0] = LT_READMEM;
 	ltdmabuf[1] = 1;  /* mailbox */
 	ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
 	ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
 	ltdmabuf[6] = 0; /* dunno if this is necessary */
 
-	inb_p(base+1);
-	inb_p(base+0);
+	inb_p(io+1);
+	inb_p(io+0);
 	timeout = jiffies+100;
 	while(timeout>jiffies) {
-		if ( 0xfa == inb_p(base+6) ) break;
+		if ( 0xfa == inb_p(io+6) ) break;
 	}
 
-	inb_p(base+3);
-	inb_p(base+2);
+	inb_p(io+3);
+	inb_p(io+2);
 	while(timeout>jiffies) {
-		if ( 0xfb == inb_p(base+6) ) break;
+		if ( 0xfb == inb_p(io+6) ) break;
 	}
 
-	/* release the other dma channel */
+	/* release the other dma channel (if we opened both of them) */
 
 	if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
 		dma&=1;
@@ -1172,31 +1081,134 @@
 		dma&=0x2;
 		free_dma(1);
 	}
- 
-	if (!dma) {  /* no dma channel */
-		printk("No DMA channel found on ltpc card.\n");
-		restore_flags(flags);
-		return -1;
-	} 
-  
+
 	/* fix up dma number */
 	dma|=1;
 
-	/* set up read */
+	return dma;
+}
+
+__initfunc(int ltpc_probe(struct device *dev))
+{
+	int err;
+	int x=0,y=0;
+	int timeout;
+	int autoirq;
+	unsigned long flags;
+	unsigned long f;
+
+	save_flags(flags);
+
+	/* probe for the I/O port address */
+	if (io != 0x240 && !check_region(0x220,8)) {
+		x = inb_p(0x220+6);
+		if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+	}
+	
+	if (io != 0x220 && !check_region(0x240,8)) {
+		y = inb_p(0x240+6);
+		if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+	} 
+
+	if(io) {
+		/* found it, now grab it */
+		request_region(io,8,"ltpc");
+	} else {
+		/* give up in despair */
+		printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+			x,y);
+		restore_flags(flags);
+		return -1;
+	}
+
+	/* probe for the IRQ line */
+	if (irq < 2) {
+		autoirq_setup(2);
+
+		/* reset the interrupt line */
+		inb_p(io+7);
+		inb_p(io+7);
+		/* trigger an interrupt (I hope) */
+		inb_p(io+6);
+
+		autoirq = autoirq_report(1);
+
+		if (autoirq == 0) {
+			printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+				io);
+		}
+		else {
+			irq = autoirq;
+		}
+	}
+
+	/* allocate a DMA buffer */
+	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+	if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+	if (!ltdmabuf) {
+		printk("ltpc: mem alloc failed\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+	}
+
+	/* reset the card */
+
+	inb_p(io+1);
+	inb_p(io+3);
+	timeout = jiffies+2;
+	while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+	inb_p(io+0);
+	inb_p(io+2);
+	inb_p(io+7); /* clear reset */
+	inb_p(io+4); 
+	inb_p(io+5);
+	inb_p(io+5); /* enable dma */
+	inb_p(io+6); /* tri-state interrupt line */
+
+	timeout = jiffies+100;
+	
+	while(timeout>jiffies) {
+		/* wait for the card to complete initialization */
+	}
+ 
+	/* now, figure out which dma channel we're using, unless it's
+	   already been specified */
+	/* well, 0 is a legal DMA channel, but the LTPC card doesn't
+	   use it... */
+	if (dma == 0) {
+		dma = ltpc_probe_dma(io);
+		if (!dma) {  /* no dma channel */
+			printk("No DMA channel found on ltpc card.\n");
+			restore_flags(flags);
+			return -1;
+		}
+	}
+
+	/* print out friendly message */
 
 	if(irq)
-		printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+		printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
 	else
-		printk("LocalTalk card found at %03x, DMA%d.  Using polled mode.\n",base,dma);
-    
-	dev->base_addr = base;
+		printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
+
+	/* seems more logical to do this *after* probing the card... */
+	err = ltpc_init(dev);
+	if (err) return err;
+
+	dev->base_addr = io;
 	dev->irq = irq;
 	dev->dma = dma;
 
-	if(debug&DEBUG_VERBOSE) {
-		printk("finishing up transfer\n");
-	}
-	
+	/* the card will want to send a result at this point */
+	/* (I think... leaving out this part makes the kernel crash,
+           so I put it back in...) */
+
 	f=claim_dma_lock();
 	disable_dma(dma);
 	clear_dma_ff(dma);
@@ -1206,41 +1218,65 @@
 	enable_dma(dma);
 	release_dma_lock(f);
 
-	(void) inb_p(base+3);
-	(void) inb_p(base+2);
+	(void) inb_p(io+3);
+	(void) inb_p(io+2);
 	timeout = jiffies+100;
 	while(timeout>jiffies) {
-		if( 0xf9 == inb_p(base+6)) break;
+		if( 0xf9 == inb_p(io+6)) break;
 	}
 
 	if(debug&DEBUG_VERBOSE) {
 		printk("setting up timer and irq\n");
 	}
 
-	init_timer(&ltpc_timer);
-	ltpc_timer.function=ltpc_poll;
-	ltpc_timer.data = (unsigned long) dev;
-
 	if (irq) {
+		/* grab it and don't let go :-) */
 		(void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
-		(void) inb_p(base+7);  /* enable interrupts from board */
-		(void) inb_p(base+7);  /* and reset irq line */
-		ltpc_timer.expires = 100;
-		  /* poll it once per second just in case */
+		(void) inb_p(io+7);  /* enable interrupts from board */
+		(void) inb_p(io+7);  /* and reset irq line */
 	} else {
-		ltpc_timer.expires = 5;
-		  /* polled mode -- 20 times per second */
-	}
-
-	ltpc_timer.expires += jiffies;  /* 1.2 to 1.3 change... */
+		/* polled mode -- 20 times per second */
+		/* this is really, really slow... should it poll more often? */
+		init_timer(&ltpc_timer);
+		ltpc_timer.function=ltpc_poll;
+		ltpc_timer.data = (unsigned long) dev;
 
-	add_timer(&ltpc_timer);
-
-	restore_flags(flags); 
+		ltpc_timer.expires = jiffies + 5;
+		add_timer(&ltpc_timer);
+		restore_flags(flags); 
+	}
 
 	return 0;
 }
 
+/* handles "ltpc=io,irq,dma" kernel command lines */
+__initfunc(void ltpc_setup(char *str, int *ints))
+{
+	if (ints[0] == 0) {
+		if (str && !strncmp(str, "auto", 4)) {
+			/* do nothing :-) */
+		}
+		else {
+			/* usage message */
+			printk (KERN_ERR
+				"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+		}
+		return;
+	} else {
+		io = ints[1];
+		if (ints[0] > 1) {
+			irq = ints[2];
+			return;
+		}
+		if (ints[0] > 2) {
+			dma = ints[3];
+			return;
+		}
+		/* ignore any other paramters */
+	}
+	return;
+}
+
 #ifdef MODULE
 
 static char dev_name[8];
@@ -1251,17 +1287,28 @@
 	 	0x0, 0,
 	 	0, 0, 0, NULL, ltpc_probe };
 
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
 int init_module(void)
 {
+	int err, result;
+	
+        if(io == 0)
+		printk(KERN_NOTICE
+		       "ltpc: Autoprobing is not recommended for modules\n");
+
 	/* Find a name for this unit */
-	int err=dev_alloc_name(&dev_ltpc,"lt%d");
+	err=dev_alloc_name(&dev_ltpc,"lt%d");
 	
 	if(err<0)
 		return err;
 
-	if (register_netdev(&dev_ltpc) != 0) {
-		if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
-		return -EIO;
+	if ((result = register_netdev(&dev_ltpc)) != 0) {
+		printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+		return result;
 	} else {
 		if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
 		return 0;
@@ -1322,3 +1369,4 @@
 	if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
 }
 #endif /* MODULE */
+
diff -u --recursive --new-file v2.1.128/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.128/linux/drivers/net/net_init.c	Tue Jun 23 10:01:23 1998
+++ linux/drivers/net/net_init.c	Mon Nov 16 10:39:27 1998
@@ -41,6 +41,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_ltalk.h>
 #include <linux/rtnetlink.h>
+#include <net/neighbour.h>
 
 /* The network devices currently exist only in the socket namespace, so these
    entries are unused.  The only ones that make sense are
@@ -219,6 +220,21 @@
 	hippi_setup(tmp_dev);
 	return tmp_dev;
 }
+
+static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+	/* Never send broadcast/multicast ARP messages */
+	p->mcast_probes = 0;
+ 
+	/* In IPv6 unicast probes are valid even on NBMA,
+	* because they are encapsulated in normal IPv6 protocol.
+	* Should be a generic flag. 
+	*/
+	if (p->tbl->family != AF_INET6)
+		p->ucast_probes = 0;
+	return 0;
+}
+
 #endif
 
 void ether_setup(struct device *dev)
@@ -304,6 +320,7 @@
 	dev->hard_header_parse		= NULL;
 	dev->hard_header_cache		= NULL;
 	dev->header_cache_update	= NULL;
+	dev->neigh_setup 		= hippi_neigh_setup_dev; 
 
 	/*
 	 * We don't support HIPPI `ARP' for the time being, and probably
@@ -317,12 +334,13 @@
 	dev->tx_queue_len	= 25 /* 5 */;
 	memset(dev->broadcast, 0xFF, HIPPI_ALEN);
 
-	/* New-style flags. */
-	dev->flags	= IFF_NODYNARP; /*
-					 * HIPPI doesn't support
-					 * broadcast+multicast and we only
-					 * use static ARP tables.
-					 */
+
+	/*
+	 * HIPPI doesn't support broadcast+multicast and we only use
+	 * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. 
+	 */
+	dev->flags = 0; 
+
 	dev_init_buffers(dev);
 }
 #endif
diff -u --recursive --new-file v2.1.128/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.1.128/linux/drivers/net/rtl8139.c	Thu Nov 12 16:21:19 1998
+++ linux/drivers/net/rtl8139.c	Sun Nov 15 09:52:26 1998
@@ -56,7 +56,6 @@
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
 
-#include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
diff -u --recursive --new-file v2.1.128/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.1.128/linux/drivers/net/sgiseeq.c	Fri May  8 23:14:48 1998
+++ linux/drivers/net/sgiseeq.c	Mon Nov 16 10:39:27 1998
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: sgiseeq.c,v 1.5 1998/05/01 01:35:40 ralf Exp $
+ * $Id: sgiseeq.c,v 1.6 1998/10/14 17:29:44 ralf Exp $
  */
 
 #include <linux/kernel.h>
@@ -88,7 +88,7 @@
 	/* Ptrs to the descriptors in KSEG1 uncached space. */
 	struct sgiseeq_rx_desc *rx_desc;
 	struct sgiseeq_tx_desc *tx_desc;
-	unsigned long _padding[14]; /* Pad out to largest cache line size. */
+	unsigned long _padding[30]; /* Pad out to largest cache line size. */
 
 	struct sgiseeq_rx_desc rxvector[SEEQ_RX_BUFFERS];
 	struct sgiseeq_tx_desc txvector[SEEQ_TX_BUFFERS];
diff -u --recursive --new-file v2.1.128/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.1.128/linux/drivers/net/shaper.c	Tue Aug 18 22:02:04 1998
+++ linux/drivers/net/shaper.c	Fri Nov 13 10:29:44 1998
@@ -157,7 +157,7 @@
  	 
  	skb->shapelatency=0;
  	skb->shapeclock=shaper->recovery;
- 	if(skb->shapeclock<jiffies)
+ 	if(time_before(skb->shapeclock, jiffies))
  		skb->shapeclock=jiffies;
  	skb->priority=0;	/* short term bug fix */
  	skb->shapestamp=jiffies;
@@ -320,7 +320,7 @@
 		 
 		if(sh_debug)
 			printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
-		if(skb->shapeclock <= jiffies + SHAPER_BURST)
+		if(skb->shapeclock - jiffies <= SHAPER_BURST)
 		{
 			/*
 			 *	Pull the frame and get interrupts back on.
@@ -385,10 +385,14 @@
 	
 	/*
 	 *	Can't open until attached.
+	 *	Also can't open until speed is set, or we'll get
+	 *	a division by zero.
 	 */
 	 
 	if(shaper->dev==NULL)
 		return -ENODEV;
+	if(shaper->bitspersec==0)
+		return -EINVAL;
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -543,6 +547,7 @@
 	shdev->type=dev->type;
 	shdev->addr_len=dev->addr_len;
 	shdev->mtu=dev->mtu;
+	sh->bitspersec=0;
 	return 0;
 }
 
@@ -564,7 +569,7 @@
 		case SHAPER_GET_DEV:
 			if(sh->dev==NULL)
 				return -ENODEV;
-			memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+			strcpy(ss->ss_name, sh->dev->name);
 			return 0;
 		case SHAPER_SET_SPEED:
 			shaper_setspeed(sh,ss->ss_speed);
diff -u --recursive --new-file v2.1.128/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.128/linux/drivers/net/sunhme.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/net/sunhme.c	Mon Nov 16 10:37:28 1998
@@ -38,6 +38,9 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
+#ifndef __sparc_v9__
+#include <asm/io-unit.h>
+#endif
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -1061,14 +1064,23 @@
 					 (RXFLAG_OWN |
 					  ((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
 					 (u32)virt_to_bus((volatile void *)skb->data));
-		} else {
+		} else
+#endif
+#ifndef __sparc_v9__
+		if (sparc_cpu_model == sun4d) {
+			__u32 va = (__u32)hp->sun4d_buffers + i * PAGE_SIZE;
+
+			hb->happy_meal_rxd[i].rx_addr =
+				iounit_map_dma_page(va, skb->data, hp->happy_sbus_dev->my_bus);
+			hb->happy_meal_rxd[i].rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+		} else
 #endif
+		{
 			hb->happy_meal_rxd[i].rx_addr = (u32)((unsigned long) skb->data);
 			hb->happy_meal_rxd[i].rx_flags =
 				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
-#ifdef CONFIG_PCI
 		}
-#endif
 		skb_reserve(skb, RX_OFFSET);
 	}
 
@@ -1078,6 +1090,7 @@
 	HMD(("done\n"));
 }
 
+#ifndef __sparc_v9__
 static void sun4c_happy_meal_init_rings(struct happy_meal *hp)
 {
 	struct hmeal_init_block *hb = hp->happy_block;
@@ -1099,6 +1112,7 @@
 		hb->happy_meal_txd[i].tx_flags = 0;
 	HMD(("done\n"));
 }
+#endif
 
 static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
 					      struct hmeal_tcvregs *tregs)
@@ -1234,9 +1248,11 @@
 
 	/* Alloc and reset the tx/rx descriptor chains. */
 	HMD(("happy_meal_init: to happy_meal_init_rings\n"));
+#ifndef __sparc_v9__	
 	if(sparc_cpu_model == sun4c)
 		sun4c_happy_meal_init_rings(hp);
 	else
+#endif	
 		happy_meal_init_rings(hp, from_irq);
 
 	/* Shut up the MIF. */
@@ -1681,7 +1697,6 @@
 				     : "=r" (flags)
 				     : "r" (&this->tx_flags), "i" (ASI_PL));
 #else
-		flush_cache_all();
 		flags = flip_dword(this->tx_flags);
 #endif
 		if(flags & TXFLAG_OWN)
@@ -1700,6 +1715,7 @@
 }
 #endif
 
+#ifndef __sparc_v9__
 static inline void sun4c_happy_meal_tx(struct happy_meal *hp)
 {
 	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1721,6 +1737,7 @@
 	hp->tx_old = elem;
 	TXD((">"));
 }
+#endif
 
 #ifdef RXDEBUG
 #define RXD(x) printk x
@@ -1855,7 +1872,6 @@
 			     : "=r" (flags)
 			     : "r" (&this->rx_flags), "i" (ASI_PL));
 #else
-	flush_cache_all();
 	flags = flip_dword(this->rx_flags); /* FIXME */
 #endif
 	while(!(flags & RXFLAG_OWN)) {
@@ -1949,7 +1965,6 @@
 				     : "=r" (flags)
 				     : "r" (&this->rx_flags), "i" (ASI_PL));
 #else
-		flush_cache_all();
 		flags = flip_dword(this->rx_flags); /* FIXME */
 #endif
 	}
@@ -1960,6 +1975,7 @@
 }
 #endif
 
+#ifndef __sparc_v9__
 static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev,
 				       struct hmeal_gregs *gregs)
 {
@@ -2023,6 +2039,115 @@
 	RXD((">"));
 }
 
+static inline void sun4d_happy_meal_rx(struct happy_meal *hp, struct device *dev,
+				       struct hmeal_gregs *gregs)
+{
+	struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];
+	struct happy_meal_rxd *this;
+	int elem = hp->rx_new, drops = 0;
+	__u32 va;
+
+	RXD(("RX<"));
+	this = &rxbase[elem];
+	while(!(this->rx_flags & RXFLAG_OWN)) {
+		struct sk_buff *skb;
+		unsigned int flags = this->rx_flags;
+		int len = flags >> 16;
+		u16 csum = flags & RXFLAG_CSUM;
+
+		RXD(("[%d ", elem));
+
+		/* Check for errors. */
+		if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
+			RXD(("ERR(%08x)]", flags));
+			hp->net_stats.rx_errors++;
+			if(len < ETH_ZLEN)
+				hp->net_stats.rx_length_errors++;
+			if(len & (RXFLAG_OVERFLOW >> 16)) {
+				hp->net_stats.rx_over_errors++;
+				hp->net_stats.rx_fifo_errors++;
+			}
+
+			/* Return it to the Happy meal. */
+	drop_it:
+			hp->net_stats.rx_dropped++;
+			va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE;
+			this->rx_addr = iounit_map_dma_page(va, hp->rx_skbs[elem]->data,
+							    hp->happy_sbus_dev->my_bus);
+			this->rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+			goto next;
+		}
+		skb = hp->rx_skbs[elem];
+		if(len > RX_COPY_THRESHOLD) {
+			struct sk_buff *new_skb;
+
+			/* Now refill the entry, if we can. */
+			new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+			if(!new_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			hp->rx_skbs[elem] = new_skb;
+			new_skb->dev = dev;
+			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
+			va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE;
+			rxbase[elem].rx_addr = iounit_map_dma_page(va, new_skb->data,
+								hp->happy_sbus_dev->my_bus);
+
+			skb_reserve(new_skb, RX_OFFSET);
+			rxbase[elem].rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+
+			/* Trim the original skb for the netif. */
+			skb_trim(skb, len);
+		} else {
+			struct sk_buff *copy_skb = dev_alloc_skb(len+2);
+
+			if(!copy_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			copy_skb->dev = dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			memcpy(copy_skb->data, skb->data, len);
+
+			/* Reuse original ring buffer. */
+			va = (__u32)hp->sun4d_buffers + elem * PAGE_SIZE;
+			rxbase[elem].rx_addr = iounit_map_dma_page(va, skb->data,
+								hp->happy_sbus_dev->my_bus);
+			rxbase[elem].rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+
+			skb = copy_skb;
+		}
+
+		/* This card is _fucking_ hot... */
+		if(!(csum ^ 0xffff))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+
+		RXD(("len=%d csum=%4x]", len, csum));
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+
+		hp->net_stats.rx_packets++;
+		hp->net_stats.rx_bytes+=len;
+	next:
+		elem = NEXT_RX(elem);
+		this = &rxbase[elem];
+	}
+	hp->rx_new = elem;
+	if(drops)
+		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+	RXD((">"));
+}
+#endif
+
 static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev            = (struct device *) dev_id;
@@ -2157,6 +2282,50 @@
 	dev->interrupt = 0;
 	HMD(("done\n"));
 }
+
+static void sun4d_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev            = (struct device *) dev_id;
+	struct happy_meal *hp         = (struct happy_meal *) dev->priv;
+	struct hmeal_gregs *gregs     = hp->gregs;
+	struct hmeal_tcvregs *tregs   = hp->tcvregs;
+	unsigned int happy_status    = hme_read32(hp, &gregs->stat);
+
+	HMD(("happy_meal_interrupt: status=%08x ", happy_status));
+
+	dev->interrupt = 1;
+
+	if(happy_status & GREG_STAT_ERRORS) {
+		HMD(("ERRORS "));
+		if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
+			dev->interrupt = 0;
+			return;
+		}
+	}
+
+	if(happy_status & GREG_STAT_MIFIRQ) {
+		HMD(("MIFIRQ "));
+		happy_meal_mif_interrupt(hp, gregs, tregs);
+	}
+
+	if(happy_status & GREG_STAT_TXALL) {
+		HMD(("TXALL "));
+		happy_meal_tx(hp);
+	}
+
+	if(happy_status & GREG_STAT_RXTOHOST) {
+		HMD(("RXTOHOST "));
+		sun4d_happy_meal_rx(hp, dev, gregs);
+	}
+
+	if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) {
+		hp->dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+
+	dev->interrupt = 0;
+	HMD(("done\n"));
+}
 #endif
 
 static int happy_meal_open(struct device *dev)
@@ -2173,6 +2342,14 @@
 			printk("happy meal: Can't order irq %d to go.\n", dev->irq);
 			return -EAGAIN;
 		}
+	} else if (sparc_cpu_model == sun4d) {
+		if(request_irq(dev->irq, &sun4d_happy_meal_interrupt,
+			       SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
+			HMD(("EAGAIN\n"));
+			printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+			       __irq_itoa(dev->irq));
+			return -EAGAIN;
+		}
 	} else
 #endif
 #ifdef CONFIG_PCI
@@ -2327,6 +2504,7 @@
 }
 #endif
 
+#ifndef __sparc_v9__
 static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
@@ -2383,6 +2561,59 @@
 	return 0;
 }
 
+static int sun4d_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	int len, entry;
+	__u32 va;
+
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+		int tickssofar = jiffies - dev->trans_start;
+	    
+		if (tickssofar >= 40) {
+			printk ("%s: transmit timed out, resetting\n", dev->name);
+			hp->net_stats.tx_errors++;
+			tx_dump_log();
+			printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+				hme_read32(hp, &hp->gregs->stat),
+				hme_read32(hp, &hp->etxregs->cfg),
+				hme_read32(hp, &hp->bigmacregs->tx_cfg));
+			happy_meal_init(hp, 0);
+			dev->tbusy = 0;
+			dev->trans_start = jiffies;
+		} else
+			tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
+		return 1;
+	}
+
+	if(!TX_BUFFS_AVAIL(hp)) {
+		tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
+		return 1;
+	}
+	len = skb->len;
+	entry = hp->tx_new;
+
+	SXD(("SX<l[%d]e[%d]>", len, entry));
+	hp->tx_skbs[entry] = skb;
+	va = (__u32)hp->sun4d_buffers + (RX_RING_SIZE + entry) * PAGE_SIZE;
+	hp->happy_block->happy_meal_txd[entry].tx_addr = 
+		iounit_map_dma_page(va, skb->data, hp->happy_sbus_dev->my_bus);
+	hp->happy_block->happy_meal_txd[entry].tx_flags =
+		(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
+	hp->tx_new = NEXT_TX(entry);
+
+	/* Get it going. */
+	dev->trans_start = jiffies;
+	hme_write32(hp, &hp->etxregs->tx_pnding, ETX_TP_DMAWAKEUP);
+
+	if(TX_BUFFS_AVAIL(hp))
+		dev->tbusy = 0;
+
+	tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
+	return 0;
+}
+#endif
+
 static struct net_device_stats *happy_meal_get_stats(struct device *dev)
 {
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
@@ -2561,11 +2792,17 @@
 		sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block",
 				  &hp->hblock_dvma);
 
+#ifndef __sparc_v9__
 	if(sparc_cpu_model == sun4c)
 		hp->sun4c_buffers = (struct hmeal_buffers *)
 		    sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs",
 				      &hp->s4c_buf_dvma);
+	else if (sparc_cpu_model == sun4d)
+		hp->sun4d_buffers = (struct hmeal_buffers *)
+		    iounit_map_dma_init(hp->happy_sbus_dev->my_bus,
+		    			(RX_RING_SIZE + TX_RING_SIZE) * PAGE_SIZE);
 	else
+#endif
 		hp->sun4c_buffers = 0;
 
 	/* Force check of the link first time we are brought up. */
@@ -2583,9 +2820,13 @@
 	hp->dev = dev;
 	dev->open = &happy_meal_open;
 	dev->stop = &happy_meal_close;
+#ifndef __sparc_v9__	
 	if(sparc_cpu_model == sun4c)
 		dev->hard_start_xmit = &sun4c_happy_meal_start_xmit;
+	else if (sparc_cpu_model == sun4d)
+		dev->hard_start_xmit = &sun4d_happy_meal_start_xmit;
 	else
+#endif
 		dev->hard_start_xmit = &happy_meal_start_xmit;
 	dev->get_stats = &happy_meal_get_stats;
 	dev->set_multicast_list = &happy_meal_set_multicast;
@@ -2684,6 +2925,11 @@
 	}
 
 	hp->hblock_dvma = (u32) virt_to_bus(hp->happy_block);
+#ifndef __sparc_v9__
+	/* This case we currently need to use 'sparc_alloc_io' */
+	hp->happy_block = sparc_alloc_io (hp->hblock_dvma, NULL, 
+					  PAGE_SIZE, "sunhme", 0, 0);
+#endif
 	hp->sun4c_buffers = 0;
 
 	hp->linkcheck = 0;
@@ -2796,6 +3042,11 @@
 		sparc_free_io(hp->erxregs, sizeof(struct hmeal_erxregs));
 		sparc_free_io(hp->bigmacregs, sizeof(struct hmeal_bigmacregs));
 		sparc_free_io(hp->tcvregs, sizeof(struct hmeal_tcvregs));
+#ifndef __sparc_v9__
+		if (sparc_cpu_model == sun4d)
+			iounit_map_dma_finish(hp->happy_sbus_dev->my_bus,
+					      (__u32)hp->sun4d_buffers, (RX_RING_SIZE + TX_RING_SIZE) * PAGE_SIZE);
+#endif		
 		unregister_netdev(hp->dev);
 		kfree(hp->dev);
 		root_happy_dev = sunshine;
diff -u --recursive --new-file v2.1.128/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.1.128/linux/drivers/net/sunhme.h	Mon Oct  5 13:13:40 1998
+++ linux/drivers/net/sunhme.h	Mon Nov 16 10:37:28 1998
@@ -525,6 +525,7 @@
 
 	/* We may use this for Ultra as well, will have to see, maybe not. */
 	struct hmeal_buffers     *sun4c_buffers;  /* CPU visible address.              */
+#define	sun4d_buffers		  sun4c_buffers	  /* No need to make this a separate.  */
 	__u32                     s4c_buf_dvma;   /* DVMA visible address.             */
 
 	unsigned int              happy_flags;    /* Driver state flags                */
@@ -664,7 +665,6 @@
 {
 	rp->rx_addr = flip_dword(addr);
 	rp->rx_flags = flip_dword(flags);
-        flush_cache_all();
 }
 	
 extern inline void pcihme_write_txd(struct happy_meal_txd *tp,
@@ -673,7 +673,6 @@
 {
 	tp->tx_addr = flip_dword(addr);
 	tp->tx_flags = flip_dword(flags);
-        flush_cache_all();
 }
 	
 #endif  /* def __sparc_v9__ */
diff -u --recursive --new-file v2.1.128/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c
--- v2.1.128/linux/drivers/net/syncppp.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/syncppp.c	Fri Nov 13 10:29:44 1998
@@ -859,6 +859,9 @@
 	if(dev->flags&IFF_UP)
 		return -EBUSY;
 		
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	
 	switch(cmd)
 	{
 		case SPPPIOCCISCO:
@@ -872,11 +875,7 @@
 		case SPPPIOCDEBUG:
 			sp->pp_flags&=~PP_DEBUG;
 			if(ifr->ifr_flags)
-			{
-				if(!capable(CAP_NET_ADMIN))
-					return -EPERM;
 				sp->pp_flags|=PP_DEBUG;
-			}
 			break;
 		default:
 			return -EINVAL;
diff -u --recursive --new-file v2.1.128/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.1.128/linux/drivers/net/yellowfin.c	Thu Nov 12 16:21:20 1998
+++ linux/drivers/net/yellowfin.c	Sun Nov 15 09:52:26 1998
@@ -63,7 +63,6 @@
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  ((2000*HZ)/1000)
 
-#include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
diff -u --recursive --new-file v2.1.128/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c
--- v2.1.128/linux/drivers/pci/pcisyms.c	Thu Nov 12 16:21:20 1998
+++ linux/drivers/pci/pcisyms.c	Sun Nov 15 09:52:26 1998
@@ -6,6 +6,7 @@
  *	Copyright 1998 Martin Mares
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in
--- v2.1.128/linux/drivers/sbus/audio/Config.in	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/Config.in	Wed Nov 18 09:06:05 1998
@@ -10,4 +10,5 @@
   dep_tristate '  AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO
   dep_tristate '  CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO
   dep_tristate '  DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO
+  dep_tristate '  Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO
 fi
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile
--- v2.1.128/linux/drivers/sbus/audio/Makefile	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/Makefile	Wed Nov 18 09:06:05 1998
@@ -16,47 +16,57 @@
 M_OBJS   :=
 
 ifeq ($(CONFIG_SPARCAUDIO),y)
-SBUS_AUDIO=y
+M=y
 else
   ifeq ($(CONFIG_SPARCAUDIO),m)
-  SBUS_AUDIO_MODULE=y
+  MM=y
   endif
 endif
 
 ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y)
-SBUS_AUDIO=y
+M=y
 OX_OBJS += amd7930.o
 else
   ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m)
-  SBUS_AUDIO_MODULE=y
+  MM=y
   MX_OBJS += amd7930.o
   endif
 endif
 
 ifeq ($(CONFIG_SPARCAUDIO_CS4231),y)
-SBUS_AUDIO=y
+M=y
 O_OBJS += cs4231.o
 else
   ifeq ($(CONFIG_SPARCAUDIO_CS4231),m)
-  SBUS_AUDIO_MODULE=y
+  MM=y
   M_OBJS += cs4231.o
   endif
 endif
 
 ifeq ($(CONFIG_SPARCAUDIO_DBRI),y)
-SBUS_AUDIO=y
-O_OBJS += dbri.o
+M=y
+OX_OBJS += dbri.o
 else
   ifeq ($(CONFIG_SPARCAUDIO_DBRI),m)
-  SBUS_AUDIO_MODULE=y
-  M_OBJS += dbri.o
+  MM=y
+  MX_OBJS += dbri.o
   endif
 endif
 
-ifdef SBUS_AUDIO
+ifeq ($(CONFIG_SPARCAUDIO_DUMMY),y)
+M=y
+O_OBJS += dmy.o
+else
+  ifeq ($(CONFIG_SPARCAUDIO_DUMMY),m)
+  MM=y
+  M_OBJS += dmy.o
+  endif
+endif
+
+ifdef M
 OX_OBJS += audio.o
 else
-  ifdef SBUS_AUDIO_MODULE
+  ifdef MM
   MX_OBJS += audio.o
   endif
 endif
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- v2.1.128/linux/drivers/sbus/audio/amd7930.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/amd7930.c	Wed Nov 18 09:06:05 1998
@@ -13,6 +13,74 @@
  *
  * Thanks to the AMD engineer who was able to get us the AMD79C30
  * databook which has all the programming information and gain tables.
+ *
+ * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
+ * SparcStation 1+.  The chip provides microphone and speaker interfaces
+ * which provide mono-channel audio at 8K samples per second via either
+ * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
+ * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
+ * which performs basic D channel LAPD processing and provides raw
+ * B channel data.  The digital audio channel, the two ISDN B channels,
+ * and two 64 Kbps channels to the microprocessor are all interconnected
+ * via a multiplexer.
+ *
+ * This driver interfaces to the Linux HiSax ISDN driver, which performs
+ * all high-level Q.921 and Q.931 ISDN functions.  The file is not
+ * itself a hardware driver; rather it uses functions exported by
+ * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
+ * allowing the chip to be simultaneously used for both audio and ISDN data.
+ * The hardware driver does _no_ buffering, but provides several callbacks
+ * which are called during interrupt service and should therefore run quickly.
+ *
+ * D channel transmission is performed by passing the hardware driver the
+ * address and size of an skb's data area, then waiting for a callback
+ * to signal successful transmission of the packet.  A task is then
+ * queued to notify the HiSax driver that another packet may be transmitted.
+ *
+ * D channel reception is quite simple, mainly because of:
+ *   1) the slow speed of the D channel - 16 kbps, and
+ *   2) the presence of an 8- or 32-byte (depending on chip version) FIFO
+ *      to buffer the D channel data on the chip
+ * Worst case scenario of back-to-back packets with the 8 byte buffer
+ * at 16 kbps yields an service time of 4 ms - long enough to preclude
+ * the need for fancy buffering.  We queue a background task that copies
+ * data out of the receive buffer into an skb, and the hardware driver
+ * simply does nothing until we're done with the receive buffer and
+ * reset it for a new packet.
+ *
+ * B channel processing is more complex, because of:
+ *   1) the faster speed - 64 kbps,
+ *   2) the lack of any on-chip buffering (it interrupts for every byte), and
+ *   3) the lack of any chip support for HDLC encapsulation
+ *
+ * The HiSax driver can put each B channel into one of three modes -
+ * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
+ * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
+ * L1_MODE_HDLC is the most common, used for almost all "pure" digital
+ * data sessions.  L1_MODE_TRANS is used for ISDN audio.
+ *
+ * HDLC B channel transmission is performed via a large buffer into
+ * which the skb is copied while performing HDLC bit-stuffing.  A CRC
+ * is computed and attached to the end of the buffer, which is then
+ * passed to the low-level routines for raw transmission.  Once
+ * transmission is complete, the hardware driver is set to enter HDLC
+ * idle by successive transmission of mark (all 1) bytes, waiting for
+ * the ISDN driver to prepare another packet for transmission and
+ * deliver it.
+ *
+ * HDLC B channel reception is performed via an X-byte ring buffer
+ * divided into N sections of X/N bytes each.  Defaults: X=256 bytes, N=4.
+ * As the hardware driver notifies us that each section is full, we
+ * hand it the next section and schedule a background task to peruse
+ * the received section, bit-by-bit, with an HDLC decoder.  As
+ * packets are detected, they are copied into a large buffer while
+ * decoding HDLC bit-stuffing.  The ending CRC is verified, and if
+ * it is correct, we alloc a new skb of the correct length (which we
+ * now know), copy the packet into it, and hand it to the upper layers.
+ * Optimization: for large packets, we hand the buffer (which also
+ * happens to be an skb) directly to the upper layer after an skb_trim,
+ * and alloc a new large buffer for future packets, thus avoiding a copy.
+ * Then we return to HDLC processing; state is saved between calls.
  */
 
 #include <linux/module.h>
@@ -22,6 +90,8 @@
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/version.h>
+#include <linux/soundcard.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
@@ -32,6 +102,12 @@
 #include <asm/audioio.h>
 #include "amd7930.h"
 
+#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff 
+#include "../../isdn/hisax/hisax.h"
+#include "../../isdn/hisax/isdnl1.h"
+#include "../../isdn/hisax/foreign.h"
+#endif
+
 #define MAX_DRIVERS 1
 
 static struct sparcaudio_driver drivers[MAX_DRIVERS];
@@ -274,12 +350,6 @@
 		map->gr = gx_coeff[level];
 	}
 
-	/* force output to speaker for now */
-	map->mmr2 |= AM_MAP_MMR2_LS;
-
-	/* input from external microphone */
-	map->mmr2 |= AM_MAP_MMR2_AINB;
-
 	amd7930_write_map(drv);
 }
 
@@ -296,9 +366,6 @@
  * driver, since D.output_callback_arg is assumed to be a certain struct ptr
  */
 
-#include "../../isdn/hisax/hisax.h"
-#include "../../isdn/hisax/isdnl1.h"
-
 #ifdef L2FRAME_DEBUG
 
 inline void debug_info(struct amd7930_info *info, char c) {
@@ -453,7 +520,7 @@
 			channel->input_count = 0;
 			if (channel->input_callback)
 				(*channel->input_callback)
-					(channel->input_callback_arg);
+					(channel->input_callback_arg, 1);
 		}
 	}
 }
@@ -498,16 +565,7 @@
 static int amd7930_open(struct inode * inode, struct file * file,
 			struct sparcaudio_driver *drv)
 {
-	struct amd7930_info *info = (struct amd7930_info *)drv->private;
-
-	/* Set the default audio parameters. */
-	info->rgain = 128;
-	info->pgain = 200;
-	info->mgain = 0;
-	amd7930_update_map(drv);
-
 	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -640,6 +698,21 @@
 	return AUDIO_DEV_AMD;
 }
 
+static int amd7930_get_formats(struct sparcaudio_driver *drv)
+{
+      return (AFMT_MU_LAW | AFMT_A_LAW);
+}
+
+static int amd7930_get_output_ports(struct sparcaudio_driver *drv)
+{
+      return (AUDIO_SPEAKER | AUDIO_HEADPHONE);
+}
+
+static int amd7930_get_input_ports(struct sparcaudio_driver *drv)
+{
+      return (AUDIO_MICROPHONE);
+}
+
 static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol)
 {
 	struct amd7930_info *info = (struct amd7930_info *)drv->private;
@@ -681,6 +754,13 @@
 	return 0;
 }
 
+static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv)
+{
+      struct amd7930_info *info = (struct amd7930_info *)drv->private;
+
+      return info->mgain;
+}
+
 /* Cheats. The amd has the minimum capabilities we support */
 static int amd7930_get_output_balance(struct sparcaudio_driver *drv)
 {
@@ -697,25 +777,68 @@
 	return AUDIO_MIN_PLAY_CHANNELS;
 }
 
+static int amd7930_set_output_channels(struct sparcaudio_driver *drv, 
+				       int value)
+{
+  return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL;
+}
+
 static int amd7930_get_input_channels(struct sparcaudio_driver *drv)
 {
 	return AUDIO_MIN_REC_CHANNELS;
 }
 
+static int 
+amd7930_set_input_channels(struct sparcaudio_driver *drv, int value)
+{
+  return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL;
+}
+
 static int amd7930_get_output_precision(struct sparcaudio_driver *drv)
 {
 	return AUDIO_MIN_PLAY_PRECISION;
 }
 
+static int 
+amd7930_set_output_precision(struct sparcaudio_driver *drv, int value)
+{
+  return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL;
+}
+
 static int amd7930_get_input_precision(struct sparcaudio_driver *drv)
 {
 	return AUDIO_MIN_REC_PRECISION;
 }
 
-/* This should eventually be made to DTRT, whatever that ends up */
+static int 
+amd7930_set_input_precision(struct sparcaudio_driver *drv, int value)
+{
+  return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL;
+}
+
 static int amd7930_get_output_port(struct sparcaudio_driver *drv)
 {
-	return AUDIO_SPEAKER; /* some of these have only HEADPHONE */
+  struct amd7930_info *info = (struct amd7930_info *)drv->private;
+  if (info->map.mmr2 & AM_MAP_MMR2_LS)
+    return AUDIO_SPEAKER; 
+  return AUDIO_HEADPHONE;
+}
+
+static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value)
+{
+  struct amd7930_info *info = (struct amd7930_info *)drv->private;
+  switch (value) {
+  case AUDIO_HEADPHONE:
+    info->map.mmr2 &= ~AM_MAP_MMR2_LS;
+    break;
+  case AUDIO_SPEAKER:
+    info->map.mmr2 |= AM_MAP_MMR2_LS;
+    break;
+  default:
+    return -EINVAL;
+  }
+  amd7930_update_map(drv);
+  return 0;
 }
 
 /* Only a microphone here, so no troubles */
@@ -724,15 +847,31 @@
 	return AUDIO_MICROPHONE;
 }
 
-/* This chip also supports AUDIO_ENCODING_ALAW, add support later */
-static int amd7930_get_output_encoding(struct sparcaudio_driver *drv)
-{
-	return AUDIO_ENCODING_ULAW;
-}
-
-static int amd7930_get_input_encoding(struct sparcaudio_driver *drv)
+static int amd7930_get_encoding(struct sparcaudio_driver *drv)
 {
-	return AUDIO_ENCODING_ULAW;
+  struct amd7930_info *info = (struct amd7930_info *)drv->private;
+  if (info->map.mmr1 & AM_MAP_MMR1_ALAW)
+    return AUDIO_ENCODING_ALAW;
+  return AUDIO_ENCODING_ULAW;
+}
+
+static int 
+amd7930_set_encoding(struct sparcaudio_driver *drv, int value)
+{
+  struct amd7930_info *info = (struct amd7930_info *)drv->private;
+
+  switch (value) {
+  case AUDIO_ENCODING_ULAW:
+    info->map.mmr1 &= ~AM_MAP_MMR1_ALAW;
+    break;
+  case AUDIO_ENCODING_ALAW:
+    info->map.mmr1 |= AM_MAP_MMR1_ALAW;
+    break;
+  default:
+    return -EINVAL;
+  }
+  amd7930_update_map(drv);
+  return 0;
 }
 
 /* This is what you get. Take it or leave it */
@@ -741,31 +880,55 @@
 	return AMD7930_RATE;
 }
 
-static int amd7930_get_input_rate(struct sparcaudio_driver *drv)
+static int 
+amd7930_set_output_rate(struct sparcaudio_driver *drv, int value)
 {
-	return AMD7930_RATE;
+  return (value == AMD7930_RATE) ? 0 : -EINVAL;
 }
 
-static int amd7930_get_output_muted(struct sparcaudio_driver *drv)
+static int amd7930_get_input_rate(struct sparcaudio_driver *drv)
 {
-      return 0;
+	return AMD7930_RATE;
 }
 
-static int amd7930_get_output_ports(struct sparcaudio_driver *drv)
+static int
+amd7930_set_input_rate(struct sparcaudio_driver *drv, int value)
 {
-      return AUDIO_SPEAKER | AUDIO_HEADPHONE;
+  return (value == AMD7930_RATE) ? 0 : -EINVAL;
 }
 
-static int amd7930_get_input_ports(struct sparcaudio_driver *drv)
+static int amd7930_get_output_muted(struct sparcaudio_driver *drv)
 {
-      return AUDIO_MICROPHONE;
+      return 0;
 }
 
-static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv)
+static void amd7930_loopback(struct sparcaudio_driver *drv, unsigned int value)
 {
-	struct amd7930_info *info = (struct amd7930_info *)drv->private;
+  struct amd7930_info *info = (struct amd7930_info *)drv->private;
+
+  if (value)
+    info->map.mmr1 |= AM_MAP_MMR1_LOOPBACK;
+  else
+    info->map.mmr1 &= ~AM_MAP_MMR1_LOOPBACK;
+  amd7930_update_map(drv);
+  return;
+}
+
+static int amd7930_ioctl(struct inode * inode, struct file * file,
+                         unsigned int cmd, unsigned long arg, 
+                         struct sparcaudio_driver *drv)
+{
+  int retval = 0;
+  
+  switch (cmd) {
+  case AUDIO_DIAG_LOOPBACK:
+    amd7930_loopback(drv, (unsigned int)arg);
+    break;
+  default:
+    retval = -EINVAL;
+  }
 
-	return info->mgain;
+  return retval;
 }
 
 
@@ -909,8 +1072,8 @@
  *
  */
 
-
-int amd7930_get_irqnum(int dev)
+#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff 
+static int amd7930_get_irqnum(int dev)
 {
 	struct amd7930_info *info;
 
@@ -923,7 +1086,7 @@
 	return info->irq;
 }
 
-int amd7930_get_liu_state(int dev)
+static int amd7930_get_liu_state(int dev)
 {
 	struct amd7930_info *info;
 
@@ -936,7 +1099,7 @@
 	return info->liu_state;
 }
 
-void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
+static void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -971,7 +1134,7 @@
 	restore_flags(flags);
 }
 
-void amd7930_liu_activate(int dev, int priority)
+static void amd7930_liu_activate(int dev, int priority)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1003,7 +1166,7 @@
 	restore_flags(flags);
 }
 
-void amd7930_liu_deactivate(int dev)
+static void amd7930_liu_deactivate(int dev)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1024,8 +1187,8 @@
 	restore_flags(flags);
 }
 
-void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
-		   void (*callback)(void *, int), void *callback_arg)
+static void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
+			  void (*callback)(void *, int), void *callback_arg)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1069,9 +1232,9 @@
 	restore_flags(flags);
 }
 
-void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
-		   void (*callback)(void *, int, unsigned int),
-		   void *callback_arg)
+static void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
+			  void (*callback)(void *, int, unsigned int),
+			  void *callback_arg)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1115,7 +1278,8 @@
 	restore_flags(flags);
 }
 
-int amd7930_bopen(int dev, int chan, u_char xmit_idle_char)
+static int amd7930_bopen(int dev, unsigned int chan, 
+                         int mode, u_char xmit_idle_char)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1124,6 +1288,10 @@
 		return -1;
 	}
 
+         if (mode == L1_MODE_HDLC) {
+                 return -1;
+         }
+ 
 	info = (struct amd7930_info *) drivers[dev].private;
 
 	save_and_cli(flags);
@@ -1167,7 +1335,7 @@
 	return 0;
 }
 
-void amd7930_bclose(int dev, int chan)
+static void amd7930_bclose(int dev, unsigned int chan)
 {
 	struct amd7930_info *info;
 	register unsigned long flags;
@@ -1202,8 +1370,9 @@
 	restore_flags(flags);
 }
 
-void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count,
-		   void (*callback)(void *), void *callback_arg)
+static void amd7930_bxmit(int dev, unsigned int chan,
+                          __u8 * buffer, unsigned long count,
+			  void (*callback)(void *, int), void *callback_arg)
 {
 	struct amd7930_info *info;
 	struct amd7930_channel *Bchan;
@@ -1228,8 +1397,10 @@
 	}
 }
 
-void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size,
-		   void (*callback)(void *), void *callback_arg)
+static void amd7930_brecv(int dev, unsigned int chan, 
+                          __u8 * buffer, unsigned long size,
+                          void (*callback)(void *, int, unsigned int),
+                          void *callback_arg)
 {
 	struct amd7930_info *info;
 	struct amd7930_channel *Bchan;
@@ -1254,17 +1425,21 @@
 	}
 }
 
-EXPORT_SYMBOL(amd7930_get_irqnum);
-EXPORT_SYMBOL(amd7930_get_liu_state);
-EXPORT_SYMBOL(amd7930_liu_init);
-EXPORT_SYMBOL(amd7930_liu_activate);
-EXPORT_SYMBOL(amd7930_liu_deactivate);
-EXPORT_SYMBOL(amd7930_dxmit);
-EXPORT_SYMBOL(amd7930_drecv);
-EXPORT_SYMBOL(amd7930_bopen);
-EXPORT_SYMBOL(amd7930_bclose);
-EXPORT_SYMBOL(amd7930_bxmit);
-EXPORT_SYMBOL(amd7930_brecv);
+struct foreign_interface amd7930_foreign_interface = {
+        amd7930_get_irqnum,
+        amd7930_get_liu_state,
+        amd7930_liu_init,
+        amd7930_liu_activate,
+        amd7930_liu_deactivate,
+        amd7930_dxmit,
+        amd7930_drecv,
+        amd7930_bopen,
+        amd7930_bclose,
+        amd7930_bxmit,
+        amd7930_brecv
+};
+EXPORT_SYMBOL(amd7930_foreign_interface);
+#endif
 
 
 /*
@@ -1274,7 +1449,7 @@
 static struct sparcaudio_operations amd7930_ops = {
 	amd7930_open,
 	amd7930_release,
-	NULL,				/* amd7930_ioctl */
+	amd7930_ioctl,
 	amd7930_start_output,
 	amd7930_stop_output,
 	amd7930_start_input,
@@ -1290,31 +1465,44 @@
 	amd7930_get_output_balance,
 	NULL,			/* amd7930_set_input_balance */
 	amd7930_get_input_balance,
-	NULL,			/* amd7930_set_output_channels */
+	amd7930_set_output_channels,
 	amd7930_get_output_channels,
-	NULL,			/* amd7930_set_input_channels */
+	amd7930_set_input_channels,
 	amd7930_get_input_channels,
-	NULL,			/* amd7930_set_output_precision */
+	amd7930_set_output_precision,
 	amd7930_get_output_precision,
-	NULL,			/* amd7930_set_input_precision */
+	amd7930_set_input_precision,
 	amd7930_get_input_precision,
-	NULL,			/* amd7930_set_output_port */
+	amd7930_set_output_port,
 	amd7930_get_output_port,
 	NULL,			/* amd7930_set_input_port */
 	amd7930_get_input_port,
-	NULL,			/* amd7930_set_output_encoding */
-	amd7930_get_output_encoding,
-	NULL,			/* amd7930_set_input_encoding */
-	amd7930_get_input_encoding,
-	NULL,			/* amd7930_set_output_rate */
+	amd7930_set_encoding,
+	amd7930_get_encoding,
+	amd7930_set_encoding,
+	amd7930_get_encoding,
+	amd7930_set_output_rate,
 	amd7930_get_output_rate,
-	NULL,			/* amd7930_set_input_rate */
+	amd7930_set_input_rate,
 	amd7930_get_input_rate,
 	amd7930_sunaudio_getdev_sunos,
 	amd7930_get_output_ports,
 	amd7930_get_input_ports,
-	NULL,			/* amd7930_set_output_muted */
+	NULL,                    /* amd7930_set_output_muted */
 	amd7930_get_output_muted,
+        NULL,                   /* amd7930_set_output_pause */
+        NULL,                   /* amd7930_get_output_pause */
+        NULL,                   /* amd7930_set_input_pause */
+        NULL,                   /* amd7930_get_input_pause */
+        NULL,                   /* amd7930_set_output_samples */
+        NULL,                   /* amd7930_get_output_samples */
+        NULL,                   /* amd7930_set_input_samples */
+        NULL,                   /* amd7930_get_input_samples */
+        NULL,                   /* amd7930_set_output_error */
+        NULL,                   /* amd7930_get_output_error */
+        NULL,                   /* amd7930_set_input_error */
+        NULL,                   /* amd7930_get_input_error */
+        amd7930_get_formats,
 };
 
 /* Attach to an amd7930 chip given its PROM node. */
@@ -1373,9 +1561,17 @@
 	memset(&info->map, 0, sizeof(info->map));
 	info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER
 			 | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG;
+        /* Start out with speaker, microphone */
+        info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
+
+	/* Set the default audio parameters. */
+	info->rgain = 128;
+	info->pgain = 200;
+	info->mgain = 0;
+	amd7930_update_map(drv);
 
 	/* Register the amd7930 with the midlevel audio driver. */
-	err = register_sparcaudio_driver(drv);
+	err = register_sparcaudio_driver(drv, 1);
 	if (err < 0) {
 		printk(KERN_ERR "amd7930: unable to register\n");
 		disable_irq(info->irq);
@@ -1399,7 +1595,7 @@
 {
 	struct amd7930_info *info = (struct amd7930_info *)drv->private;
 
-	unregister_sparcaudio_driver(drv);
+	unregister_sparcaudio_driver(drv, 1);
 	amd7930_idle(info);
 	disable_irq(info->irq);
 	free_irq(info->irq, drv);
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/amd7930.h linux/drivers/sbus/audio/amd7930.h
--- v2.1.128/linux/drivers/sbus/audio/amd7930.h	Mon Jan 12 15:15:45 1998
+++ linux/drivers/sbus/audio/amd7930.h	Wed Nov 18 09:06:05 1998
@@ -14,26 +14,7 @@
 #define _AMD7930_H_
 
 #include <linux/types.h>
-
-/* Exported ISDN functions */
-
-int amd7930_get_irqnum(int dev);
-int amd7930_get_liu_state(int dev);
-void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg);
-void amd7930_liu_activate(int dev, int priority);
-void amd7930_liu_deactivate(int dev);
-void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
-		   void (*callback)(void *, int), void *callback_arg);
-void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
-		   void (*callback)(void *, int, unsigned int),
-		   void *callback_arg);
-int amd7930_bopen(int dev, int chan, u_char xmit_idle_char);
-void amd7930_bclose(int dev, int chan);
-void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count,
-		   void (*callback)(void *), void *callback_arg);
-void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size,
-		   void (*callback)(void *), void *callback_arg);
-
+#include <linux/version.h>
 
 /* Register interface presented to the CPU by the amd7930. */
 struct amd7930
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.1.128/linux/drivers/sbus/audio/audio.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/audio.c	Wed Nov 18 09:06:05 1998
@@ -1,13 +1,17 @@
 /*
  * drivers/sbus/audio/audio.c
  *
- * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org)
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright (C) 1997,1998 Derrick J. Brashear (shadow@dementia.org)
  * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org)
  * 
  * Mixer code adapted from code contributed by and
  * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz)
+ * The mixer code cheats; Sparc hardware doesn't generally allow independent
+ * line control, and this fakes it badly.
  *
+ * SNDCTL_DSP_SETFMT based on code contributed by
+ * Ion Badulescu (ionut@moisil.cs.columbia.edu)
  *
  * This is the audio midlayer that sits between the VFS character
  * devices and the low-level audio hardware device drivers.
@@ -26,191 +30,345 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/soundcard.h>
-#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <asm/delay.h>
 #include <asm/pgtable.h>
 
 #include <asm/audioio.h>
 
+#undef __AUDIO_DEBUG
+#define __AUDIO_ERROR
+#undef __AUDIO_TRACE
+#ifdef __AUDIO_DEBUG
+#define dprintk(x) printk x
+#else
+#define dprintk(x)
+#endif
+#ifdef __AUDIO_ERROR
+#define eprintk(x) printk x
+#else
+#define eprintk(x)
+#endif
+#ifdef __AUDIO_TRACE
+#define tprintk(x) printk x
+#else
+#define tprintk(x)
+#endif
 
-/*
- *	Low-level driver interface.
- */
+static short lis_get_elist_ent( strevent_t *list, pid_t pid );
+static int lis_add_to_elist( strevent_t **list, pid_t pid, short events );
+static int lis_del_from_elist( strevent_t **list, pid_t pid, short events );
+static void lis_free_elist( strevent_t **list);
+static void kill_procs( struct strevent *elist, int sig, short e);
+
+static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES] = {NULL};
+
+/* This crap to be pulled off into a local include file */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+
+#define COPY_IN(arg, get) verify_area(VERIFY_READ, (void *)arg, sizeof(long)); memcpy_fromfs(&get, (long *)arg, sizeof(get));
+#define COPY_OUT(arg, ret) verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); memcpy_tofs((long *)arg, &ret, sizeof(ret));
+#define copy_to_user memcpy_tofs
+#define copy_from_user memcpy_fromfs
+#define signal_pending(x) (((x)->signal) & ~((x)->blocked))
+
+#else
 
-/* We only support one low-level audio driver currently. */
-static struct sparcaudio_driver *driver = NULL;
+#include <asm/uaccess.h>
+#include <linux/poll.h>
+#define COPY_IN(arg, get) get_user(get, (int *)arg)
+#define COPY_OUT(arg, ret) put_user(ret, (int *)arg)
+#define sparcaudio_release_ret sparcaudio_release
+#define sparcaudioctl_release_ret sparcaudioctl_release
+#define sparcaudio_select sparcaudio_poll
 
-int register_sparcaudio_driver(struct sparcaudio_driver *drv)
+#endif
+
+int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
 {
-	int i;
+	int i, dev;
 
-	/* If a driver is already present, don't allow the register. */
-	if (driver)
-		return -EIO;
+	/* If we've used up SPARCAUDIO_MAX_DEVICES, fail */
+	for (dev = 0; dev < SPARCAUDIO_MAX_DEVICES; dev++) {
+	  if (drivers[dev] == NULL) {
+	    break;
+	  }
+	}
+	if (drivers[dev]) {
+	  return -EIO;
+	}
 
 	/* Ensure that the driver has a proper operations structure. */
-	if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output)
+	if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output ||
+	    !drv->ops->start_input || !drv->ops->stop_input)
 		return -EINVAL;
 
-	/* Setup the circular queues of output and input buffers
-	 *
-	 * Each buffer is a single page, but output buffers might
-	 * be partially filled (by a write with count < 4096),
-	 * so each output buffer also has a paired output size.
-	 *
-	 * Input buffers, on the other hand, always fill completely,
-	 * so we don't need input counts - each contains 4096
-	 * bytes of audio data.
-	 *
-	 * TODO: Make number of input/output buffers tunable parameters
-	 */
-
-	drv->num_output_buffers = 32;
-        drv->playing_count = 0;
-	drv->output_front = 0;
-	drv->output_rear = 0;
-	drv->output_count = 0;
-	drv->output_active = 0;
-	drv->output_buffers = kmalloc(drv->num_output_buffers * sizeof(__u8 *), GFP_KERNEL);
-	drv->output_sizes = kmalloc(drv->num_output_buffers * sizeof(size_t), GFP_KERNEL);
-	if (!drv->output_buffers || !drv->output_sizes) goto kmalloc_failed1;
-
-	/* Allocate the pages for each output buffer. */
-	for (i = 0; i < drv->num_output_buffers; i++) {
-		drv->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL);
-		if (!drv->output_buffers[i]) goto kmalloc_failed2;
-	}
+        /* Setup the circular queues of output and input buffers
+         *
+         * Each buffer is a single page, but output buffers might
+         * be partially filled (by a write with count < output_buffer_size),
+         * so each output buffer also has a paired output size.
+         *
+         * Input buffers, on the other hand, always fill completely,
+         * so we don't need input counts - each contains input_buffer_size
+         * bytes of audio data.
+         *
+         * TODO: Make number of input/output buffers tunable parameters
+         */
+
+        drv->num_output_buffers = 8;
+	drv->output_buffer_size = (4096 * 2);
+	drv->playing_count = 0;
+	drv->output_offset = 0;
+	drv->output_eof = 0;
+        drv->output_front = 0;
+        drv->output_rear = 0;
+        drv->output_count = 0;
+        drv->output_active = 0;
+        drv->output_buffers = kmalloc(drv->num_output_buffers * 
+				      sizeof(__u8 *), GFP_KERNEL);
+        drv->output_sizes = kmalloc(drv->num_output_buffers * 
+				    sizeof(size_t), GFP_KERNEL);
+        drv->output_notify = kmalloc(drv->num_output_buffers * 
+				    sizeof(char), GFP_KERNEL);
+        if (!drv->output_buffers || !drv->output_sizes || !drv->output_notify)
+	  goto kmalloc_failed1;
+
+	drv->output_buffer = kmalloc((drv->output_buffer_size * 
+					       drv->num_output_buffers),
+					      GFP_KERNEL);
+	if (!drv->output_buffer) goto kmalloc_failed2;
+
+        /* Allocate the pages for each output buffer. */
+        for (i = 0; i < drv->num_output_buffers; i++) {
+	        drv->output_buffers[i] = (void *)(drv->output_buffer + 
+					  (i * drv->output_buffer_size));
+		drv->output_sizes[i] = 0;
+		drv->output_notify[i] = 0;
+        }
 
-	/* Setup the circular queue of input buffers. */
-	drv->num_input_buffers = 32;
-        drv->recording_count = 0;
-	drv->input_front = 0;
-	drv->input_rear = 0;
-	drv->input_count = 0;
-	drv->input_active = 0;
-	drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), GFP_KERNEL);
-	if (!drv->input_buffers) goto kmalloc_failed3;
-
-	/* Allocate the pages for each input buffer. */
-	for (i = 0; i < drv->num_input_buffers; i++) {
-		drv->input_buffers[i] = (void *) __get_free_page(GFP_KERNEL);
-		if (!drv->input_buffers[i]) goto kmalloc_failed4;
+        /* Setup the circular queue of input buffers. */
+        drv->num_input_buffers = 8;
+	drv->input_buffer_size = (4096 * 2);
+	drv->recording_count = 0;
+        drv->input_front = 0;
+        drv->input_rear = 0;
+        drv->input_count = 0;
+	drv->input_offset = 0;
+        drv->input_size = 0;
+        drv->input_active = 0;
+        drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *),
+				     GFP_KERNEL);
+        drv->input_sizes = kmalloc(drv->num_input_buffers * 
+				    sizeof(size_t), GFP_KERNEL);
+        if (!drv->input_buffers || !drv->input_sizes) goto kmalloc_failed3;
+
+        /* Allocate the pages for each input buffer. */
+	if (duplex == 1) {
+	  drv->input_buffer = kmalloc((drv->input_buffer_size * 
+						drv->num_input_buffers), 
+					       GFP_KERNEL);
+	  if (!drv->input_buffer) goto kmalloc_failed4;
+
+	  for (i = 0; i < drv->num_input_buffers; i++) {
+	    drv->input_buffers[i] = (void *)(drv->input_buffer + 
+					      (i * drv->input_buffer_size));
+	  }
+	} else {
+	  if (duplex == 2) {
+	    drv->input_buffer = drv->output_buffer;
+	    drv->input_buffer_size = drv->output_buffer_size;
+	    drv->num_input_buffers = drv->num_output_buffers;
+	    for (i = 0; i < drv->num_input_buffers; i++) 
+	      drv->input_buffers[i] = drv->output_buffers[i];
+	  } else {
+	    for (i = 0; i < drv->num_input_buffers; i++) 
+	      drv->input_buffers[i] = NULL;
+	  }
 	}
 
+	/* Take note of our duplexity */
+	drv->duplex = duplex;
+
 	/* Ensure that the driver is marked as not being open. */
 	drv->flags = 0;
 
 	MOD_INC_USE_COUNT;
 
-	driver = drv;
-	return 0;
+	/* Take driver slot, note which we took */
+	drv->index = dev;
+	drivers[dev] = drv;
 
+	return 0;
 
 kmalloc_failed4:
-	for (i--; i >= 0; i--)
-		free_page((unsigned long) drv->input_buffers[i]);
+	kfree(drv->input_buffer);
 
 kmalloc_failed3:
-	if (drv->input_buffers)
-		kfree(drv->input_buffers);
-	i = drv->num_output_buffers;
+        if (drv->input_sizes)
+                kfree(drv->input_sizes);
+        if (drv->input_buffers)
+                kfree(drv->input_buffers);
+        i = drv->num_output_buffers;
 
 kmalloc_failed2:
-	for (i--; i >= 0; i--)
-		free_page((unsigned long) drv->output_buffers[i]);
+	kfree(drv->output_buffer);
 
 kmalloc_failed1:
-	if (drv->output_buffers)
-		kfree(drv->output_buffers);
-	if (drv->output_sizes)
-		kfree(drv->output_sizes);
+        if (drv->output_buffers)
+                kfree(drv->output_buffers);
+        if (drv->output_sizes)
+                kfree(drv->output_sizes);
+        if (drv->output_notify)
+                kfree(drv->output_notify);
 
-	return -ENOMEM;
+        return -ENOMEM;
 }
 
-int unregister_sparcaudio_driver(struct sparcaudio_driver *drv)
+int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
 {
-	int i;
-
-	/* Make sure that the current driver is unregistering. */
-	if (driver != drv)
+	/* Figure out which driver is unregistering */
+	if (drivers[drv->index] != drv)
 		return -EIO;
 
 	/* Deallocate the queue of output buffers. */
-	for (i = 0; i < driver->num_output_buffers; i++)
-		free_page((unsigned long) driver->output_buffers[i]);
-	kfree(driver->output_buffers);
-	kfree(driver->output_sizes);
-
-        /* Deallocate the queue of input buffers. */
-        for (i = 0; i < driver->num_input_buffers; i++)
-                free_page((unsigned long) driver->input_buffers[i]);
-        kfree(driver->input_buffers);
+	kfree(drv->output_buffer);
+	kfree(drv->output_buffers);
+	kfree(drv->output_sizes);
+	kfree(drv->output_notify);
+
+	/* Deallocate the queue of input buffers. */
+	if (duplex == 1) {
+	  kfree(drv->input_buffer);
+	  kfree(drv->input_sizes);
+	}
+	kfree(drv->input_buffers);
+
+	if (&(drv->sd_siglist) != NULL)
+	  lis_free_elist( &(drv->sd_siglist) );
 
 	MOD_DEC_USE_COUNT;
 
-	driver = NULL;
+	/* Null the appropriate driver */
+	drivers[drv->index] = NULL;
+
 	return 0;
 }
 
-void sparcaudio_output_done(struct sparcaudio_driver * drv, int reclaim)
+void sparcaudio_output_done(struct sparcaudio_driver * drv, int status)
 {
-    /* Reclaim a buffer unless it's still in the DMA pipe */
-    if (reclaim) {
-        if (drv->output_count > 0) 
-            drv->output_count--;
-        else 
-            if (drv->playing_count > 0) 
-                drv->playing_count--;
-    } else 
-        drv->playing_count++;
-
-	/* Point the queue after the "done" buffer. */
-	drv->output_size -= drv->output_sizes[drv->output_front];
-	drv->output_front = (drv->output_front + 1) % drv->num_output_buffers;
-
-	/* If the output queue is empty, shutdown the driver. */
-	if (drv->output_count == 0) {
-            if (drv->playing_count == 0) {
-		/* Stop the lowlevel driver from outputing. */
-		drv->ops->stop_output(drv);
-		drv->output_active = 0;
-
-		/* Wake up any waiting writers or syncers and return. */
-		wake_up_interruptible(&drv->output_write_wait);
-		wake_up_interruptible(&drv->output_drain_wait);
-		return;
-            }
-	}
-
-    /* If we got back a buffer, see if anyone wants to write to it */
-    if (reclaim || ((drv->output_count + drv->playing_count) 
-                    < drv->num_output_buffers))
-        wake_up_interruptible(&drv->output_write_wait);
+  /* 
+   * If !status, just restart current output.
+   * If status & 1, a buffer is finished; make it available again.
+   * If status & 2, a buffer was claimed for DMA and is still in use.
+   *
+   * The playing_count for non-DMA hardware should never be non-zero.
+   */
+  if (status & 1) {
+    if (drv->playing_count) 
+      drv->playing_count--;
+    else {
+      drv->output_count--;
+      drv->output_size -= drv->output_sizes[drv->output_front];
+      if (drv->output_notify[drv->output_front] == 1) {
+	drv->output_eof++;
+	drv->output_notify[drv->output_front] = 0;
+	kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+      }
+      drv->output_front = (drv->output_front + 1) % 
+	drv->num_output_buffers;
+    }
+  }
     
-    drv->ops->start_output(drv, drv->output_buffers[drv->output_front],
-                           drv->output_sizes[drv->output_front]);
+  if (status & 2) {
+    drv->output_count--;
+    drv->playing_count++;
+    drv->output_size -= drv->output_sizes[drv->output_front];
+    if (drv->output_notify[drv->output_front] == 1) {
+      drv->output_eof++;
+      drv->output_notify[drv->output_front] = 0;
+      kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+    }
+    drv->output_front = (drv->output_front + 1) % 
+      drv->num_output_buffers;
+  }
+
+  /* If we've played everything go inactive. */
+  if ((drv->output_count < 1) && (drv->playing_count < 1)) 
+    drv->output_active = 0;
+
+  /* If we got back a buffer, see if anyone wants to write to it */
+  if ((status & 1) || ((drv->output_count + drv->playing_count) 
+		  < drv->num_output_buffers)) 
+    wake_up_interruptible(&drv->output_write_wait);
+
+  /* If the output queue is empty, shut down the driver. */
+  if ((drv->output_count < 1) && (drv->playing_count < 1)) {
+    kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+
+    /* Stop the lowlevel driver from outputing. */
+    /* drv->ops->stop_output(drv); Should not be necessary  -- DJB 5/25/98 */
+    drv->output_active = 0;
+		  
+    /* Wake up any waiting writers or syncers and return. */
+    wake_up_interruptible(&drv->output_write_wait);
+    wake_up_interruptible(&drv->output_drain_wait);
+    return;
+  }
 
+  /* Start next block of output if we have it */
+  if (drv->output_count > 0) {
+    drv->ops->start_output(drv, drv->output_buffers[drv->output_front],
+			   drv->output_sizes[drv->output_front]);
+    drv->output_active = 1;
+  } else 
+    drv->output_active = 0;
 }
 
-void sparcaudio_input_done(struct sparcaudio_driver * drv)
+void sparcaudio_input_done(struct sparcaudio_driver * drv, int status)
 {
-	/* Point the queue after the "done" buffer. */
-	drv->input_front = (drv->input_front + 1) % drv->num_input_buffers;
-	drv->input_count++;
-
-	/* If the input queue is full, shutdown the driver. */
-	if (drv->input_count == drv->num_input_buffers) {
-		/* Stop the lowlevel driver from inputing. */
-		drv->ops->stop_input(drv);
-		drv->input_active = 0;
-	} else {
-		/* Otherwise, give the driver the next buffer. */
-		drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
-				      4096);
-	}
+  /* Deal with the weird case here */
+  if (drv->duplex == 2) {
+    if (drv->input_count < drv->num_input_buffers)
+      drv->input_count++;
+    drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
+			  drv->input_buffer_size);
+    wake_up_interruptible(&drv->input_read_wait);
+    return;
+  } 
+
+  /* 
+   * If status % 2, they filled a buffer for us. 
+   * If status & 2, they took a buffer from us.
+   */
+
+  if ((status % 2) == 1) {
+    drv->input_count++;
+    drv->recording_count--;
+    drv->input_size+=drv->input_buffer_size;
+  }
+
+  if (status > 1) {
+    drv->recording_count++;
+    drv->input_front = (drv->input_front + 1) % drv->num_input_buffers;
+  }
+
+  dprintk(("f%d r%d c%d u%d\n", drv->input_front, drv->input_rear, drv->input_count, drv->recording_count));
+  /* If the input queue is full, shutdown the driver. */
+  if ((drv->input_count + drv->recording_count) == drv->num_input_buffers) {
+    kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+
+    /* Stop the lowlevel driver from inputing. */
+    drv->ops->stop_input(drv);
+    drv->input_active = 0;
+  } else {
+    /* Otherwise, give the driver the next buffer. */
+    drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
+			  drv->input_buffer_size);
+  }
 
-	/* Wake up any tasks that are waiting. */
-	wake_up_interruptible(&drv->input_read_wait);
+  /* Wake up any tasks that are waiting. */
+  wake_up_interruptible(&drv->input_read_wait);
 }
 
 
@@ -219,803 +377,1680 @@
  *	VFS layer interface
  */
 
-static loff_t sparcaudio_llseek(struct file * file, loff_t offset, int origin)
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static int sparcaudio_select(struct inode * inode, struct file * file,
+			    int sel_type, select_table * wait)
 {
-	return -ESPIPE;
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+					   SPARCAUDIO_DEVICE_SHIFT)];
+  
+  switch (sel_type) {
+  case SEL_IN:
+    if (((!file->f_flags & O_NONBLOCK) && drv->input_count) ||
+	(drv->input_size > drv->buffer_size)) {
+      dprintk(("read ready: c%d o%d\n", drv->input_count, drv->input_offset));
+      return 1;
+    }
+    select_wait(&drv->input_read_wait, wait);
+    break;
+  case SEL_OUT:
+    dprintk(("sel out: c%d o%d p%d\n", drv->output_count, drv->output_offset, drv->playing_count));
+    if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) {
+      return 1;
+    }
+    select_wait(&drv->output_write_wait, wait);
+    break;
+  case SEL_EX:
+    break;
+  }
+
+  return 0;
+}
+#else
+static unsigned int sparcaudio_poll(struct file *file, poll_table * wait)
+{
+  unsigned int mask = 0;
+  struct inode *inode = file->f_dentry->d_inode;
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+                                           SPARCAUDIO_DEVICE_SHIFT)];
+
+  poll_wait(file, &drv->input_read_wait, wait);
+  poll_wait(file, &drv->output_write_wait, wait);
+  if (((!file->f_flags & O_NONBLOCK) && drv->input_count) ||
+      (drv->input_size > drv->buffer_size)) {
+    mask |= POLLIN | POLLRDNORM;
+  }
+  if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) {
+    mask |= POLLOUT | POLLWRNORM;
+  }
+  return mask;
 }
+#endif
 
-static ssize_t sparcaudio_read(struct file * file,
-			       char *buf, size_t count, loff_t *ppos)
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static int sparcaudio_lseek(struct inode * inode, struct file * file,
+			    off_t offset, int origin)
+#else
+static loff_t sparcaudio_lseek(struct file * file, loff_t offset, int origin)
+#endif
 {
-	int bytes_to_copy;
+	return -ESPIPE;
+}
 
-	if (! file->f_mode & FMODE_READ)
-		return -EINVAL;
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static int sparcaudio_read(struct inode * inode, struct file * file,
+			   char *buf, int count)
+#else
+static ssize_t sparcaudio_read(struct file * file, char *buf, 
+                               size_t count, loff_t *ppos)
+#endif
+{
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+  struct inode *inode = file->f_dentry->d_inode;
+#endif
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+					   SPARCAUDIO_DEVICE_SHIFT)];
+  int bytes_to_copy, bytes_read = 0, err;
 
-	if (driver->input_count == 0) {
-		interruptible_sleep_on(&driver->input_read_wait);
-		if (signal_pending(current))
-			return -EINTR;
-	}
+  if (! file->f_mode & FMODE_READ)
+    return -EINVAL;
 
-	bytes_to_copy = 4096 - driver->input_offset;
-	if (bytes_to_copy > count)
-		bytes_to_copy = count;
-
-	copy_to_user_ret(buf, driver->input_buffers[driver->input_rear]+driver->input_offset,
-			 bytes_to_copy, -EFAULT);
-	driver->input_offset += bytes_to_copy;
-
-	if (driver->input_offset >= 4096) {
-		driver->input_rear = (driver->input_rear + 1) % driver->num_input_buffers;
-		driver->input_count--;
-		driver->input_offset = 0;
-	}
+  if ((file->f_flags & O_NONBLOCK) && (drv->input_size < count))
+    return -EAGAIN;
+    
+  while (count > 0) {
+    if (drv->input_count == 0) {
+      /* This *should* never happen. */
+      if (file->f_flags & O_NONBLOCK) {
+	printk("Warning: audio input leak!\n");
+	return -EAGAIN;
+      }
+      interruptible_sleep_on(&drv->input_read_wait);
+      if (signal_pending(current))
+	return -EINTR;
+    }
+  
+    bytes_to_copy = drv->input_buffer_size - drv->input_offset;
+    
+    if (bytes_to_copy > count)
+      bytes_to_copy = count;
 
-	return bytes_to_copy;
-}
+    err = verify_area(VERIFY_WRITE, buf, bytes_to_copy);
+    if (err)
+      return err;
+
+    copy_to_user(buf, drv->input_buffers[drv->input_rear]+drv->input_offset, 
+                 bytes_to_copy);
+
+    drv->input_offset += bytes_to_copy;
+    drv->input_size -= bytes_to_copy;
+    buf += bytes_to_copy;
+    count -= bytes_to_copy;
+    bytes_read += bytes_to_copy;
+
+    if (drv->input_offset >= drv->input_buffer_size) {
+      drv->input_rear = (drv->input_rear + 1) % 
+	drv->num_input_buffers;
+      drv->input_count--;
+      drv->input_offset = 0;
+    }
+    /* If we're in "loop audio" mode, try waking up the other side
+     * in case they're waiting for us to eat a block. 
+     */
+    if (drv->duplex == 2) {
+      wake_up_interruptible(&drv->output_write_wait);
+    }
+  }
 
-static void sparcaudio_reorganize_buffers(struct sparcaudio_driver * driver)
-{
-  /* It may never matter but if it does this routine will pack */
-  /* buffers to free space for more data */
+  return bytes_read;
 }
 
-static void sparcaudio_sync_output(struct sparcaudio_driver * driver)
+static void sparcaudio_sync_output(struct sparcaudio_driver * drv)
 {
-	unsigned long flags;
+  unsigned long flags;
 
-	/* If the low-level driver is not active, activate it. */
-	save_and_cli(flags);
-        if ((!driver->output_active) && (driver->output_count > 0)) {
-            driver->ops->start_output(driver,
-                                      driver->output_buffers[driver->output_front],
-                                      driver->output_sizes[driver->output_front]);
-            driver->output_active = 1;
-	}
-	restore_flags(flags);
+  /* If the low-level driver is not active, activate it. */
+  save_and_cli(flags);
+  if ((!drv->output_active) && (drv->output_count > 0)) {
+    drv->ops->start_output(drv, 
+			   drv->output_buffers[drv->output_front],
+			   drv->output_sizes[drv->output_front]);
+    drv->output_active = 1;
+  }
+  restore_flags(flags);
 }
 
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static int sparcaudio_write(struct inode * inode, struct file * file,
+			    const char *buf, int count)
+#else
 static ssize_t sparcaudio_write(struct file * file, const char *buf,
-				size_t count, loff_t *ppos)
+                                size_t count, loff_t *ppos)
+#endif
 {
-	int bytes_written = 0, bytes_to_copy;
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+  struct inode *inode = file->f_dentry->d_inode;
+#endif
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+					   SPARCAUDIO_DEVICE_SHIFT)];
+  int bytes_written = 0, bytes_to_copy, err;
+  
+  if (! file->f_mode & FMODE_WRITE)
+    return -EINVAL;
+
+  /* 
+   * A signal they want notification when this is processed. Too bad
+   * sys_write doesn't tell us unless you patch it, in 2.0 kernels.
+   */
+  if (count == 0) {
+#ifndef notdef
+    drv->output_eof++;
+    kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+#else
+    /* Nice code, but the world isn't ready yet... */
+    drv->output_notify[drv->output_rear] = 1;
+#endif
+  }
 
-        if (! file->f_mode & FMODE_WRITE)
-            return -EINVAL;
+  /* Loop until all output is written to device. */
+  while (count > 0) {
+    /* Check to make sure that an output buffer is available. */
+    if (drv->num_output_buffers == (drv->output_count + drv->playing_count)) {
+      /* We need buffers, so... */
+      sparcaudio_sync_output(drv);
+      if (file->f_flags & O_NONBLOCK) {
+	return -EAGAIN;
+      }
+      interruptible_sleep_on(&drv->output_write_wait);
+      if (signal_pending(current))
+	return bytes_written > 0 ? bytes_written : -EINTR;
+    }
 
-	/* Loop until all output is written to device. */
-	while (count > 0) {
-            /* Check to make sure that an output buffer is available. */
-            /* If not, make valiant attempt */
-            if (driver->num_output_buffers == 
-                (driver->output_count + driver->playing_count))
-                sparcaudio_reorganize_buffers(driver);
-            
-            if (driver->num_output_buffers == 
-                (driver->output_count + driver->playing_count)) {
-                /* We need buffers, so... */
-                sparcaudio_sync_output(driver);
-                interruptible_sleep_on(&driver->output_write_wait);
-                if (signal_pending(current))
-                    return bytes_written > 0 ? bytes_written : -EINTR;
-		}
+    /* No buffers were freed. Go back to sleep */
+    if (drv->num_output_buffers == (drv->output_count + drv->playing_count)) 
+      continue;
+
+    /* Deal with the weird case of a reader in the write area by trying to
+     * let them keep ahead of us... Go to sleep until they start servicing.
+     */
+    if ((drv->duplex == 2) && (drv->flags & SDF_OPEN_READ) &&
+	(drv->output_rear == drv->input_rear) && (drv->input_count > 0)) {
+      if (file->f_flags & O_NONBLOCK) {
+	return -EAGAIN;
+      }
+      interruptible_sleep_on(&drv->output_write_wait);
+      if (signal_pending(current))
+	return bytes_written > 0 ? bytes_written : -EINTR;
+    }
 
-            /* No buffers were freed. Go back to sleep */
-            if (driver->num_output_buffers == 
-                (driver->output_count + driver->playing_count)) 
-                continue;
-
-            /* Determine how much we can copy in this iteration. */
-            bytes_to_copy = count;
-            if (bytes_to_copy > 4096)
-                bytes_to_copy = 4096;
-
-            copy_from_user_ret(driver->output_buffers[driver->output_rear],
-			       buf, bytes_to_copy, -EFAULT);
-
-            /* Update the queue pointers. */
-            buf += bytes_to_copy;
-            count -= bytes_to_copy;
-            bytes_written += bytes_to_copy;
-            driver->output_sizes[driver->output_rear] = bytes_to_copy;
-            driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers;
-            driver->output_count++;
-            driver->output_size += bytes_to_copy;
-	}
-        sparcaudio_sync_output(driver);
+    /* Determine how much we can copy in this iteration. */
+    bytes_to_copy = count;
+    if (bytes_to_copy > drv->output_buffer_size - drv->output_offset)
+      bytes_to_copy = drv->output_buffer_size - drv->output_offset;
+    
+    err = verify_area(VERIFY_READ, buf, bytes_to_copy);
+    if (err)
+      return err;
 
-	/* Return the number of bytes written to the caller. */
-	return bytes_written;
+    copy_from_user(drv->output_buffers[drv->output_rear]+drv->output_offset, buf, bytes_to_copy);
+    
+    /* Update the queue pointers. */
+    buf += bytes_to_copy;
+    count -= bytes_to_copy;
+    bytes_written += bytes_to_copy;
+
+    /* A block can get orphaned in a flush and not cleaned up. */
+    if (drv->output_offset)
+      drv->output_sizes[drv->output_rear] += bytes_to_copy;
+    else
+      drv->output_sizes[drv->output_rear] = bytes_to_copy;
+
+    drv->output_notify[drv->output_rear] = 0;
+
+    if (drv->output_sizes[drv->output_rear] == drv->output_buffer_size) {
+      drv->output_rear = (drv->output_rear + 1) 
+	% drv->num_output_buffers;
+      drv->output_count++;
+      drv->output_offset = 0;
+    } else
+      drv->output_offset += bytes_to_copy;
+
+    drv->output_size+=bytes_to_copy;
+  }
+
+  sparcaudio_sync_output(drv);
+  
+  /* Return the number of bytes written to the caller. */
+  return bytes_written;
 }
 
-#define COPY_IN(arg, get) get_user(get, (int *)arg)
-#define COPY_OUT(arg, ret) put_user(ret, (int *)arg)
-
 /* Add these in as new devices are supported. Belongs in audioio.h, actually */
-#define SUPPORTED_MIXER_DEVICES         (SOUND_MASK_VOLUME)
-#define MONO_DEVICES (SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER | SOUND_MASK_MIC)
+#define MONO_DEVICES (SOUND_MASK_SPEAKER | SOUND_MASK_MIC)
 
-static inline int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
-					 unsigned int cmd, unsigned long arg)
+static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
+			    unsigned int cmd, unsigned long arg)
 {
-	int i = 0, j = 0;
-	if (_IOC_DIR(cmd) & _IOC_WRITE) {
-		/* For any missing routines, pretend we changed things anyhow for now */
-		switch (cmd & 0xff) {
-		case SOUND_MIXER_VOLUME:
-			if (driver->ops->get_output_channels)
-				j = driver->ops->get_output_channels(driver);
-			COPY_IN(arg, i);
-			if (j == 1) {
-				i = s_to_m(i);
-				if (driver->ops->set_output_volume)
-					driver->ops->set_output_volume(driver, i * 255/100);
-				if (driver->ops->get_output_volume)
-					i = driver->ops->get_output_volume(driver);
-				i = m_to_s(i);
-			} else {
-				/* there should be stuff here which calculates balance and
-				   volume on a stereo device. will do it eventually */
-				i = s_to_g(i);
-				if (driver->ops->set_output_volume)
-					driver->ops->set_output_volume(driver, i * 255/100);
-				if (driver->ops->get_output_volume)
-					i = driver->ops->get_output_volume(driver);
-				j = s_to_b(i);
-				if (driver->ops->set_output_balance)
-					driver->ops->set_output_balance(driver, j);
-				if (driver->ops->get_output_balance)
-					j = driver->ops->get_output_balance(driver);
-				i = b_to_s(i,j);
-			}
-			return COPY_OUT(arg, i);
-		default:
-			/* Play like we support other things */
-			return COPY_OUT(arg, i);
-		}
-	} else {
-		switch (cmd & 0xff) {
-		case SOUND_MIXER_RECSRC:
-			if (driver->ops->get_input_port)
-				i = driver->ops->get_input_port(driver);
-			/* only one should ever be selected */
-			if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */
-			if (i & AUDIO_CD) j = SOUND_MASK_CD;
-			if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE;
-			if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC;
-
-			return COPY_OUT(arg, j);
-
-		case SOUND_MIXER_RECMASK:
-			if (driver->ops->get_input_ports)
-				i = driver->ops->get_input_ports(driver);
-			/* what do we support? */
-			if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
-			if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
-			if (i & AUDIO_CD) j |= SOUND_MASK_CD;
-			if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
-
-			return COPY_OUT(arg, j);
-
-		case SOUND_MIXER_CAPS: /* mixer capabilities */
-			i = SOUND_CAP_EXCL_INPUT;
-			return COPY_OUT(arg, i);
-
-		case SOUND_MIXER_DEVMASK: /* all supported devices */
-		case SOUND_MIXER_STEREODEVS: /* what supports stereo */
-			if (driver->ops->get_input_ports)
-				i = driver->ops->get_input_ports(driver);
-			/* what do we support? */
-			if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
-			if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
-			if (i & AUDIO_CD) j |= SOUND_MASK_CD;
-			if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
-
-			if (driver->ops->get_output_ports)
-				i = driver->ops->get_output_ports(driver);
-			if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER;
-			if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */
-			if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE;
-			
-			j |= SOUND_MASK_VOLUME;
-
-			if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS)
-			j &= ~(MONO_DEVICES);
-			return COPY_OUT(arg, j);
-
-		case SOUND_MIXER_VOLUME:
-			if (driver->ops->get_output_channels)
-				j = driver->ops->get_output_channels(driver);
-			if (j == 1) {
-				if (driver->ops->get_output_volume)
-					i = driver->ops->get_output_volume(driver);
-				i = m_to_s(i);
-			} else {
-				/* there should be stuff here which calculates balance and
-				   volume on a stereo device. will do it eventually */
-				if (driver->ops->get_output_volume)
-					i = driver->ops->get_output_volume(driver);
-				if (driver->ops->get_output_balance)
-					j = driver->ops->get_output_balance(driver);
-				i = b_to_s(i,j);
-			}
-			return COPY_OUT(arg, i);
-
-		default:
-			/* Play like we support other things */
-			return COPY_OUT(arg, i);
-		}
-	}
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+					   SPARCAUDIO_DEVICE_SHIFT)];
+  unsigned long i = 0, j = 0, k = 0;
+
+  k = (unsigned long) &arg;
+
+  switch (cmd) {
+  case SOUND_MIXER_WRITE_RECLEV:
+  case SOUND_MIXER_WRITE_MIC:
+  case SOUND_MIXER_WRITE_CD:
+  case SOUND_MIXER_WRITE_LINE:
+    tprintk(("setting input volume (0x%x)", k));
+    if (drv->ops->get_input_channels)
+      j = drv->ops->get_input_channels(drv);
+    if (j == 1) {
+      i = s_to_m(k);
+      tprintk((" for mono to %d\n", i));
+      if (drv->ops->set_input_volume)
+	drv->ops->set_input_volume(drv, i);
+      if (drv->ops->get_input_volume)
+	i = drv->ops->get_input_volume(drv);
+      i = m_to_s(i);
+    } else {
+      i = s_to_g(k);
+      j = s_to_b(k);
+      tprintk((" for stereo to to %d (bal %d)\n", i, j));
+      if (drv->ops->set_input_volume)
+	drv->ops->set_input_volume(drv, i);
+      if (drv->ops->get_input_volume)
+	i = drv->ops->get_input_volume(drv);
+      if (drv->ops->set_input_balance)
+	drv->ops->set_input_balance(drv, j);
+      if (drv->ops->get_input_balance)
+	j = drv->ops->get_input_balance(drv);
+      i = b_to_s(i,j);
+    }
+    return COPY_OUT(arg, i);
+  case SOUND_MIXER_WRITE_PCM:
+  case SOUND_MIXER_WRITE_VOLUME:
+  case SOUND_MIXER_WRITE_SPEAKER:
+    tprintk(("setting output volume (0x%x)", k));
+    if (drv->ops->get_output_channels)
+      j = drv->ops->get_output_channels(drv);
+    if (j == 1) {
+      i = s_to_m(k);
+      tprintk((" for mono to %d\n", i));
+      if (drv->ops->set_output_volume)
+	drv->ops->set_output_volume(drv, i);
+      if (drv->ops->get_output_volume)
+	i = drv->ops->get_output_volume(drv);
+      i = m_to_s(i);
+    } else {
+      i = s_to_g(k);
+      j = s_to_b(k);
+      tprintk((" for stereo to to %d (bal %d)\n", i, j));
+      if (drv->ops->set_output_volume)
+	drv->ops->set_output_volume(drv, i);
+      if (drv->ops->get_output_volume)
+	i = drv->ops->get_output_volume(drv);
+      if (drv->ops->set_output_balance)
+	drv->ops->set_output_balance(drv, j);
+      if (drv->ops->get_output_balance)
+	j = drv->ops->get_output_balance(drv);
+      i = b_to_s(i,j);
+    }
+    return COPY_OUT(arg, i);
+  case SOUND_MIXER_READ_RECSRC: 
+    if (drv->ops->get_input_port)
+      i = drv->ops->get_input_port(drv);
+    /* only one should ever be selected */
+    if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */
+    if (i & AUDIO_CD) j = SOUND_MASK_CD;
+    if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE;
+    if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC;
+    
+    return COPY_OUT(arg, j);
+  case SOUND_MIXER_WRITE_RECSRC: 
+    if (!drv->ops->set_input_port)
+      return -EINVAL;
+    if (arg & SOUND_MASK_IMIX) j |= AUDIO_ANALOG_LOOPBACK;
+    if (arg & SOUND_MASK_CD) j |= AUDIO_CD;
+    if (arg & SOUND_MASK_LINE) j |= AUDIO_LINE_IN;
+    if (arg & SOUND_MASK_MIC) j |= AUDIO_MICROPHONE;
+    tprintk(("setting inport to %d\n", j));
+    i = drv->ops->set_input_port(drv, j);
+    
+    return COPY_OUT(arg, i);
+  case SOUND_MIXER_READ_RECMASK: 
+    if (drv->ops->get_input_ports)
+      i = drv->ops->get_input_ports(drv);
+    /* what do we support? */
+    if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
+    if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
+    if (i & AUDIO_CD) j |= SOUND_MASK_CD;
+    if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
+    
+    return COPY_OUT(arg, j);
+  case SOUND_MIXER_READ_CAPS: /* mixer capabilities */
+    i = SOUND_CAP_EXCL_INPUT;
+    return COPY_OUT(arg, i);
+
+  case SOUND_MIXER_READ_DEVMASK: /* all supported devices */
+  case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */
+    if (drv->ops->get_input_ports)
+      i = drv->ops->get_input_ports(drv);
+    /* what do we support? */
+    if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
+    if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
+    if (i & AUDIO_CD) j |= SOUND_MASK_CD;
+    if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */
+    
+    if (drv->ops->get_output_ports)
+      i = drv->ops->get_output_ports(drv);
+    if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER;
+    if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */
+    if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE;
+    
+    j |= SOUND_MASK_VOLUME;
+    
+    if (cmd == SOUND_MIXER_READ_STEREODEVS)
+      j &= ~(MONO_DEVICES);
+    return COPY_OUT(arg, j);
+  case SOUND_MIXER_READ_PCM:
+  case SOUND_MIXER_READ_SPEAKER:
+  case SOUND_MIXER_READ_VOLUME:
+    if (drv->ops->get_output_channels)
+      j = drv->ops->get_output_channels(drv);
+    if (j == 1) {
+      if (drv->ops->get_output_volume)
+	i = drv->ops->get_output_volume(drv);
+      i = m_to_s(i);
+    } else {
+      if (drv->ops->get_output_volume)
+	i = drv->ops->get_output_volume(drv);
+      if (drv->ops->get_output_balance)
+	j = drv->ops->get_output_balance(drv);
+      i = b_to_s(i,j);
+    }
+    return COPY_OUT((int *)arg, i);
+  case SOUND_MIXER_READ_RECLEV:
+  case SOUND_MIXER_READ_MIC:
+  case SOUND_MIXER_READ_CD:
+  case SOUND_MIXER_READ_LINE:
+    if (drv->ops->get_input_channels)
+      j = drv->ops->get_input_channels(drv);
+    if (j == 1) {
+      if (drv->ops->get_input_volume)
+	i = drv->ops->get_input_volume(drv);
+      i = m_to_s(i);
+    } else {
+      if (drv->ops->get_input_volume)
+	i = drv->ops->get_input_volume(drv);
+      if (drv->ops->get_input_balance)
+	j = drv->ops->get_input_balance(drv);
+      i = b_to_s(i,j);
+    }
+    return COPY_OUT((int *)arg, i);
+  default:
+    return -EINVAL;
+  }
 }
 
-static int sparcaudio_ioctl(struct inode * inode, struct file * file,
-			    unsigned int cmd, unsigned long arg)
+/* AUDIO_SETINFO uses these to set values if possible. */
+static __inline__ int 
+__sparcaudio_if_set_do(struct sparcaudio_driver *drv, 
+		       int (*set_function)(struct sparcaudio_driver *, int), 
+		       int (*get_function)(struct sparcaudio_driver *), 
+		       unsigned int value)
 {
-	int retval = 0;
-	struct audio_info ainfo;
-
-        if (((cmd >> 8) & 0xff) == 'M') {
-            return sparcaudio_mixer_ioctl(inode, file, cmd, arg);
-        }
-
-	switch (cmd) {
-	case SNDCTL_DSP_SYNC:
-	case AUDIO_DRAIN:
-		if (driver->output_count > 0) {
-			interruptible_sleep_on(&driver->output_drain_wait);
-			retval = signal_pending(current) ? -EINTR : 0;
-		}
-		break;
-
-        case AUDIO_FLUSH:
-                if (driver->output_active && (file->f_mode & FMODE_WRITE)) {
-                    wake_up_interruptible(&driver->output_write_wait);
-                    driver->ops->stop_output(driver);
-                    driver->output_active = 0;
-                    driver->output_front = 0;
-                    driver->output_rear = 0;
-                    driver->output_count = 0;
-                    driver->output_size = 0;
-                    driver->playing_count = 0;
-                }
-                if (driver->input_active && (file->f_mode & FMODE_READ)) {
-                    wake_up_interruptible(&driver->input_read_wait);
-                    driver->ops->stop_input(driver);
-                    driver->input_active = 0;
-                    driver->input_front = 0;
-                    driver->input_rear = 0;
-                    driver->input_count = 0;
-                    driver->recording_count = 0;
-                }
-                if ((file->f_mode & FMODE_READ) && 
-                    !(driver->flags & SDF_OPEN_READ)) {
-                    driver->ops->start_input(driver, 
-                                             driver->input_buffers[driver->input_front],
-                                             4096);
-                    driver->input_active = 1;
-                    }
-                if ((file->f_mode & FMODE_WRITE) && 
-                    !(driver->flags & SDF_OPEN_WRITE)) {
-                    sparcaudio_sync_output(driver);
-                    }
-                break;
-            
-
-	case AUDIO_GETDEV:
-		if (driver->ops->sunaudio_getdev) {
-			audio_device_t tmp;
-
-			driver->ops->sunaudio_getdev(driver, &tmp);
-
-			copy_to_user_ret((audio_device_t *)arg, &tmp, sizeof(tmp), -EFAULT);
-		} else
-			retval = -EINVAL;
-
-		break;
-
-	case AUDIO_GETDEV_SUNOS:
-		if (driver->ops->sunaudio_getdev_sunos) {
-			int tmp=driver->ops->sunaudio_getdev_sunos(driver);
-
-			if (put_user(tmp, (int *)arg))
-				retval = -EFAULT;
-		} else
-			retval = -EINVAL;
-
-		break;
-
-	case AUDIO_GETINFO:
-
-		AUDIO_INITINFO(&ainfo);
-
-		if (driver->ops->get_input_rate)
-		  ainfo.record.sample_rate =
-		    driver->ops->get_input_rate(driver);
-		if (driver->ops->get_input_channels)
-		  ainfo.record.channels =
-		    driver->ops->get_input_channels(driver);
-		if (driver->ops->get_input_precision)
-		  ainfo.record.precision =
-		    driver->ops->get_input_precision(driver);
-		if (driver->ops->get_input_encoding)
-		  ainfo.record.encoding =
-		    driver->ops->get_input_encoding(driver);
-		if (driver->ops->get_input_volume)
-		  ainfo.record.gain =
-		    driver->ops->get_input_volume(driver);
-		if (driver->ops->get_input_port)
-		  ainfo.record.port =
-		    driver->ops->get_input_port(driver);
-		if (driver->ops->get_input_ports)
-		  ainfo.record.avail_ports =
-		    driver->ops->get_input_ports(driver);
-		ainfo.record.buffer_size = 4096;
-		ainfo.record.samples = 0;
-		ainfo.record.eof = 0;
-		ainfo.record.pause = 0;
-		ainfo.record.error = 0;
-		ainfo.record.waiting = 0;
-		if (driver->ops->get_input_balance)
-		  ainfo.record.balance =
-		    driver->ops->get_input_balance(driver);
-		ainfo.record.minordev = 4;
-		ainfo.record.open = 1;
-		ainfo.record.active = 0;
-
-		if (driver->ops->get_output_rate)
-		  ainfo.play.sample_rate =
-		    driver->ops->get_output_rate(driver);
-		if (driver->ops->get_output_channels)
-		  ainfo.play.channels =
-		    driver->ops->get_output_channels(driver);
-		if (driver->ops->get_output_precision)
-		  ainfo.play.precision =
-		    driver->ops->get_output_precision(driver);
-		if (driver->ops->get_output_encoding)
-		  ainfo.play.encoding =
-		    driver->ops->get_output_encoding(driver);
-		if (driver->ops->get_output_volume)
-		  ainfo.play.gain =
-		    driver->ops->get_output_volume(driver);
-		if (driver->ops->get_output_port)
-		  ainfo.play.port =
-		    driver->ops->get_output_port(driver);
-		if (driver->ops->get_output_ports)
-		  ainfo.play.avail_ports =
-		    driver->ops->get_output_ports(driver);
-                /* This is not defined in the play context in Solaris */
-		ainfo.play.buffer_size = 0;
-		ainfo.play.samples = 0;
-		ainfo.play.eof = 0;
-		ainfo.play.pause = 0;
-		ainfo.play.error = 0;
-		ainfo.play.waiting = waitqueue_active(&driver->open_wait);
-		if (driver->ops->get_output_balance)
-		  ainfo.play.balance =
-                      (unsigned char)driver->ops->get_output_balance(driver);
-		ainfo.play.minordev = 4;
-		ainfo.play.open = 1;
-		ainfo.play.active = driver->output_active;
-
-		if (driver->ops->get_monitor_volume)
-		  ainfo.monitor_gain =
-		    driver->ops->get_monitor_volume(driver);
-
-		if (driver->ops->get_output_muted)
-		  ainfo.output_muted =
-                      (unsigned char)driver->ops->get_output_muted(driver);
-
-		copy_to_user_ret((struct audio_info *)arg, &ainfo,
-				 sizeof(ainfo), -EFAULT);
+  if (set_function && Modify(value))
+    return (int)set_function(drv, value);
+  else if (get_function)
+    return (int)get_function(drv);
+  else 
+    return 0;
+}
 
-		break;
+static __inline__ int 
+__sparcaudio_if_setc_do(struct sparcaudio_driver *drv, 
+			int (*set_function)(struct sparcaudio_driver *, int), 
+			int (*get_function)(struct sparcaudio_driver *), 
+			unsigned char value)
+{
+  if (set_function && Modifyc(value))
+    return (char)set_function(drv, (int)value);
+  else if (get_function)
+    return (char)get_function(drv);
+  else 
+    return 0;
+}
 
-	case AUDIO_SETINFO:
-	  {
-	    audio_info_t curinfo, newinfo;
+/* I_FLUSH, I_{G,S}ETSIG, I_NREAD provided for SunOS compatibility
+ *
+ * I must admit I'm quite ashamed of the state of the ioctl handling,
+ * but I do have several optimizations which I'm planning. -- DJB
+ */
 
-	    copy_from_user_ret(&ainfo, (audio_info_t *) arg, sizeof(audio_info_t), -EFAULT);
+static int sparcaudio_ioctl(struct inode * inode, struct file * file,
+			    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0, i, j, k;
+	int minor = MINOR(inode->i_rdev);
+	struct audio_info ainfo;
+	audio_buf_info binfo;
+	count_info cinfo;
+	struct sparcaudio_driver *drv = 
+	  drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
+
+	switch (minor & 0xf) {
+	case SPARCAUDIO_MIXER_MINOR:
+	  return sparcaudio_mixer_ioctl(inode, file, cmd, arg);
+	case SPARCAUDIO_DSP16_MINOR:
+        case SPARCAUDIO_DSP_MINOR:
+	case SPARCAUDIO_AUDIO_MINOR:
+	case SPARCAUDIO_AUDIOCTL_MINOR:
+	  switch (cmd) {
+	  case I_GETSIG:
+	  case I_GETSIG_SOLARIS:
+	    j = (int)lis_get_elist_ent(drv->sd_siglist,current->pid);
+	    COPY_OUT(arg, j);
+	    retval = drv->input_count;
+	    break;
 
-	    /* Without these there's no point in trying */
-	    if (!driver->ops->get_input_precision ||
-		!driver->ops->get_input_channels ||
-		!driver->ops->get_input_rate ||
-		!driver->ops->get_input_encoding ||
-		!driver->ops->get_output_precision ||
-		!driver->ops->get_output_channels ||
-                !driver->ops->get_output_rate ||
-                !driver->ops->get_output_encoding) 
-	      {
-		retval = -EINVAL;
-		break;
+	  case I_SETSIG:
+	  case I_SETSIG_SOLARIS:
+	    if ((minor & 0xf) == SPARCAUDIO_AUDIOCTL_MINOR) {
+	      if (!arg){
+		if (lis_del_from_elist(&(drv->sd_siglist),current->pid,S_ALL))
+		  retval = -EINVAL;
+		else 
+		  if (!drv->sd_siglist)
+		    drv->sd_sigflags=0;
 	      }
-
-	    /* Do bounds checking for things which always apply.
-	     * Follow with enforcement of basic tenets of certain
-	     * encodings. Everything over and above generic is
-	     * enforced by the driver, which can assume that
-	     * Martian cases are taken care of here. */
-	    if (Modify(ainfo.play.gain) && 
-		((ainfo.play.gain > AUDIO_MAX_GAIN) || 
-		 (ainfo.play.gain < AUDIO_MIN_GAIN))) {
-	      /* Need to differentiate this from e.g. the above error */
+	      else 
+		if (lis_add_to_elist(&(drv->sd_siglist),current->pid,
+				     (short)arg))
+		  retval = -EAGAIN;
+		else
+		  ((drv->sd_sigflags) |= (arg));
+	    }
+	    break;
+	  case I_NREAD:
+	  case I_NREAD_SOLARIS:
+	    /* According to the Solaris man page, this copies out
+	     * the size of the first streams buffer and returns 
+             * the number of streams messages on the read queue as
+	     * as its retval. (streamio(7I)) This should work. */
+             
+	    j = (drv->input_count > 0) ? drv->input_buffer_size : 0;
+	    COPY_OUT(arg, j);
+	    retval = drv->input_count;
+	    break;
+	    /*
+	     * A poor substitute until we do true resizable buffers.
+	     */
+	  case SNDCTL_DSP_GETISPACE:
+	    binfo.fragstotal = drv->num_input_buffers;
+	    binfo.fragments = drv->num_input_buffers - 
+	      (drv->input_count + drv->recording_count);
+	    binfo.fragsize = drv->input_buffer_size;
+	    binfo.bytes = binfo.fragments*binfo.fragsize;
+	    
+	    retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
+	    if (retval) break; 
+	    copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
+	    break;
+	  case SNDCTL_DSP_GETOSPACE:
+	    binfo.fragstotal = drv->num_output_buffers;
+	    binfo.fragments = drv->num_output_buffers - 
+	      (drv->output_count + drv->playing_count + 
+	       (drv->output_offset ? 1 : 0));
+	    binfo.fragsize = drv->output_buffer_size;
+	    binfo.bytes = binfo.fragments*binfo.fragsize + 
+	      (drv->output_buffer_size - drv->output_offset);
+	    
+	    retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
+	    if (retval) break; 
+	    copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
+	    break;
+	  case SNDCTL_DSP_GETIPTR:
+	  case SNDCTL_DSP_GETOPTR:
+	    /*
+	     * int bytes (number of bytes read/written since last)
+             * int blocks (number of frags read/wrote since last call)
+             * int ptr (current position of dma in buffer)
+	     */
+	    retval = 0;
+	    cinfo.bytes = 0;
+	    cinfo.ptr = 0;
+	    cinfo.blocks = 0;
+	    cinfo.bytes += cinfo.ptr;
+	    
+	    retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(cinfo));
+	    if (retval) break; 
+	    copy_to_user(&((char *)arg)[0], (char *)&cinfo, sizeof(cinfo));
+	    break;
+	  case SNDCTL_DSP_SETFRAGMENT:
+            /* XXX Small hack to get ESD/Enlightenment to work.  --DaveM */
+            retval = 0;
+            break;
+
+	  case SNDCTL_DSP_SUBDIVIDE:
+	    /*
+	     * I don't understand what I need to do yet.
+	     */
+	    retval = -EINVAL;
+	    break;
+	  case SNDCTL_DSP_SETTRIGGER:
+	    /* This may not be 100% correct */
+	    if ((arg & PCM_ENABLE_INPUT) && drv->ops->get_input_pause &&
+		drv->ops->set_input_pause) {
+	      if (drv->ops->get_input_pause(drv))
+		drv->ops->set_input_pause(drv, 0);
+	    } else {
+	      if (!drv->ops->get_input_pause(drv))
+		drv->ops->set_input_pause(drv, 1);
+	    }
+	    if ((arg & PCM_ENABLE_OUTPUT) && drv->ops->get_output_pause &&
+		drv->ops->set_output_pause) {
+	      if (drv->ops->get_output_pause(drv))
+		drv->ops->set_output_pause(drv, 0);
+	    } else {
+	      if (!drv->ops->get_output_pause(drv))
+		drv->ops->set_output_pause(drv, 1);
+	    }
+	    break;
+	  case SNDCTL_DSP_GETTRIGGER:
+            j = 0;
+	    if (drv->ops->get_input_pause)
+	      if (drv->ops->get_input_pause(drv))
+		j = PCM_ENABLE_INPUT;
+	    if (drv->ops->get_output_pause)
+	      if (drv->ops->get_output_pause(drv))
+		j |= PCM_ENABLE_OUTPUT;
+	    COPY_OUT(arg, j);
+	    break;
+	  case SNDCTL_DSP_GETBLKSIZE:
+	    j = drv->input_buffer_size;
+	    COPY_OUT(arg, j);
+	    break;
+	  case SNDCTL_DSP_SPEED:
+	    if ((!drv->ops->set_output_rate) && 
+		(!drv->ops->set_input_rate)) {
 	      retval = -EINVAL;
 	      break;
 	    }
-	    if (Modify(ainfo.record.gain) &&
-		((ainfo.record.gain > AUDIO_MAX_GAIN) ||
-		 (ainfo.record.gain < AUDIO_MIN_GAIN))) {
+	    COPY_IN(arg, i);
+	    tprintk(("setting speed to %d\n", i));
+	    drv->ops->set_input_rate(drv, i);
+	    drv->ops->set_output_rate(drv, i);
+	    j = drv->ops->get_output_rate(drv);
+	    COPY_OUT(arg, j);
+	    break;
+	  case SNDCTL_DSP_GETCAPS:
+	    /* 
+	     * All Sparc audio hardware is full duplex.
+	     * 4231 supports DMA pointer reading, 7930 is byte at a time.
+             * Pause functionality emulates trigger
+             */
+	    j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME;
+	    COPY_OUT(arg, j);
+	    break;
+	  case SNDCTL_DSP_GETFMTS:
+	    if (drv->ops->get_formats) {
+	      j = drv->ops->get_formats(drv);
+	      COPY_OUT(arg, j);
+	    } else
 	      retval = -EINVAL;
+	    break;
+	  case SNDCTL_DSP_SETFMT:
+	    /* need to decode into encoding, precision */
+	    COPY_IN(arg, i);
+	    
+	    /* handle special case here */
+	    if (i == AFMT_QUERY) {
+	      j = drv->ops->get_output_encoding(drv);
+	      k = drv->ops->get_output_precision(drv);
+	      if (j == AUDIO_ENCODING_DVI)
+                i = AFMT_IMA_ADPCM;
+	      else if (k == 8) {
+		switch (j) {
+		case AUDIO_ENCODING_ULAW:
+		  i = AFMT_MU_LAW;
+		  break;
+		case AUDIO_ENCODING_ALAW:
+		  i = AFMT_A_LAW;
+		  break;
+		case AUDIO_ENCODING_LINEAR8:
+		  i = AFMT_U8;
+		  break;
+		}
+	      } else if (k == 16) {
+		case AUDIO_ENCODING_LINEAR:
+		  i = AFMT_S16_BE;
+		  break;
+		case AUDIO_ENCODING_LINEARLE:
+		  i = AFMT_S16_LE;
+		  break;
+	      } 
+	      COPY_OUT(arg, i);
 	      break;
 	    }
-	    if (Modify(ainfo.monitor_gain) &&
-		((ainfo.monitor_gain > AUDIO_MAX_GAIN) ||
-		 (ainfo.monitor_gain < AUDIO_MIN_GAIN))) {
+
+            /* Without these there's no point in trying */
+            if (!drv->ops->set_input_precision ||
+                !drv->ops->set_input_encoding ||
+                !drv->ops->set_output_precision ||
+                !drv->ops->set_output_encoding) {
+	      eprintk(("missing set routines: failed\n"));
 	      retval = -EINVAL;
 	      break;
-	    }
-	    /* Don't need to check less than zero on these */
-	    if (Modifyc(ainfo.play.balance) &&
-		(ainfo.play.balance > AUDIO_RIGHT_BALANCE)) {
+            }
+
+	    if (drv->ops->get_formats)
+	      if (!(drv->ops->get_formats(drv) & i)) {
+		dprintk(("format not supported\n"));
+		return -EINVAL;
+	      }
+
+            switch (i) {
+            case AFMT_S16_LE:
+              ainfo.record.precision = ainfo.play.precision = 16;
+              ainfo.record.encoding = ainfo.play.encoding =
+		AUDIO_ENCODING_LINEARLE;
+              break;
+            case AFMT_S16_BE:
+              ainfo.record.precision = ainfo.play.precision = 16;
+              ainfo.record.encoding = ainfo.play.encoding =
+		AUDIO_ENCODING_LINEAR;
+              break;
+            case AFMT_MU_LAW:
+              ainfo.record.precision = ainfo.play.precision = 8;
+              ainfo.record.encoding = ainfo.play.encoding =
+		AUDIO_ENCODING_ULAW;
+              break;
+            case AFMT_A_LAW:
+              ainfo.record.precision = ainfo.play.precision = 8;
+              ainfo.record.encoding = ainfo.play.encoding =
+		AUDIO_ENCODING_ALAW;
+              break;
+            case AFMT_U8:
+              ainfo.record.precision = ainfo.play.precision = 8;
+              ainfo.record.encoding = ainfo.play.encoding =
+		AUDIO_ENCODING_LINEAR8;
+              break;
+            }
+	    tprintk(("setting fmt to enc %d pr %d\n", ainfo.play.encoding,
+		     ainfo.play.precision));
+            if ((drv->ops->set_input_precision(drv,
+						  ainfo.record.precision) 
+		 < 0) ||
+                (drv->ops->set_output_precision(drv,
+						   ainfo.play.precision)  
+		 < 0) ||
+                (drv->ops->set_input_encoding(drv,
+						 ainfo.record.encoding)
+		 < 0) ||
+                (drv->ops->set_output_encoding(drv,
+						  ainfo.play.encoding)
+		 < 0)) {
+	      dprintk(("setting format: failed\n"));
+	      return -EINVAL;
+            }
+	    COPY_OUT(arg, i);
+            break;
+	  case SNDCTL_DSP_CHANNELS:
+	    if ((!drv->ops->set_output_channels) && 
+		(!drv->ops->set_input_channels)) {
 	      retval = -EINVAL;
 	      break;
 	    }
-	    if (Modifyc(ainfo.record.balance) &&
-		(ainfo.record.balance > AUDIO_RIGHT_BALANCE)) {
+	    COPY_IN(arg, i);
+	    drv->ops->set_input_channels(drv, i);
+	    drv->ops->set_output_channels(drv, i);
+	    i = drv->ops->get_output_channels(drv);
+	    COPY_OUT(arg, i);
+	    break;
+	  case SNDCTL_DSP_STEREO:
+	    if ((!drv->ops->set_output_channels) && 
+		(!drv->ops->set_input_channels)) {
 	      retval = -EINVAL;
 	      break;
 	    }
-	    
-	    /* If any of these changed, record them all, then make
-	     * changes atomically. If something fails, back it all out. */
-	    if (Modify(ainfo.record.precision) || 
-		Modify(ainfo.record.sample_rate) ||
-		Modify(ainfo.record.channels) ||
-		Modify(ainfo.record.encoding) || 
-		Modify(ainfo.play.precision) || 
-		Modify(ainfo.play.sample_rate) ||
-		Modify(ainfo.play.channels) ||
-		Modify(ainfo.play.encoding)) 
-	      {
-		/* If they're trying to change something we
-		 * have no routine for, they lose */
-		if ((!driver->ops->set_input_encoding && 
-		    Modify(ainfo.record.encoding)) ||
-		    (!driver->ops->set_input_rate && 
-		    Modify(ainfo.record.sample_rate)) ||
-		    (!driver->ops->set_input_precision && 
-		    Modify(ainfo.record.precision)) ||
-		    (!driver->ops->set_input_channels && 
-		    Modify(ainfo.record.channels))) {
-		  retval = -EINVAL;
-		  break;
-		}		  
-
-                curinfo.record.encoding = driver->ops->get_input_encoding(driver);
-                curinfo.record.sample_rate = driver->ops->get_input_rate(driver);
-                curinfo.record.precision = driver->ops->get_input_precision(driver);
-                curinfo.record.channels = driver->ops->get_input_channels(driver);
-                newinfo.record.encoding = Modify(ainfo.record.encoding) ?
-                  ainfo.record.encoding : curinfo.record.encoding;
-                newinfo.record.sample_rate = Modify(ainfo.record.sample_rate)?
-                  ainfo.record.sample_rate : curinfo.record.sample_rate;
-                newinfo.record.precision = Modify(ainfo.record.precision) ?
-                  ainfo.record.precision : curinfo.record.precision;
-                newinfo.record.channels = Modify(ainfo.record.channels) ?
-                  ainfo.record.channels : curinfo.record.channels;
+	    COPY_IN(arg, i);
+	    drv->ops->set_input_channels(drv, (i + 1));
+	    drv->ops->set_output_channels(drv, (i + 1));
+	    i = ((drv->ops->get_output_channels(drv)) - 1);
+	    COPY_OUT(arg, i);
+	    break;
+	  case SNDCTL_DSP_POST:
+	  case SNDCTL_DSP_SYNC:
+	  case AUDIO_DRAIN:
+	    /* Deal with weirdness so we can fill buffers */
+	    if (drv->output_offset) {
+	      drv->output_offset = 0;
+	      drv->output_rear = (drv->output_rear + 1)
+		% drv->num_output_buffers;
+	      drv->output_count++;
+	    }
+	    if (drv->output_count > 0) {
+	      sparcaudio_sync_output(drv);
+	      /* Only pause for DRAIN/SYNC, not POST */
+	      if (cmd != SNDCTL_DSP_POST) {
+		interruptible_sleep_on(&drv->output_drain_wait);
+		retval = (signal_pending(current)) ? -EINTR : 0;
+	      }
+	    }
+	    break;
+	  case I_FLUSH:
+	  case I_FLUSH_SOLARIS:
+	    if (((unsigned int)arg == FLUSHW) || 
+		((unsigned int)arg == FLUSHRW)) {
+	      if (file->f_mode & FMODE_WRITE) {
+		sparcaudio_sync_output(drv);
+		if (drv->output_active) {
+		  wake_up_interruptible(&drv->output_write_wait);
+		  drv->ops->stop_output(drv);
+		}
+		drv->output_offset = 0;
+		drv->output_active = 0;
+		drv->output_front = 0;
+		drv->output_rear = 0;
+		drv->output_count = 0;
+		drv->output_size = 0;
+		drv->playing_count = 0;
+		drv->output_eof = 0;
+	      }
+	    }
+	    if (((unsigned int)arg == FLUSHR) || 
+		((unsigned int)arg == FLUSHRW)) {
+	      if (drv->input_active && (file->f_mode & FMODE_READ)) {
+		wake_up_interruptible(&drv->input_read_wait);
+		drv->ops->stop_input(drv);
+		drv->input_active = 0;
+		drv->input_front = 0;
+		drv->input_rear = 0;
+		drv->input_count = 0;
+		drv->input_size = 0;
+		drv->input_offset = 0;
+		drv->recording_count = 0;
+	      }
+	      if ((file->f_mode & FMODE_READ) && 
+		  (drv->flags & SDF_OPEN_READ)) {
+		if (drv->duplex == 2)
+		  drv->input_count = drv->output_count;
+		drv->ops->start_input(drv, 
+					 drv->input_buffers[drv->input_front],
+					 drv->input_buffer_size);
+		drv->input_active = 1;
+	      }
+	    }
+	    if (((unsigned int)arg == FLUSHW) || 
+		((unsigned int)arg == FLUSHRW)) {
+	      if ((file->f_mode & FMODE_WRITE) && 
+		  !(drv->flags & SDF_OPEN_WRITE)) {
+		kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+		sparcaudio_sync_output(drv);
+	      }
+	    }
+	    break;
+	  case SNDCTL_DSP_RESET:
+	  case AUDIO_FLUSH:
+	    if (drv->output_active && (file->f_mode & FMODE_WRITE)) {
+	      wake_up_interruptible(&drv->output_write_wait);
+	      drv->ops->stop_output(drv);
+	      drv->output_active = 0;
+	      drv->output_front = 0;
+	      drv->output_rear = 0;
+	      drv->output_count = 0;
+	      drv->output_size = 0;
+	      drv->playing_count = 0;
+	      drv->output_offset = 0;
+	      drv->output_eof = 0;
+	    }
+	    if (drv->input_active && (file->f_mode & FMODE_READ)) {
+	      wake_up_interruptible(&drv->input_read_wait);
+	      drv->ops->stop_input(drv);
+	      drv->input_active = 0;
+	      drv->input_front = 0;
+	      drv->input_rear = 0;
+	      drv->input_count = 0;
+	      drv->input_size = 0;
+	      drv->input_offset = 0;
+	      drv->recording_count = 0;
+	    }
+	    if ((file->f_mode & FMODE_READ) && 
+		!(drv->flags & SDF_OPEN_READ)) {
+	      drv->ops->start_input(drv, 
+				       drv->input_buffers[drv->input_front],
+				       drv->input_buffer_size);
+	      drv->input_active = 1;
+	    }
+	    if ((file->f_mode & FMODE_WRITE) && 
+		!(drv->flags & SDF_OPEN_WRITE)) {
+	      sparcaudio_sync_output(drv);
+	    }
+	    break;
+	  case AUDIO_GETDEV:
+	    if (drv->ops->sunaudio_getdev) {
+	      audio_device_t tmp;
+	      
+	      retval = verify_area(VERIFY_WRITE, (void *)arg, 
+				   sizeof(audio_device_t));
+	      if (!retval)
+		drv->ops->sunaudio_getdev(drv, &tmp);
+	      copy_to_user((audio_device_t *)arg, &tmp, sizeof(tmp));
+	    } else
+	      retval = -EINVAL;
+	    break;
+	  case AUDIO_GETDEV_SUNOS:
+	    if (drv->ops->sunaudio_getdev_sunos) {
+	      int tmp = drv->ops->sunaudio_getdev_sunos(drv);
+	      
+	      retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
+	      if (!retval)
+		copy_to_user((int *)arg, &tmp, sizeof(tmp));
+	    } else
+	      retval = -EINVAL;
+	    break;
+	  case AUDIO_GETINFO:
+	    AUDIO_INITINFO(&ainfo);
 
-		switch (newinfo.record.encoding) {
-		case AUDIO_ENCODING_ALAW:
-		case AUDIO_ENCODING_ULAW:
-                  if (newinfo.record.precision != 8) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.record.channels != 1) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  break;
-                case AUDIO_ENCODING_LINEAR:
-                case AUDIO_ENCODING_LINEARLE:
-                  if (newinfo.record.precision != 16) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.record.channels != 1 &&
-                       newinfo.record.channels != 2)
-                    {
-                      retval = -EINVAL;
-                      break;
-                    }
-                  break;
-                case AUDIO_ENCODING_LINEAR8:
-                  if (newinfo.record.precision != 8) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.record.channels != 1 &&
-                       newinfo.record.channels != 2)
-                    {
-                      retval = -EINVAL;
-                      break;
-                    }
-                }
+	    if (drv->ops->get_input_rate)
+	      ainfo.record.sample_rate =
+		drv->ops->get_input_rate(drv);
+	    else
+	      ainfo.record.sample_rate = (8000);
+	    if (drv->ops->get_input_channels)
+	      ainfo.record.channels =
+		drv->ops->get_input_channels(drv);
+	    else
+	      ainfo.record.channels = (1);
+	    if (drv->ops->get_input_precision)
+	      ainfo.record.precision =
+		drv->ops->get_input_precision(drv);
+	    else
+	      ainfo.record.precision = (8);
+	    if (drv->ops->get_input_encoding)
+	      ainfo.record.encoding =
+		drv->ops->get_input_encoding(drv);
+	    else
+	      ainfo.record.encoding = (AUDIO_ENCODING_ULAW);
+	    if (drv->ops->get_input_volume)
+	      ainfo.record.gain =
+		drv->ops->get_input_volume(drv);
+	    else
+	      ainfo.record.gain = (0);
+	    if (drv->ops->get_input_port)
+	      ainfo.record.port =
+		drv->ops->get_input_port(drv);
+	    else
+	      ainfo.record.port = (0);
+	    if (drv->ops->get_input_ports)
+	      ainfo.record.avail_ports = 
+		drv->ops->get_input_ports(drv);
+	    else
+	      ainfo.record.avail_ports = (0);
+	    /* To make e.g. vat happy, we let them think they control this */
+	    ainfo.record.buffer_size = drv->buffer_size;
+	    if (drv->ops->get_input_samples)
+	      ainfo.record.samples = drv->ops->get_input_samples(drv);
+	    else
+	      ainfo.record.samples = 0;
+	    /* This is undefined in the record context in Solaris */
+	    ainfo.record.eof = 0;
+	    if (drv->ops->get_input_pause)
+	      ainfo.record.pause =
+		drv->ops->get_input_pause(drv);
+	    else
+	      ainfo.record.pause = 0;
+	    if (drv->ops->get_input_error)
+	      ainfo.record.error = 
+		(unsigned char)drv->ops->get_input_error(drv);
+	    else
+	      ainfo.record.error = 0;
+	    ainfo.record.waiting = 0;
+	    if (drv->ops->get_input_balance)
+	      ainfo.record.balance =
+		(unsigned char)drv->ops->get_input_balance(drv);
+	    else
+	      ainfo.record.balance = (unsigned char)(AUDIO_MID_BALANCE);
+	    ainfo.record.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
+	    ainfo.record.open = (drv->flags & SDF_OPEN_READ);
+	    ainfo.record.active = 0;
+
+	    if (drv->ops->get_output_rate)
+	      ainfo.play.sample_rate =
+		drv->ops->get_output_rate(drv);
+	    else
+	      ainfo.play.sample_rate = (8000);
+	    if (drv->ops->get_output_channels)
+	      ainfo.play.channels =
+		drv->ops->get_output_channels(drv);
+	    else
+	      ainfo.play.channels = (1);
+	    if (drv->ops->get_output_precision)
+	      ainfo.play.precision =
+		drv->ops->get_output_precision(drv);
+	    else
+	      ainfo.play.precision = (8);
+	    if (drv->ops->get_output_encoding)
+	      ainfo.play.encoding =
+		drv->ops->get_output_encoding(drv);
+	    else
+	      ainfo.play.encoding = (AUDIO_ENCODING_ULAW);
+	    if (drv->ops->get_output_volume)
+	      ainfo.play.gain =
+		drv->ops->get_output_volume(drv);
+	    else
+	      ainfo.play.gain = (0);
+	    if (drv->ops->get_output_port)
+	      ainfo.play.port =
+		drv->ops->get_output_port(drv);
+	    else
+	      ainfo.play.port = (0);
+	    if (drv->ops->get_output_ports)
+	      ainfo.play.avail_ports = 
+		drv->ops->get_output_ports(drv);
+	    else
+	      ainfo.play.avail_ports = (0);
+	    /* This is not defined in the play context in Solaris */
+	    ainfo.play.buffer_size = 0;
+	    if (drv->ops->get_output_samples)
+	      ainfo.play.samples = drv->ops->get_output_samples(drv);
+	    else
+	      ainfo.play.samples = 0;
+	    ainfo.play.eof = drv->output_eof;
+	    if (drv->ops->get_output_pause)
+	      ainfo.play.pause =
+		drv->ops->get_output_pause(drv);
+	    else
+	      ainfo.play.pause = 0;
+	    if (drv->ops->get_output_error)
+	      ainfo.play.error =
+		(unsigned char)drv->ops->get_output_error(drv);
+	    else
+	      ainfo.play.error = 0;
+	    ainfo.play.waiting = waitqueue_active(&drv->open_wait);
+	    if (drv->ops->get_output_balance)
+	      ainfo.play.balance =
+		(unsigned char)drv->ops->get_output_balance(drv);
+	    else
+	      ainfo.play.balance = (unsigned char)(AUDIO_MID_BALANCE);
+	    ainfo.play.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
+	    ainfo.play.open = (drv->flags & SDF_OPEN_WRITE);
+	    ainfo.play.active = drv->output_active;
+	    
+	    if (drv->ops->get_monitor_volume)
+	      ainfo.monitor_gain =
+		drv->ops->get_monitor_volume(drv);
+	    else
+	      ainfo.monitor_gain = (0);
+
+	    if (drv->ops->get_output_muted)
+	      ainfo.output_muted = 
+		(unsigned char)drv->ops->get_output_muted(drv);
+	    else
+	      ainfo.output_muted = (unsigned char)(0);
+
+	    retval = verify_area(VERIFY_WRITE, (void *)arg,
+				 sizeof(struct audio_info));
+	    if (retval < 0)
+	      break;
 
-		if (retval < 0)
-		  break;
+	    copy_to_user((struct audio_info *)arg, &ainfo, sizeof(ainfo));
+	    
+	    break;
+	  case AUDIO_SETINFO:
+	    {
+	      audio_info_t curinfo, newinfo;
+	      
+	      if (verify_area(VERIFY_READ, (audio_info_t *)arg, 
+			      sizeof(audio_info_t))) {
+		dprintk(("verify_area failed\n"));
+		return -EINVAL;
+	      }
+	      copy_from_user(&ainfo, (audio_info_t *)arg, sizeof(audio_info_t));
 
-		/* If they're trying to change something we
-		 * have no routine for, they lose */
-		if ((!driver->ops->set_output_encoding && 
-		    Modify(ainfo.play.encoding)) ||
-		    (!driver->ops->set_output_rate && 
-		    Modify(ainfo.play.sample_rate)) ||
-		    (!driver->ops->set_output_precision && 
-		    Modify(ainfo.play.precision)) ||
-		    (!driver->ops->set_output_channels && 
-		    Modify(ainfo.play.channels))) {
+	      /* Without these there's no point in trying */
+	      if (!drv->ops->get_input_precision ||
+		  !drv->ops->get_input_channels ||
+		  !drv->ops->get_input_rate ||
+		  !drv->ops->get_input_encoding ||
+		  !drv->ops->get_output_precision ||
+		  !drv->ops->get_output_channels ||
+		  !drv->ops->get_output_rate ||
+		  !drv->ops->get_output_encoding) 
+		{
+		  eprintk(("missing get routines: failed\n"));
 		  retval = -EINVAL;
 		  break;
-		}		  
-
-                curinfo.play.encoding = driver->ops->get_output_encoding(driver);
-                curinfo.play.sample_rate = driver->ops->get_output_rate(driver);
-                curinfo.play.precision = driver->ops->get_output_precision(driver);
-                curinfo.play.channels = driver->ops->get_output_channels(driver);
-                newinfo.play.encoding = Modify(ainfo.play.encoding) ?
-                  ainfo.play.encoding : curinfo.play.encoding;
-                newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ?
-                  ainfo.play.sample_rate : curinfo.play.sample_rate;
-                newinfo.play.precision = Modify(ainfo.play.precision) ?
-                  ainfo.play.precision : curinfo.play.precision;
-                newinfo.play.channels = Modify(ainfo.play.channels) ?
-                  ainfo.play.channels : curinfo.play.channels;
-
-		switch (newinfo.play.encoding) {
-		case AUDIO_ENCODING_ALAW:
-		case AUDIO_ENCODING_ULAW:
-                  if (newinfo.play.precision != 8) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.play.channels != 1) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  break;
-                case AUDIO_ENCODING_LINEAR:
-                case AUDIO_ENCODING_LINEARLE:
-                  if (newinfo.play.precision != 16) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.play.channels != 1 &&
-                       newinfo.play.channels != 2)
-                    {
-                      retval = -EINVAL;
-                      break;
-                    }
-                  break;
-                case AUDIO_ENCODING_LINEAR8:
-                  if (newinfo.play.precision != 8) {
-                    retval = -EINVAL;
-                    break;
-                  }
-                  if (newinfo.play.channels != 1 &&
-                       newinfo.play.channels != 2)
-                    {
-                      retval = -EINVAL;
-                      break;
-                    }
-                }
-		
-		if (retval < 0)
-		  break;
+		}
 
-		/* If we got this far, we're at least sane with
-		 * respect to generics. Try the changes. */
-		if ((driver->ops->set_input_precision(driver, ainfo.record.precision) < 0) ||
-		    (driver->ops->set_output_precision(driver, ainfo.play.precision) < 0) ||
-		    (driver->ops->set_input_channels(driver, ainfo.record.channels) < 0) ||
-		    (driver->ops->set_output_channels(driver, ainfo.play.channels) < 0) ||
-		    (driver->ops->set_input_rate(driver, ainfo.record.sample_rate) < 0) ||
-		    (driver->ops->set_output_rate(driver, ainfo.play.sample_rate) < 0) ||
-		    (driver->ops->set_input_encoding(driver, ainfo.record.encoding) < 0) ||
-		    (driver->ops->set_output_encoding(driver, ainfo.play.encoding) < 0)) 
-		  {
-		    /* Pray we can set it all back. If not, uh... */
-		    driver->ops->set_input_precision(driver, curinfo.record.precision);
-		    driver->ops->set_output_precision(driver, curinfo.play.precision);
-		    driver->ops->set_input_channels(driver, curinfo.record.channels);
-		    driver->ops->set_output_channels(driver, curinfo.play.channels);
-		    driver->ops->set_input_rate(driver, curinfo.record.sample_rate);
-		    driver->ops->set_output_rate(driver, curinfo.play.sample_rate);
-		    driver->ops->set_input_encoding(driver, curinfo.record.encoding); 
-		    driver->ops->set_output_encoding(driver, curinfo.play.encoding);
+	      /* Do bounds checking for things which always apply.
+	       * Follow with enforcement of basic tenets of certain
+	       * encodings. Everything over and above generic is
+	       * enforced by the driver, which can assume that
+	       * Martian cases are taken care of here. */
+	      if (Modify(ainfo.play.gain) && 
+		  ((ainfo.play.gain > AUDIO_MAX_GAIN) || 
+		   (ainfo.play.gain < AUDIO_MIN_GAIN))) {
+		/* Need to differentiate this from e.g. the above error */
+		eprintk(("play gain bounds: failed %d\n", ainfo.play.gain));
+		retval = -EINVAL;
+		break;
+	      }
+	      if (Modify(ainfo.record.gain) &&
+		  ((ainfo.record.gain > AUDIO_MAX_GAIN) ||
+		   (ainfo.record.gain < AUDIO_MIN_GAIN))) {
+		eprintk(("rec gain bounds: failed %d\n", ainfo.record.gain));
+		retval = -EINVAL;
+		break;
+	      }
+	      if (Modify(ainfo.monitor_gain) &&
+		  ((ainfo.monitor_gain > AUDIO_MAX_GAIN) ||
+		   (ainfo.monitor_gain < AUDIO_MIN_GAIN))) {
+		eprintk(("monitor gain bounds: failed\n"));
+		retval = -EINVAL;
+		break;
+	      }
+	      /* Don't need to check less than zero on these */
+	      if (Modifyc(ainfo.play.balance) &&
+		  (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) {
+		eprintk(("play balance bounds: %d failed\n", 
+			 (int)ainfo.play.balance));
+		retval = -EINVAL;
+		break;
+	      }
+	      if (Modifyc(ainfo.record.balance) &&
+		  (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) {
+		eprintk(("rec balance bounds: failed\n"));
+		retval = -EINVAL;
+		break;
+	      }
+	      
+	      /* If any of these changed, record them all, then make
+	       * changes atomically. If something fails, back it all out. */
+	      if (Modify(ainfo.record.precision) || 
+		  Modify(ainfo.record.sample_rate) ||
+		  Modify(ainfo.record.channels) ||
+		  Modify(ainfo.record.encoding) || 
+		  Modify(ainfo.play.precision) || 
+		  Modify(ainfo.play.sample_rate) ||
+		  Modify(ainfo.play.channels) ||
+		  Modify(ainfo.play.encoding)) 
+		{
+		  /* If they're trying to change something we
+		   * have no routine for, they lose */
+		  if ((!drv->ops->set_input_encoding && 
+		       Modify(ainfo.record.encoding)) ||
+		      (!drv->ops->set_input_rate && 
+		       Modify(ainfo.record.sample_rate)) ||
+		      (!drv->ops->set_input_precision && 
+		       Modify(ainfo.record.precision)) ||
+		      (!drv->ops->set_input_channels && 
+		       Modify(ainfo.record.channels))) {
+		    eprintk(("rec set no routines: failed\n"));
+		    retval = -EINVAL;
+		    break;
+		  }		  
+		  
+		  curinfo.record.encoding = 
+		    drv->ops->get_input_encoding(drv);
+		  curinfo.record.sample_rate = 
+		    drv->ops->get_input_rate(drv);	   
+		  curinfo.record.precision = 
+		    drv->ops->get_input_precision(drv);	   
+		  curinfo.record.channels = 
+		    drv->ops->get_input_channels(drv);	   
+		  newinfo.record.encoding = Modify(ainfo.record.encoding) ? 
+		    ainfo.record.encoding : curinfo.record.encoding;
+		  newinfo.record.sample_rate =
+		    Modify(ainfo.record.sample_rate)?
+		    ainfo.record.sample_rate : curinfo.record.sample_rate;
+		  newinfo.record.precision = Modify(ainfo.record.precision) ? 
+		    ainfo.record.precision : curinfo.record.precision;
+		  newinfo.record.channels = Modify(ainfo.record.channels) ? 
+		    ainfo.record.channels : curinfo.record.channels;
+		    
+		  switch (newinfo.record.encoding) {
+		  case AUDIO_ENCODING_ALAW:
+		  case AUDIO_ENCODING_ULAW:
+		    if (newinfo.record.precision != 8) {
+		      eprintk(("rec law precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.record.channels != 1) {
+		      eprintk(("rec law channel bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    break;
+		  case AUDIO_ENCODING_LINEAR:
+		  case AUDIO_ENCODING_LINEARLE:
+		    if (newinfo.record.precision != 16) {
+		      eprintk(("rec lin precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.record.channels != 1 && 
+			newinfo.record.channels != 2) 
+		      {
+			eprintk(("rec lin channel bounds: failed\n"));
+			retval = -EINVAL;
+			break;
+		      }
+		    break;
+		  case AUDIO_ENCODING_LINEAR8:
+		    if (newinfo.record.precision != 8) {
+		      eprintk(("rec lin8 precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.record.channels != 1 && 
+			newinfo.record.channels != 2)
+		      {
+			eprintk(("rec lin8 channel bounds: failed\n"));
+			retval = -EINVAL;
+			break;
+		      }
+		  }
+		  
+		  if (retval < 0)
+		    break;
+		  
+		  /* If they're trying to change something we
+		   * have no routine for, they lose */
+		  if ((!drv->ops->set_output_encoding && 
+		       Modify(ainfo.play.encoding)) ||
+		      (!drv->ops->set_output_rate && 
+		       Modify(ainfo.play.sample_rate)) ||
+		      (!drv->ops->set_output_precision && 
+		       Modify(ainfo.play.precision)) ||
+		      (!drv->ops->set_output_channels && 
+		       Modify(ainfo.play.channels))) {
+		    eprintk(("play set no routine: failed\n"));
+		    retval = -EINVAL;
+		    break;
+		  }		  
+		  
+		  curinfo.play.encoding = 
+		    drv->ops->get_output_encoding(drv);
+		  curinfo.play.sample_rate = 
+		    drv->ops->get_output_rate(drv);	   
+		  curinfo.play.precision = 
+		    drv->ops->get_output_precision(drv);	   
+		  curinfo.play.channels = 
+		    drv->ops->get_output_channels(drv);	   
+		  newinfo.play.encoding = Modify(ainfo.play.encoding) ? 
+		    ainfo.play.encoding : curinfo.play.encoding;
+		  newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ? 
+		    ainfo.play.sample_rate : curinfo.play.sample_rate;
+		  newinfo.play.precision = Modify(ainfo.play.precision) ? 
+		    ainfo.play.precision : curinfo.play.precision;
+		  newinfo.play.channels = Modify(ainfo.play.channels) ? 
+		    ainfo.play.channels : curinfo.play.channels;
+		  
+		  switch (newinfo.play.encoding) {
+		  case AUDIO_ENCODING_ALAW:
+		  case AUDIO_ENCODING_ULAW:
+		    if (newinfo.play.precision != 8) {
+		      eprintk(("play law precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.play.channels != 1) {
+		      eprintk(("play law channel bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    break;
+		  case AUDIO_ENCODING_LINEAR:
+		  case AUDIO_ENCODING_LINEARLE:
+		    if (newinfo.play.precision != 16) {
+		      eprintk(("play lin precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.play.channels != 1 && 
+			newinfo.play.channels != 2) 
+		      {
+			eprintk(("play lin channel bounds: failed\n"));
+			retval = -EINVAL;
+			break;
+		      }
+		    break;
+		  case AUDIO_ENCODING_LINEAR8:
+		    if (newinfo.play.precision != 8) {
+		      eprintk(("play lin8 precision bounds: failed\n"));
+		      retval = -EINVAL;
+		      break;
+		    }
+		    if (newinfo.play.channels != 1 && 
+			newinfo.play.channels != 2) 
+		      {
+			eprintk(("play lin8 channel bounds: failed\n"));
+			retval = -EINVAL;
+			break;
+		      }
 		  }
+		  
+		  if (retval < 0)
+		    break;
+		  
+		  /* If we got this far, we're at least sane with
+		   * respect to generics. Try the changes. */
+		  if ((drv->ops->set_input_channels &&
+		      (drv->ops->set_input_channels(drv, 
+						    newinfo.record.channels)
+		       < 0)) ||
+		      (drv->ops->set_output_channels &&
+		       (drv->ops->set_output_channels(drv, 
+						      newinfo.play.channels)
+			< 0)) ||
+		      (drv->ops->set_input_rate &&
+		       (drv->ops->set_input_rate(drv, 
+						 newinfo.record.sample_rate) 
+			< 0)) ||
+		      (drv->ops->set_output_rate &&
+		       (drv->ops->set_output_rate(drv, 
+						  newinfo.play.sample_rate) 
+			< 0)) ||
+		      (drv->ops->set_input_precision &&
+		       (drv->ops->set_input_precision(drv, 
+						      newinfo.record.precision)
+			< 0)) ||
+		      (drv->ops->set_output_precision &&
+		       (drv->ops->set_output_precision(drv, 
+						       newinfo.play.precision)
+			< 0)) ||
+		      (drv->ops->set_input_encoding &&
+		       (drv->ops->set_input_encoding(drv, 
+						     newinfo.record.encoding)
+			< 0)) ||
+		      (drv->ops->set_output_encoding &&
+		       (drv->ops->set_output_encoding(drv, 
+						      newinfo.play.encoding)
+			< 0))) 
+		    {
+		      dprintk(("setting format: failed\n"));
+		      /* Pray we can set it all back. If not, uh... */
+		      if (drv->ops->set_input_channels)
+			drv->ops->set_input_channels(drv, 
+						     curinfo.record.channels);
+		      if (drv->ops->set_output_channels)
+			drv->ops->set_output_channels(drv, 
+						      curinfo.play.channels);
+		      if (drv->ops->set_input_rate)
+			drv->ops->set_input_rate(drv, 
+						 curinfo.record.sample_rate);
+		      if (drv->ops->set_output_rate)
+			drv->ops->set_output_rate(drv, 
+						  curinfo.play.sample_rate);
+		      if (drv->ops->set_input_precision)
+			drv->ops->set_input_precision(drv, 
+						      curinfo.record.precision);
+		      if (drv->ops->set_output_precision)
+			drv->ops->set_output_precision(drv, 
+						       curinfo.play.precision);
+		      if (drv->ops->set_input_encoding)
+			drv->ops->set_input_encoding(drv, 
+						     curinfo.record.encoding);
+		      if (drv->ops->set_output_encoding)
+			drv->ops->set_output_encoding(drv, 
+						      curinfo.play.encoding);
+		      retval = -EINVAL;
+		      break;
+		    }
+		}
+	      
+	      if (retval < 0)
+		break;
+	      
+	      newinfo.record.balance =
+		__sparcaudio_if_setc_do(drv, 
+					drv->ops->set_input_balance, 
+					drv->ops->get_input_balance,
+					ainfo.record.balance);
+	      newinfo.play.balance =
+		__sparcaudio_if_setc_do(drv, 
+					drv->ops->set_output_balance, 
+					drv->ops->get_output_balance,
+					ainfo.play.balance);
+	      newinfo.record.error =
+		__sparcaudio_if_setc_do(drv, 
+					drv->ops->set_input_error, 
+					drv->ops->get_input_error,
+					ainfo.record.error);
+	      newinfo.play.error =
+		__sparcaudio_if_setc_do(drv, 
+					drv->ops->set_output_error, 
+					drv->ops->get_output_error,
+					ainfo.play.error);
+	      newinfo.output_muted =
+		__sparcaudio_if_setc_do(drv, 
+					drv->ops->set_output_muted, 
+					drv->ops->get_output_muted,
+					ainfo.output_muted);
+	      newinfo.record.gain =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_input_volume, 
+					drv->ops->get_input_volume,
+					ainfo.record.gain);
+	      newinfo.play.gain =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_output_volume, 
+					drv->ops->get_output_volume,
+					ainfo.play.gain);
+	      newinfo.record.port =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_input_port, 
+					drv->ops->get_input_port,
+					ainfo.record.port);
+	      newinfo.play.port =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_output_port, 
+					drv->ops->get_output_port,
+					ainfo.play.port);
+	      newinfo.record.samples =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_input_samples, 
+					drv->ops->get_input_samples,
+					ainfo.record.samples);
+	      newinfo.play.samples =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_output_samples, 
+					drv->ops->get_output_samples,
+					ainfo.play.samples);
+	      newinfo.monitor_gain =
+		__sparcaudio_if_set_do(drv, 
+					drv->ops->set_monitor_volume, 
+					drv->ops->get_monitor_volume,
+					ainfo.monitor_gain);
+
+	      if (Modify(ainfo.record.buffer_size)) {
+		/* Should sanity check this */
+		newinfo.record.buffer_size = ainfo.record.buffer_size;
+		drv->buffer_size = ainfo.record.buffer_size;
+	      } else 
+		newinfo.record.buffer_size = drv->buffer_size;
+
+
+	      if (Modify(ainfo.play.eof)) {
+		ainfo.play.eof = newinfo.play.eof;
+		newinfo.play.eof = drv->output_eof;
+		drv->output_eof = ainfo.play.eof;
+	      } else
+		newinfo.play.eof = drv->output_eof;
+		
+	      if (drv->flags & SDF_OPEN_READ) {
+		newinfo.record.pause =
+		  __sparcaudio_if_setc_do(drv, 
+					  drv->ops->set_input_pause, 
+					  drv->ops->get_input_pause,
+					  ainfo.record.pause);
+	      } else if (drv->ops->get_input_pause) {
+		newinfo.record.pause = drv->ops->get_input_pause(drv);
+	      } else newinfo.record.pause = 0;
+
+	      if (drv->flags & SDF_OPEN_WRITE) {
+		newinfo.play.pause =
+		  __sparcaudio_if_setc_do(drv, 
+					  drv->ops->set_output_pause, 
+					  drv->ops->get_output_pause,
+					  ainfo.play.pause);
+	      } else if (drv->ops->get_output_pause) {
+		newinfo.play.pause = drv->ops->get_output_pause(drv);
+	      } else newinfo.play.pause = 0;
+	      
+	      retval = verify_area(VERIFY_WRITE, (void *)arg,
+				   sizeof(struct audio_info));
+
+	      /* Even if we fail, if we made changes let's try notification */
+	      if (!retval) 
+		copy_to_user((struct audio_info *)arg, &newinfo, 
+			     sizeof(newinfo));
+	    
+#ifdef REAL_AUDIO_SIGNALS
+	      kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+#endif
 
+	      break;
 	    }
-            /* Maybe this should be a routine instead of a macro */
-#define IF_SET_DO(x,y) if ((x) && Modify(y)) x(driver, y)
-#define IF_SETC_DO(x,y) if ((x) && Modifyc(y)) x(driver, y)
-            IF_SETC_DO(driver->ops->set_input_balance, (int)ainfo.record.balance);
-            IF_SETC_DO(driver->ops->set_output_balance, (int)ainfo.play.balance);
-            IF_SET_DO(driver->ops->set_input_volume, ainfo.record.gain);
-            IF_SET_DO(driver->ops->set_output_volume, ainfo.play.gain);
-            IF_SET_DO(driver->ops->set_input_port, ainfo.record.port);
-            IF_SET_DO(driver->ops->set_output_port, ainfo.play.port);
-            IF_SET_DO(driver->ops->set_monitor_volume, ainfo.monitor_gain);
-            IF_SETC_DO(driver->ops->set_output_muted, (int)ainfo.output_muted);
-#undef IF_SET_DO
-#undef IF_SETC_DO
-
-	    break;
+	  
+	  default:
+	    if (drv->ops->ioctl)
+	      retval = drv->ops->ioctl(inode,file,cmd,arg,drv);
+	    else
+	      retval = -EINVAL;
 	  }
-
+	  break;
+	case SPARCAUDIO_STATUS_MINOR:
+	  eprintk(("status minor not yet implemented\n"));
+	  retval = -EINVAL;
 	default:
-		if (driver->ops->ioctl)
-			retval = driver->ops->ioctl(inode,file,cmd,arg,driver);
-		else {
-			retval = -EINVAL;
-		}
+	  eprintk(("unknown minor device number\n"));
+	  retval = -EINVAL;
 	}
-
+	
 	return retval;
 }
 
-static int sparcaudioctl_release(struct inode * inode, struct file * file)
+static int sparcaudioctl_release_ret(struct inode * inode, struct file * file)
 {
-	MOD_DEC_USE_COUNT;
+      MOD_DEC_USE_COUNT;
+      return 0;
+}
 
-	return 0;
+/* For 2.0 kernels */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static void sparcaudioctl_release(struct inode * inode, struct file * file)
+{
+  sparcaudioctl_release_ret(inode, file);
 }
+#endif
 
 static struct file_operations sparcaudioctl_fops = {
-	NULL,
-	NULL,
-	NULL,
-	NULL,			/* sparcaudio_readdir */
-	NULL,			/* sparcaudio_select */
-	sparcaudio_ioctl,
-	NULL,			/* sparcaudio_mmap */
-	NULL,
-	NULL,			/* flush */
-	sparcaudioctl_release
+      NULL,
+      NULL,
+      NULL,
+      NULL,                   /* sparcaudio_readdir */
+      sparcaudio_select,
+      sparcaudio_ioctl,
+      NULL,                   /* sparcaudio_mmap */
+      NULL,
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+      NULL,                   /* sparcaudio_flush */
+#endif
+      sparcaudioctl_release,
 };
 
 static int sparcaudio_open(struct inode * inode, struct file * file)
 {
-    int minor = MINOR(inode->i_rdev);
-    int err;
+        int minor = MINOR(inode->i_rdev);
+	struct sparcaudio_driver *drv = 
+	  drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
+	int err;
+
+	/* A low-level audio driver must exist. */
+	if (!drv)
+		return -ENODEV;
+
+	switch (minor & 0xf) {
+	case SPARCAUDIO_AUDIOCTL_MINOR:
+	  file->f_op = &sparcaudioctl_fops;
+	  break;
+	case SPARCAUDIO_DSP16_MINOR:
+	case SPARCAUDIO_DSP_MINOR:
+	case SPARCAUDIO_AUDIO_MINOR:
+	  /* If the driver is busy, then wait to get through. */
+	  retry_open:
+	  if (file->f_mode & FMODE_READ && drv->flags & SDF_OPEN_READ) {
+	    if (file->f_flags & O_NONBLOCK)
+	      return -EBUSY;
+
+	    /* If something is now waiting, signal control device */
+	    kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
 
-    /* A low-level audio driver must exist. */
-    if (!driver)
-        return -ENODEV;
-
-    switch (minor) {
-    case SPARCAUDIO_AUDIOCTL_MINOR:
-        file->f_op = &sparcaudioctl_fops;
-        break;
-
-    case SPARCAUDIO_DSP16_MINOR:
-    case SPARCAUDIO_DSP_MINOR:
-    case SPARCAUDIO_AUDIO_MINOR:
-        /* If the driver is busy, then wait to get through. */
-    retry_open:
-	if (file->f_mode & FMODE_READ && driver->flags & SDF_OPEN_READ) {
-            if (file->f_flags & O_NONBLOCK)
-                return -EBUSY;
-            
-            interruptible_sleep_on(&driver->open_wait);
+	    interruptible_sleep_on(&drv->open_wait);
             if (signal_pending(current))
-                return -EINTR;
-            goto retry_open;
-	}
-	if (file->f_mode & FMODE_WRITE && driver->flags & SDF_OPEN_WRITE) {
-            if (file->f_flags & O_NONBLOCK)
-                return -EBUSY;
-            
-            interruptible_sleep_on(&driver->open_wait);
+	      return -EINTR;
+	    goto retry_open;
+	  }
+	  if (file->f_mode & FMODE_WRITE && drv->flags & SDF_OPEN_WRITE) {
+	    if (file->f_flags & O_NONBLOCK)
+	      return -EBUSY;
+	    
+	    /* If something is now waiting, signal control device */
+	    kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
+
+	    interruptible_sleep_on(&drv->open_wait);
             if (signal_pending(current))
-                return -EINTR;
-            goto retry_open;
-	}
+	      return -EINTR;
+	    goto retry_open;
+	  }
 
-	/* Allow the low-level driver to initialize itself. */
-	if (driver->ops->open) {
-            err = driver->ops->open(inode,file,driver);
-            if (err < 0)
-                return err;
-	}
-        
-	/* Mark the driver as locked for read and/or write. */
-	if (file->f_mode & FMODE_READ) {
-            driver->input_offset = 0;
-            driver->input_front = 0;
-            driver->input_rear = 0;
-            driver->input_count = 0;
-            driver->recording_count = 0;
-            driver->ops->start_input(driver, driver->input_buffers[driver->input_front],
-                                     4096);
-            driver->input_active = 1;
-            driver->flags |= SDF_OPEN_READ;
+	  /* Allow the low-level driver to initialize itself. */
+	  if (drv->ops->open) {
+	    err = drv->ops->open(inode,file,drv);
+	    if (err < 0)
+	      return err;
+	  }
+
+	  /* Mark the driver as locked for read and/or write. */
+	  if (file->f_mode & FMODE_READ) {
+	    drv->input_offset = 0;
+	    drv->input_front = 0;
+	    drv->input_rear = 0;
+	    drv->input_count = 0;
+	    drv->input_size = 0;
+	    drv->recording_count = 0;
+	    /* Clear pause */
+	    if (drv->ops->set_input_pause)
+	      drv->ops->set_input_pause(drv, 0); 
+	    drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
+				     drv->input_buffer_size);
+	    drv->input_active = 1;
+	    drv->flags |= SDF_OPEN_READ;
+	  }
+	  if (file->f_mode & FMODE_WRITE) {
+	    drv->output_offset = 0;
+	    drv->output_eof = 0;
+	    drv->playing_count = 0;
+	    drv->output_size = 0;
+	    drv->output_front = 0;
+	    drv->output_rear = 0;
+	    drv->output_count = 0;
+	    drv->output_active = 0;
+	    /* Clear pause */
+	    if (drv->ops->set_output_pause)
+	      drv->ops->set_output_pause(drv, 0); 
+	    drv->flags |= SDF_OPEN_WRITE;
+	  }  
+
+	  break;
+	case SPARCAUDIO_MIXER_MINOR:     
+	  file->f_op = &sparcaudioctl_fops;
+	  break;
+
+	default:
+	  return -ENXIO;
 	}
-	if (file->f_mode & FMODE_WRITE) {
-            driver->playing_count = 0;
-            driver->output_size = 0;
-            driver->output_front = 0;
-            driver->output_rear = 0;
-            driver->output_count = 0;
-            driver->output_active = 0;
-            driver->flags |= SDF_OPEN_WRITE;
-	}  
-        break;
-    case SPARCAUDIO_MIXER_MINOR:     
-        file->f_op = &sparcaudioctl_fops;
-        break;
 
-    default:
-        return -ENXIO;
-    }
+	MOD_INC_USE_COUNT;
 
-    MOD_INC_USE_COUNT;
-    
-    /* Success! */
-    return 0;
+	/* Success! */
+	return 0;
 }
 
-static int sparcaudio_release(struct inode * inode, struct file * file)
+static int sparcaudio_release_ret(struct inode * inode, struct file * file)
 {
-        /* Anything in the queue? */
-        sparcaudio_sync_output(driver);
+  struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+                                           SPARCAUDIO_DEVICE_SHIFT)];
 
-	/* Stop input */
-	driver->ops->stop_input(driver);
-	driver->input_active = 0;
+  if (file->f_mode & FMODE_READ) {
+    /* Stop input */
+    drv->ops->stop_input(drv);
+    drv->input_active = 0;
+  }
+
+  if (file->f_mode & FMODE_WRITE) {
+    /* Anything in the queue? */
+    if (drv->output_offset) {
+      drv->output_offset = 0;
+      drv->output_rear = (drv->output_rear + 1)
+	% drv->num_output_buffers;
+      drv->output_count++;
+    }
+    sparcaudio_sync_output(drv);
 
-	/* Wait for any output still in the queue to be played. */
-	if (driver->output_count > 0)
-		interruptible_sleep_on(&driver->output_drain_wait);
+    /* Wait for any output still in the queue to be played. */
+    if ((drv->output_count > 0) || (drv->playing_count > 0))
+      interruptible_sleep_on(&drv->output_drain_wait);
 
-	/* Force any output to be stopped. */
-	driver->ops->stop_output(driver);
-	driver->output_active = 0;
+    /* Force any output to be stopped. */
+    drv->ops->stop_output(drv);
+    drv->output_active = 0;
+    drv->playing_count = 0;
+    drv->output_eof = 0;
 
-	/* Let the low-level driver do any release processing. */
-	if (driver->ops->release)
-		driver->ops->release(inode,file,driver);
+  }
 
-	if (file->f_mode & FMODE_READ)
-		driver->flags &= ~(SDF_OPEN_READ);
+  /* Let the low-level driver do any release processing. */
+  if (drv->ops->release)
+    drv->ops->release(inode,file,drv);
 
-	if (file->f_mode & FMODE_WRITE)
-		driver->flags &= ~(SDF_OPEN_WRITE);
+  if (file->f_mode & FMODE_READ)
+    drv->flags &= ~(SDF_OPEN_READ);
 
-	MOD_DEC_USE_COUNT;
+  if (file->f_mode & FMODE_WRITE) 
+    drv->flags &= ~(SDF_OPEN_WRITE);
 
-	wake_up_interruptible(&driver->open_wait);
+  /* Status changed. Signal control device */
+  kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
 
-	return 0;
+  MOD_DEC_USE_COUNT;
+
+  wake_up_interruptible(&drv->open_wait);
+
+  return 0;
+}
+
+/* For 2.0 kernels */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static void sparcaudio_release(struct inode * inode, struct file * file)
+{
+  sparcaudio_release_ret(inode, file);
 }
+#endif
 
 static struct file_operations sparcaudio_fops = {
-	sparcaudio_llseek,
+	sparcaudio_lseek,
 	sparcaudio_read,
 	sparcaudio_write,
 	NULL,			/* sparcaudio_readdir */
-	NULL,			/* sparcaudio_select */
+	sparcaudio_select,
 	sparcaudio_ioctl,
 	NULL,			/* sparcaudio_mmap */
 	sparcaudio_open,
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+      NULL,                   /* sparcaudio_flush */
+#endif
 	sparcaudio_release
 };
 
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+static struct symbol_table sparcaudio_syms = {
+#include <linux/symtab_begin.h>
+	X(register_sparcaudio_driver),
+	X(unregister_sparcaudio_driver),
+	X(sparcaudio_output_done),
+	X(sparcaudio_input_done),
+#include <linux/symtab_end.h>
+};
+#else
 EXPORT_SYMBOL(register_sparcaudio_driver);
 EXPORT_SYMBOL(unregister_sparcaudio_driver);
 EXPORT_SYMBOL(sparcaudio_output_done);
 EXPORT_SYMBOL(sparcaudio_input_done);
+#endif
 
 #ifdef MODULE
 int init_module(void)
@@ -1023,20 +2058,27 @@
 __initfunc(int sparcaudio_init(void))
 #endif
 {
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+	/* Export symbols for use by the low-level drivers. */
+	register_symtab(&sparcaudio_syms);
+#endif
+
 	/* Register our character device driver with the VFS. */
 	if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
 		return -EIO;
 
+	
 #ifdef CONFIG_SPARCAUDIO_AMD7930
 	amd7930_init();
 #endif
-
+#ifdef CONFIG_SPARCAUDIO_DBRI
+        dbri_init();
+#endif
 #ifdef CONFIG_SPARCAUDIO_CS4231
 	cs4231_init();
 #endif
-
-#ifdef CONFIG_SPARCAUDIO_DBRI
-	dbri_init();
+#ifdef CONFIG_SPARCAUDIO_DUMMY
+	dummy_init();
 #endif
 
 	return 0;
@@ -1048,6 +2090,147 @@
 	unregister_chrdev(SOUND_MAJOR, "sparcaudio");
 }
 #endif
+
+/*
+ * Code from Linux Streams, Copyright 1995 by
+ * Graham Wheeler, Francisco J. Ballesteros, Denis Froschauer
+ * and available under GPL 
+ */
+
+static int
+lis_add_to_elist( strevent_t **list, pid_t pid, short events )
+{
+    strevent_t *ev = NULL;
+
+    if (*list != NULL)
+      {
+        for (ev=(*list)->se_next;
+             ev != *list && ev->se_pid < pid;
+             ev=ev->se_next
+            );    
+      }
+
+    if (ev == NULL || ev == *list)              /* no slot for pid in list */
+      {
+        if ((ev = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL))==NULL)
+            return(-ENOMEM);
+
+        if (!*list)                     /* create dummy head node */
+	  {
+            strevent_t *hd;
+            if ((hd = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL)
+                                         )==NULL)
+	      {
+                kfree(ev);
+                return(-ENOMEM);
+	      }
+            (*list=hd)->se_pid=0;
+            hd->se_next=hd->se_prev=hd;         /* empty list */
+	  }
+
+        /* link node last in the list */
+        ev->se_prev=(*list)->se_prev;
+        (*list)->se_prev->se_next=ev;
+        ((*list)->se_prev=ev)->se_next=*list;
+
+        ev->se_pid=pid;
+        ev->se_evs=0;
+      }
+    else if (ev->se_pid!=pid){  /* link node in the middle of the list */
+        strevent_t *new;
+        if ((new = (strevent_t*)kmalloc(sizeof(strevent_t),GFP_KERNEL))==NULL){
+            return(-ENOMEM);
+        }
+        new->se_prev=ev->se_prev;
+        new->se_next=ev;
+        ev->se_prev->se_next=new;
+        ev->se_prev=new;
+        ev = new ;                              /* use new element */
+        ev->se_pid=pid;
+        ev->se_evs=0;
+    }
+    ev->se_evs|=events;
+    return(0);
+}
+
+static int
+lis_del_from_elist( strevent_t **list, pid_t pid, short events )
+{
+    strevent_t *ev = NULL;     
+
+    if (*list != NULL)
+      {
+        for (ev=(*list)->se_next;
+             ev != *list && ev->se_pid < pid;
+             ev=ev->se_next
+            );    
+      }
+
+    if (ev == NULL || ev == *list || ev->se_pid != pid )
+        return(1);
+
+    if ( (ev->se_evs &= ~events) == 0 ){        /* unlink */
+        if (ev->se_next)                        /* should always be true */
+            ev->se_next->se_prev=ev->se_prev;
+        if (ev->se_prev)                        /* should always be true */
+            ev->se_prev->se_next=ev->se_next;
+        kfree(ev);
+    }
+    return(0);
+}
+
+static void
+lis_free_elist( strevent_t **list )
+{
+    strevent_t  *ev;     
+    strevent_t  *nxt ;
+
+    for (ev = *list; ev != NULL; )
+      {
+        nxt = ev->se_next ;
+        kfree(ev) ;
+        ev = nxt ;
+        if (ev == *list) break ;                /* all done */
+      }
+
+    *list = NULL ;
+}
+
+static short
+lis_get_elist_ent( strevent_t *list, pid_t pid )
+{
+    strevent_t *ev = NULL;
+
+    if (list == NULL) return(0) ;
+
+    for(ev = list->se_next ; ev != list && ev->se_pid < pid; ev=ev->se_next )
+        ;
+    if (ev != list && ev->se_pid == pid)
+        return(ev->se_evs);
+    else
+        return(0);
+}
+
+static void 
+kill_procs( struct strevent *elist, int sig, short e)
+{
+  strevent_t *ev;
+  int res;
+
+  (void) sig ;
+  if (elist) {
+    for(ev = elist->se_next ; ev != elist; ev=ev->se_next )
+      if ((ev->se_evs & e) != 0){
+	if ((res=kill_proc(ev->se_pid,SIGPOLL,1))<0) {
+	  if (res == -3) {
+	    lis_del_from_elist(&elist, ev->se_pid, S_ALL);
+	    continue;
+	  }
+	  dprintk(("kill_proc: errno %d\n",res));
+	}
+      }
+  }
+}
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.1.128/linux/drivers/sbus/audio/cs4231.c	Thu Aug  6 14:06:32 1998
+++ linux/drivers/sbus/audio/cs4231.c	Wed Nov 18 09:06:05 1998
@@ -1,10 +1,10 @@
 /*
  * drivers/sbus/audio/cs4231.c
  *
- * Copyright (C) 1996, 1997 Derrick J Brashear (shadow@andrew.cmu.edu)
+ * Copyright 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
  *
  * Based on the AMD7930 driver:
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
+ * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
  *
  * This is the lowlevel driver for the CS4231 audio chip found on some
  * sun4m and sun4u machines.
@@ -14,6 +14,7 @@
  * The APC DMA controller support unfortunately is not documented. Thanks, Sun
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -22,6 +23,8 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/version.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
@@ -35,7 +38,7 @@
 
 #undef __CS4231_DEBUG
 #undef __CS4231_TRACE
-#undef __CS4231_ERROR
+#define __CS4231_ERROR
 #ifdef __CS4231_ERROR
 #define eprintk(x) printk x
 #else
@@ -70,7 +73,7 @@
 static void cs4231_getsamplecount(struct sparcaudio_driver *drv, 
                                   unsigned int length, unsigned int value);
 
-#define CHIP_READY udelay(100); cs4231_ready(drv); mdelay(1);
+#define CHIP_READY udelay(100); cs4231_ready(drv); udelay(1000);
 
 /* Enable cs4231 interrupts atomically. */
 static __inline__ void cs4231_enable_interrupts(struct sparcaudio_driver *drv)
@@ -269,7 +272,7 @@
       return 0;
     }
   }
-  eprintk(("output enc failed\n"));
+  dprintk(("output enc failed\n"));
   return -EINVAL;
 }
 
@@ -285,7 +288,7 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int tmp_bits, set_bits;
 
-  dprintk(("input encoding %d\n", value));
+  tprintk(("input encoding %d\n", value));
   if (value != 0) {
     set_bits = cs4231_encoding_to_bits(drv, value);
     if (set_bits >= 0) {
@@ -299,7 +302,7 @@
       return 0;
     }
   }
-  eprintk(("input enc failed\n"));
+  dprintk(("input enc failed\n"));
   return -EINVAL;
 }
 
@@ -329,7 +332,7 @@
       return 0;
     }
   }
-  eprintk(("output rate failed\n"));
+  dprintk(("output rate failed\n"));
   return -EINVAL;
 }
 
@@ -345,7 +348,7 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int tmp_bits, set_bits;
 
-  dprintk(("input rate %d\n", value));
+  tprintk(("input rate %d\n", value));
   if (value != 0) {
     set_bits = cs4231_rate_to_bits(drv, value);
     if (set_bits >= 0) {
@@ -359,7 +362,7 @@
       return 0;
     }
   }
-  eprintk(("input rate failed\n"));
+  dprintk(("input rate failed\n"));
   return -EINVAL;
 }
 
@@ -376,7 +379,7 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int tmp_bits;
 
-  dprintk(("input channels %d\n", value));
+  tprintk(("input channels %d\n", value));
   cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c;
   tmp_bits = cs4231_chip->regs->idr;
   switch (value) {
@@ -387,7 +390,7 @@
     cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
     break;
   default:
-    eprintk(("input chan failed\n"));
+    dprintk(("input chan failed\n"));
     return -(EINVAL);
   }  
 
@@ -421,7 +424,7 @@
     cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
     break;
   default:
-    eprintk(("output chan failed\n"));
+    dprintk(("output chan failed\n"));
     return -(EINVAL);
   }  
 
@@ -437,29 +440,33 @@
       return cs4231_chip->perchip_info.play.channels;
 }
 
-static int cs4231_set_input_precision(struct sparcaudio_driver *drv, int value)
+static int cs4231_get_input_precision(struct sparcaudio_driver *drv)
 {
       struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-      cs4231_chip->perchip_info.record.precision = value;
-      return 0;
+      return cs4231_chip->perchip_info.record.precision;
 }
 
-static int cs4231_get_input_precision(struct sparcaudio_driver *drv)
+static int cs4231_get_output_precision(struct sparcaudio_driver *drv)
 {
       struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-      return cs4231_chip->perchip_info.record.precision;
+      return cs4231_chip->perchip_info.play.precision;
 }
 
-static int cs4231_set_output_precision(struct sparcaudio_driver *drv, int value)
+static int cs4231_set_input_precision(struct sparcaudio_driver *drv, int val)
 {
       struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-      cs4231_chip->perchip_info.play.precision = value;
-      return 0;
+
+      cs4231_chip->perchip_info.record.precision = val;
+
+      return cs4231_chip->perchip_info.record.precision;
 }
 
-static int cs4231_get_output_precision(struct sparcaudio_driver *drv)
+static int cs4231_set_output_precision(struct sparcaudio_driver *drv, int val)
 {
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; 
+
+      cs4231_chip->perchip_info.play.precision = val;
+
       return cs4231_chip->perchip_info.play.precision;
 }
 
@@ -509,6 +516,12 @@
   return cs4231_chip->perchip_info.output_muted;
 }
 
+static int cs4231_get_formats(struct sparcaudio_driver *drv)
+{
+      return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_IMA_ADPCM | 
+              AFMT_S16_LE | AFMT_S16_BE);
+}
+
 static int cs4231_get_output_ports(struct sparcaudio_driver *drv)
 {
       return (AUDIO_LINE_OUT | AUDIO_SPEAKER | AUDIO_HEADPHONE);
@@ -577,11 +590,11 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int retval = 0;
 
-  dprintk(("input port: %d\n", value));
+  tprintk(("input port: %d\n", value));
 
   /* You can have one and only one. This is probably wrong, but
    * appears to be how SunOS is doing it. Should be able to mix.
-   * More work to be done.
+   * More work to be done. CD input mixable, analog loopback may be.
    */
 
   /* Ultra systems do not support AUDIO_INTERNAL_CD_IN */
@@ -663,6 +676,58 @@
         return (int)cs4231_chip->perchip_info.monitor_gain;
 }
 
+static int cs4231_get_output_error(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+
+        return (int)cs4231_chip->perchip_info.play.error;
+}
+
+static int cs4231_get_input_error(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+
+        return (int)cs4231_chip->perchip_info.record.error;
+}
+
+static int cs4231_get_output_samples(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+        int count = 
+          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, 
+                                       cs4231_chip->regs->dmapc);
+
+        return (cs4231_chip->perchip_info.play.samples - 
+                ((count > cs4231_chip->perchip_info.play.samples) 
+                 ? 0 : count));
+}
+
+static int cs4231_get_input_samples(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+        int count = 
+          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, 
+                                       cs4231_chip->regs->dmacc);
+
+        return (cs4231_chip->perchip_info.record.samples - 
+                ((count > cs4231_chip->perchip_info.record.samples) ?
+                0 : count));
+}
+
+static int cs4231_get_output_pause(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+
+        return (int)cs4231_chip->perchip_info.play.pause;
+}
+
+static int cs4231_get_input_pause(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+
+        return (int)cs4231_chip->perchip_info.record.pause;
+}
+
 /* But for play/record we have these cheesy jacket routines because of 
  * how this crap gets set */
 static int cs4231_set_input_volume(struct sparcaudio_driver *drv, int value)
@@ -704,7 +769,7 @@
         struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
 	cs4231_chip->perchip_info.record.balance = value;
-	cs4231_record_gain(drv, cs4231_chip->perchip_info.record.gain,
+	cs4231_record_gain(drv, cs4231_chip->perchip_info.record.gain, 
                            cs4231_chip->perchip_info.record.balance);
 	
         return 0;
@@ -745,13 +810,11 @@
   r = l = value;
 
   if (balance < AUDIO_MID_BALANCE) {
-      r = (int)(value - ((AUDIO_MID_BALANCE - balance) 
-                         << AUDIO_BALANCE_SHIFT));
-      if (r < 0) r = 0;
+    r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
+    if (r < 0) r = 0;
   } else if (balance > AUDIO_MID_BALANCE) {
-      l = (int)(value - ((balance - AUDIO_MID_BALANCE) 
-                         << AUDIO_BALANCE_SHIFT));
-      if (l < 0) l = 0;
+    l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
+    if (l < 0) l = 0;
   }
 
   l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
@@ -785,20 +848,18 @@
   tprintk(("in play_gain: %d %c\n", value, balance));
   r = l = value;
   if (balance < AUDIO_MID_BALANCE) {
-      r = (int)(value - ((AUDIO_MID_BALANCE - balance)
-                         << AUDIO_BALANCE_SHIFT));
-      if (r < 0) r = 0;
+    r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
+    if (r < 0) r = 0;
   } else if (balance > AUDIO_MID_BALANCE) {
-      l = (int)(value - ((balance - AUDIO_MID_BALANCE) 
-                         << AUDIO_BALANCE_SHIFT));
-      if (l < 0) l = 0;
+    l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
+    if (l < 0) l = 0;
   }
 
   (l == 0) ? (l_adj = CS4231_MAX_DEV_ATEN) : (l_adj = CS4231_MAX_ATEN - 
                                               (l * (CS4231_MAX_ATEN + 1) / 
                                                (AUDIO_MAX_GAIN + 1)));
-  (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN - 
-                                              (r * (CS4231_MAX_ATEN + 1) / 
+  (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN -
+                                              (r * (CS4231_MAX_ATEN + 1) /
                                                (AUDIO_MAX_GAIN + 1)));
   
   cs4231_chip->regs->iar = 0x6;
@@ -811,10 +872,10 @@
   if ((value == 0) || (value == AUDIO_MAX_GAIN)) {
     tmp = value;
   } else {
-    if (value == l) 
+    if (value == l)
       tmp = ((CS4231_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / 
              (CS4231_MAX_ATEN + 1));
-    else if (r == value) 
+    else if (value == r)
       tmp = ((CS4231_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / 
              (CS4231_MAX_ATEN + 1));
   }
@@ -900,7 +961,16 @@
   cs4231_output_muted(drv, 0);
 
   cs4231_chip->recording_count = 0;
+  cs4231_chip->input_next_dma_handle = 0;
+  cs4231_chip->input_dma_handle = 0;
+  cs4231_chip->input_next_dma_size = 0;
+  cs4231_chip->input_dma_size = 0;
+
   cs4231_chip->playing_count = 0;
+  cs4231_chip->output_next_dma_handle = 0;
+  cs4231_chip->output_dma_handle = 0;
+  cs4231_chip->output_next_dma_size = 0;
+  cs4231_chip->output_dma_size = 0;
 }
 
 static int 
@@ -945,6 +1015,7 @@
     }
   count = thisdir->samples;
   length = cs4231_length_to_samplecount(thisdir, length);
+  /* normalize for where we are. */
   thisdir->samples = ((count - nextcount) + (length - curcount));
 }
 
@@ -957,7 +1028,8 @@
     if (!(drv->flags & SDF_OPEN_WRITE) && 
 	(cs4231_chip->perchip_info.play.active == 0)) {
       cs4231_chip->perchip_info.play.open = 1;
-      cs4231_set_output_port(drv, AUDIO_SPEAKER);
+      cs4231_chip->perchip_info.play.samples =
+        cs4231_chip->perchip_info.play.error = 0;
     }
   }
 
@@ -965,7 +1037,8 @@
     if (!(drv->flags & SDF_OPEN_READ) && 
 	(cs4231_chip->perchip_info.record.active == 0)) {
       cs4231_chip->perchip_info.record.open = 1;
-      cs4231_set_input_port(drv, AUDIO_MICROPHONE);
+      cs4231_chip->perchip_info.record.samples = 
+        cs4231_chip->perchip_info.record.error = 0;
     }
   }  
 
@@ -984,11 +1057,40 @@
 
   /* zero out any info about what data we have as well */
 
-  if (file->f_mode & FMODE_READ) 
-      cs4231_chip->perchip_info.record.open = 0;
+  if (file->f_mode & FMODE_READ) {
+    /* stop capture here or midlevel? */
+    cs4231_chip->perchip_info.record.open = 0;
+    if (cs4231_chip->input_dma_handle) {
+      mmu_release_scsi_one((u32)((unsigned long)cs4231_chip->input_dma_handle),
+                           cs4231_chip->input_dma_size, drv->dev->my_bus);
+      cs4231_chip->input_dma_handle = 0;
+      cs4231_chip->input_dma_size = 0;
+    }
+    if (cs4231_chip->input_next_dma_handle) {
+      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle),
+                           cs4231_chip->input_next_dma_size, drv->dev->my_bus);
+      cs4231_chip->input_next_dma_handle = 0;
+      cs4231_chip->input_next_dma_size = 0;
+    }
+  }
 
-  if (file->f_mode & FMODE_WRITE) 
+  if (file->f_mode & FMODE_WRITE) {
+    cs4231_chip->perchip_info.play.active =
       cs4231_chip->perchip_info.play.open = 0;
+    if (cs4231_chip->output_dma_handle) {
+      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle),
+                           cs4231_chip->output_dma_size, drv->dev->my_bus);
+      cs4231_chip->output_dma_handle = 0;
+      cs4231_chip->output_dma_size = 0;
+    }
+    if (cs4231_chip->output_next_dma_handle) {
+      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle),
+                           cs4231_chip->output_next_dma_size, 
+                           drv->dev->my_bus);
+      cs4231_chip->output_next_dma_handle = 0;
+      cs4231_chip->output_next_dma_size = 0;
+    }
+  }
 
   if (!cs4231_chip->perchip_info.play.open && 
       !cs4231_chip->perchip_info.record.open && 
@@ -1003,53 +1105,60 @@
 static void cs4231_playintr(struct sparcaudio_driver *drv)
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  int status = 0;
 
-  if (cs4231_chip->playlen == 0)
+  if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) 
     cs4231_chip->playlen = cs4231_chip->output_size;
 
   if (cs4231_chip->output_dma_handle) {
-      mmu_release_scsi_one((char *)cs4231_chip->output_dma_handle, 
-                           4096, drv->dev->my_bus);
-      cs4231_chip->output_dma_handle = 0;
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), 
+                         cs4231_chip->output_dma_size, drv->dev->my_bus);
+    cs4231_chip->output_dma_handle = 0;
+    cs4231_chip->output_dma_size = 0;
+    cs4231_chip->playing_count--;
+    status++;
   }
   if (cs4231_chip->output_next_dma_handle) {
-      cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle;
-      cs4231_chip->output_next_dma_handle = 0;
+    cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle;
+    cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size;
+    cs4231_chip->output_next_dma_size = 0;
+    cs4231_chip->output_next_dma_handle = 0;
+  }
+
+  if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && 
+      !(cs4231_chip->perchip_info.play.pause)) {
+    cs4231_chip->output_next_dma_handle = (u32 *) (unsigned long)
+      mmu_get_scsi_one((char *) cs4231_chip->output_ptr, 
+                       cs4231_chip->output_size, drv->dev->my_bus);
+    cs4231_chip->regs->dmapnva = (u32) (unsigned long)
+      cs4231_chip->output_next_dma_handle;
+    cs4231_chip->output_next_dma_size = cs4231_chip->regs->dmapnc = 
+      cs4231_chip->output_size;
+    cs4231_chip->output_size = 0;
+    cs4231_chip->output_ptr = NULL;
+    cs4231_chip->playing_count++;
+    status += 2;
+  } else {
+    cs4231_chip->regs->dmapnva = 0;
+    cs4231_chip->regs->dmapnc = 0;
   }
 
-  if (cs4231_chip->output_ptr && cs4231_chip->output_size > 0) {
-      cs4231_chip->output_next_dma_handle = 
-          mmu_get_scsi_one((char *) cs4231_chip->output_ptr, 4096, 
-                           drv->dev->my_bus);
-      cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle;
-      cs4231_chip->regs->dmapnc = cs4231_chip->output_size;
-      cs4231_chip->output_size = 0;
-      cs4231_chip->output_ptr = NULL;
-      cs4231_chip->playing_count++;
-  }
+  sparcaudio_output_done(drv, status);
 
-  /* Get two buffers into the pipe, then chain... */
-  if (cs4231_chip->playing_count < 3) 
-    sparcaudio_output_done(drv, 0);
-  else {
-    cs4231_chip->playing_count--;
-    sparcaudio_output_done(drv, 1);
-  }
-
-  return; 
+  return;
 }
 
-static void cs4231_recmute(int fmt)
+static void cs4231_recclear(int fmt, char *dmabuf, int length)
 {
   switch (fmt) {
   case AUDIO_ENCODING_LINEAR:
-    /* Insert 0x00 from "here" to end of data stream */
+    memset(dmabuf, 0x00, length);
     break;
   case AUDIO_ENCODING_ALAW:
-    /* Insert 0xd5 from "here" to end of data stream */
+    memset(dmabuf, 0xd5, length);
     break;
   case AUDIO_ENCODING_ULAW:
-    /* Insert 0xff from "here" to end of data stream */
+    memset(dmabuf, 0xff, length);
     break;
   }
 }
@@ -1057,19 +1166,51 @@
 static int cs4231_recintr(struct sparcaudio_driver *drv)
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  int status = 0;
 
   if (cs4231_chip->perchip_info.record.active == 0) {
+    dprintk(("going inactive\n"));
     cs4231_pollinput(drv);
-    cs4231_recmute(cs4231_chip->perchip_info.record.encoding);
     cs4231_disable_rec(drv);    
-  }
-  if (cs4231_chip->input_ptr) {
-    cs4231_chip->regs->dmacnva = (__u32) cs4231_chip->input_ptr;
-    cs4231_chip->regs->dmacnc = cs4231_chip->input_size;
-    cs4231_chip->input_ptr = NULL;
+  } 
+
+  if (cs4231_chip->input_dma_handle) {
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle),
+                         cs4231_chip->input_dma_size, drv->dev->my_bus);
+    cs4231_chip->input_dma_handle = 0;
+    cs4231_chip->input_dma_size = 0;
+    cs4231_chip->recording_count--;
+    status++;
+  }
+  if (cs4231_chip->input_next_dma_handle) {
+    cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle;
+    cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size;
+    cs4231_chip->input_next_dma_size = 0;
+    cs4231_chip->input_next_dma_handle = 0;
+  }
+
+  if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && 
+      !(cs4231_chip->perchip_info.record.pause)) {
+    cs4231_recclear(cs4231_chip->perchip_info.record.encoding, 
+                    (char *)cs4231_chip->input_ptr, cs4231_chip->input_size);
+    cs4231_chip->input_next_dma_handle = (u32*) (unsigned long)
+      mmu_get_scsi_one((char *) cs4231_chip->input_ptr, 
+                       cs4231_chip->input_size, drv->dev->my_bus);
+    cs4231_chip->regs->dmacnva = (u32) (unsigned long)
+      cs4231_chip->input_next_dma_handle;
+    cs4231_chip->input_next_dma_size = cs4231_chip->regs->dmacnc = 
+      cs4231_chip->input_size;
     cs4231_chip->input_size = 0;
-    sparcaudio_input_done(drv);
+    cs4231_chip->input_ptr = NULL;
+    cs4231_chip->recording_count++;
+    status += 2;
+  } else {
+    cs4231_chip->regs->dmacnva = 0;
+    cs4231_chip->regs->dmacnc = 0;
   }
+
+  sparcaudio_input_done(drv, status);
+
   return 1;
 }
 
@@ -1078,6 +1219,7 @@
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
+  tprintk(("in 4231 start output\n"));
   cs4231_chip->output_ptr = buffer;
   cs4231_chip->output_size = count;
 
@@ -1088,16 +1230,21 @@
   cs4231_ready(drv);
 
   cs4231_chip->perchip_info.play.active = 1;
-
   cs4231_chip->playing_count = 0;
-  cs4231_disable_play(drv);
-  cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY;
-  cs4231_chip->regs->dmacsr &= ~CS_PPAUSE;
-  cs4231_playintr(drv);
-  cs4231_enable_play(drv);
-  cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP;
 
-  cs4231_ready(drv);
+  if ((cs4231_chip->regs->dmacsr & CS_PPAUSE) || 
+      !(cs4231_chip->regs->dmacsr & PDMA_READY)) {
+    cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY;
+    cs4231_chip->regs->dmacsr &= ~CS_PPAUSE;
+    
+    cs4231_playintr(drv);
+
+    cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP;
+    cs4231_enable_play(drv);
+
+    cs4231_ready(drv);
+  } else 
+    cs4231_playintr(drv);
 }
 
 static void cs4231_stop_output(struct sparcaudio_driver *drv)
@@ -1108,17 +1255,17 @@
   cs4231_chip->output_ptr = NULL;
   cs4231_chip->output_size = 0;
   if (cs4231_chip->output_dma_handle) {
-      mmu_release_scsi_one((char *)cs4231_chip->output_dma_handle,
-                           4096, drv->dev->my_bus);
-      cs4231_chip->output_dma_handle = 0;
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle),
+                         cs4231_chip->output_dma_size, drv->dev->my_bus);
+    cs4231_chip->output_dma_handle = 0;
+    cs4231_chip->output_dma_size = 0;
   }
   if (cs4231_chip->output_next_dma_handle) {
-      mmu_release_scsi_one((char *)cs4231_chip->output_next_dma_handle,
-                           4096, drv->dev->my_bus);
-      cs4231_chip->output_next_dma_handle = 0;
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle),
+                         cs4231_chip->output_next_dma_size, drv->dev->my_bus);
+    cs4231_chip->output_next_dma_handle = 0;
+    cs4231_chip->output_next_dma_size = 0;
   }
-  cs4231_chip->perchip_info.play.active = 0;
-  cs4231_chip->regs->dmacsr |= (CS_PPAUSE);
 }
 
 static void cs4231_pollinput(struct sparcaudio_driver *drv)
@@ -1137,6 +1284,9 @@
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
+  cs4231_chip->input_ptr = buffer;
+  cs4231_chip->input_size = count;
+
   if (cs4231_chip->perchip_info.record.active || 
       (cs4231_chip->perchip_info.record.pause))
     return;
@@ -1145,12 +1295,20 @@
 
   cs4231_chip->perchip_info.record.active = 1;
   cs4231_chip->recording_count = 0;
-  /* init dma foo here */
-  cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT;
-  cs4231_chip->regs->dmacsr &= ~CS_CPAUSE;
-  cs4231_recintr(drv);
-  cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP;
-  cs4231_enable_rec(drv);
+
+  if ((cs4231_chip->regs->dmacsr & CS_CPAUSE) || 
+      !(cs4231_chip->regs->dmacsr & CDMA_READY)) {
+    cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT;
+    cs4231_chip->regs->dmacsr &= ~CS_CPAUSE;
+
+    cs4231_recintr(drv);
+
+    cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP;
+    cs4231_enable_rec(drv);
+
+    cs4231_ready(drv);
+  } else
+    cs4231_recintr(drv);
 }
 
 static void cs4231_stop_input(struct sparcaudio_driver *drv)
@@ -1160,11 +1318,89 @@
   cs4231_chip->perchip_info.record.active = 0;
   cs4231_chip->regs->dmacsr |= (CS_CPAUSE);
 
+  cs4231_chip->input_ptr = NULL;
+  cs4231_chip->input_size = 0;
+  if (cs4231_chip->input_dma_handle) {
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle),
+                         cs4231_chip->input_dma_size, drv->dev->my_bus);
+    cs4231_chip->input_dma_handle = 0;
+    cs4231_chip->input_dma_size = 0;
+  }
+  if (cs4231_chip->input_next_dma_handle) {
+    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle),
+                         cs4231_chip->input_next_dma_size, drv->dev->my_bus);
+    cs4231_chip->input_next_dma_handle = 0;
+    cs4231_chip->input_next_dma_size = 0;
+  }
   cs4231_pollinput(drv);
+}
+
+static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+
+        cs4231_chip->perchip_info.play.pause = value;
+
+        if (!value)
+          sparcaudio_output_done(drv, 0);
+
+        return value;
+}
+
+static int cs4231_set_output_error(struct sparcaudio_driver *drv, int value)
+{
+  int i;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  
+  i = cs4231_chip->perchip_info.play.error;
+  cs4231_chip->perchip_info.play.error = value;
+  
+  return i;
+}
+
+static int cs4231_set_input_error(struct sparcaudio_driver *drv, int value)
+{
+  int i;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  
+  i = cs4231_chip->perchip_info.record.error;
+  cs4231_chip->perchip_info.record.error = value;
+  
+  return i;
+}
+
+static int cs4231_set_output_samples(struct sparcaudio_driver *drv, int value)
+{
+  int i;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  
+  i = cs4231_chip->perchip_info.play.samples;
+  cs4231_chip->perchip_info.play.samples = value;
+  
+  return i;
+}
+
+static int cs4231_set_input_samples(struct sparcaudio_driver *drv, int value)
+{
+  int i;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  
+  i = cs4231_chip->perchip_info.record.samples;
+  cs4231_chip->perchip_info.record.samples = value;
+  
+  return i;
+}
 
-  /* need adjust the end pointer, process the input, and clean up the dma */
+static int cs4231_set_input_pause(struct sparcaudio_driver *drv, int value)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
-  cs4231_disable_rec(drv);
+        cs4231_chip->perchip_info.record.pause = value;
+	
+        if (value)
+          cs4231_stop_input(drv);
+	
+        return value;
 }
 
 static void cs4231_audio_getdev(struct sparcaudio_driver *drv,
@@ -1185,7 +1421,7 @@
 
 static int cs4231_audio_getdev_sunos(struct sparcaudio_driver *drv)
 {
-        return AUDIO_DEV_CS4231;
+  return AUDIO_DEV_CS4231;
 }
 
 static void cs4231_loopback(struct sparcaudio_driver *drv, unsigned int value)
@@ -1237,9 +1473,9 @@
     if (dummy & CS_XINT_PNVA) {
       cs4231_chip->perchip_info.play.samples += 
 	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
-				     cs4231_chip->playlen);
+				     cs4231_chip->playlen); 
       cs4231_playintr(drv);
-    }
+    } 
     /* Any other conditions we need worry about? */
   }
 
@@ -1253,16 +1489,25 @@
     /* Any other conditions we need worry about? */
   }
 
-  if ((dummy & CS_XINT_CEMP) 
-      && (cs4231_chip->perchip_info.record.active == 0)) 
-    {
-        /* Fix me */
-        cs4231_chip->perchip_info.record.active = 0;
+  
+  if (dummy & CS_XINT_CEMP) {
+    if (cs4231_chip->perchip_info.record.active == 0) {
+      /* Fix me */
+      cs4231_chip->perchip_info.record.active = 0;
+      cs4231_chip->perchip_info.record.error = 1;
+      cs4231_recintr(drv);
     }
-  if ((dummy & CS_XINT_EMPT) && (cs4231_chip->perchip_info.play.active == 0)) {
-    cs4231_chip->regs->dmacsr |= (CS_PPAUSE);
-    cs4231_disable_play(drv);
-    
+  }
+
+  if (dummy & CS_XINT_EMPT) {
+    if (!cs4231_chip->output_next_dma_handle) {
+      cs4231_chip->regs->dmacsr |= (CS_PPAUSE);
+      cs4231_disable_play(drv);
+      cs4231_chip->perchip_info.play.error = 1;
+    }
+    cs4231_chip->perchip_info.play.active = 0;
+    cs4231_playintr(drv);
+
     cs4231_getsamplecount(drv, cs4231_chip->playlen, 0);
   }
 
@@ -1317,15 +1562,31 @@
 	cs4231_get_input_ports,
 	cs4231_output_muted,
 	cs4231_get_output_muted,
+	cs4231_set_output_pause,
+	cs4231_get_output_pause,
+	cs4231_set_input_pause,
+	cs4231_get_input_pause,
+	cs4231_set_output_samples,
+	cs4231_get_output_samples,
+	cs4231_set_input_samples,
+	cs4231_get_input_samples,
+	cs4231_set_output_error,
+	cs4231_get_output_error,
+	cs4231_set_input_error,
+	cs4231_get_input_error,
+        cs4231_get_formats,
 };
 
 /* Attach to an cs4231 chip given its PROM node. */
 static int cs4231_attach(struct sparcaudio_driver *drv, 
 			 struct linux_sbus_device *sdev)
 {
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+  struct linux_prom_irqs irq;
+#endif
+  struct linux_sbus *sbus = sdev->my_bus;
   struct cs4231_chip *cs4231_chip;
   int err;
-  struct linux_sbus *sbus = sdev->my_bus;
 
   /* Allocate our private information structure. */
   drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL);
@@ -1342,8 +1603,15 @@
   drv->dev = sdev;
 
   /* Map the registers into memory. */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+  prom_apply_sbus_ranges(sbus, &sdev->reg_addrs[0], 
+			 sdev->num_registers, sdev);
+#else
   prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
+#endif
+
   cs4231_chip->regs_size = sdev->reg_addrs[0].reg_size;
+
   cs4231_chip->regs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
 				     sdev->reg_addrs[0].reg_size, 
 				     "cs4231", sdev->reg_addrs[0].which_io, 
@@ -1356,9 +1624,23 @@
   }
 
   /* Attach the interrupt handler to the audio interrupt. */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+  prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq));
+
+  if (irq.pri < 0) {
+    sparc_free_io(cs4231_chip->regs, cs4231_chip->regs_size);
+    kfree(drv->private);
+    return -EIO;
+  }
+
+  cs4231_chip->irq = irq.pri;
+
+#else
   cs4231_chip->irq = sdev->irqs[0];
+#endif
 
   request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
+
   enable_irq(cs4231_chip->irq);
 
   cs4231_enable_interrupts(drv);
@@ -1367,7 +1649,7 @@
   cs4231_chip_reset(drv);
 
   /* Register ourselves with the midlevel audio driver. */
-  err = register_sparcaudio_driver(drv);
+  err = register_sparcaudio_driver(drv, 1);
 
   if (err < 0) {
     printk(KERN_ERR "cs4231: unable to register\n");
@@ -1395,8 +1677,8 @@
 						  AUDIO_ANALOG_LOOPBACK);
 
   /* Announce the hardware to the user. */
-  printk(KERN_INFO "cs4231%c at 0x%lx irq %d\n",
-	 (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
+  printk(KERN_INFO "audio%d: cs4231%c at 0x%lx irq %d\n",
+         drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
 	 (unsigned long)cs4231_chip->regs, cs4231_chip->irq);
   
   /* Success! */
@@ -1438,7 +1720,7 @@
         struct cs4231_chip *info = (struct cs4231_chip *)drv->private;
 
 	cs4231_disable_interrupts(drv);
-        unregister_sparcaudio_driver(drv);
+        unregister_sparcaudio_driver(drv, 1);
         disable_irq(info->irq);
         free_irq(info->irq, drv);
         sparc_free_io(info->regs, info->regs_size);
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h
--- v2.1.128/linux/drivers/sbus/audio/cs4231.h	Thu Aug  6 14:06:32 1998
+++ linux/drivers/sbus/audio/cs4231.h	Wed Nov 18 09:06:05 1998
@@ -48,11 +48,14 @@
   /* Current buffer that the driver is playing. */
   volatile __u8 * output_ptr;
   volatile unsigned long output_size;
-  volatile __u32 * output_dma_handle, output_next_dma_handle;
+  volatile __u32 * output_dma_handle, * output_next_dma_handle;
+  volatile unsigned long output_dma_size, output_next_dma_size;
 
   /* Current record buffer. */
   volatile __u8 * input_ptr;
   volatile unsigned long input_size;
+  volatile __u32 * input_dma_handle, * input_next_dma_handle;
+  volatile unsigned long input_dma_size, input_next_dma_size;
 
   /* Number of buffers in the pipe. */
   volatile unsigned long playing_count;
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- v2.1.128/linux/drivers/sbus/audio/dbri.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/dbri.c	Wed Nov 18 09:06:05 1998
@@ -51,6 +51,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/version.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
@@ -62,9 +63,13 @@
 #include <asm/audioio.h>
 #include "dbri.h"
 
+#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+#include "../../isdn/hisax/hisax.h"
+#include "../../isdn/hisax/isdnl1.h"
+#include "../../isdn/hisax/foreign.h"
+#endif
 
-
-#define DBRI_DEBUG
+/* #define DBRI_DEBUG */
 
 #ifdef DBRI_DEBUG
 
@@ -104,34 +109,58 @@
 static struct sparcaudio_driver drivers[MAX_DRIVERS];
 static char drv_name[] = "DBRI/audio";
 static int num_drivers;
-static int dbri_cmdlocked = 0;
 
 static void * output_callback_arg;
 
 /*
- * Make sure, that we can send a command to the dbri
+ * Commands are sent to the DBRI by building a list of them in memory,
+ * then writing the address of the first list item to DBRI register 8.
+ * The list is terminated with a WAIT command, which can generate a
+ * CPU interrupt if required.
+ *
+ * Since the DBRI can run asynchronously to the CPU, several means of
+ * synchronization present themselves.  The original scheme (Rudolf's)
+ * was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
+ * an interrupt signaled completion, and wait on a wait_queue if a routine
+ * attempted to cmdlock while the flag was set.  The problems arose when
+ * we tried to cmdlock from inside an interrupt handler, which might
+ * cause scheduling in an interrupt (if we waited), etc, etc
+ *
+ * A more sophisticated scheme might involve a circular command buffer
+ * or an array of command buffers.  A routine could fill one with
+ * commands and link it onto a list.  When a interrupt signaled
+ * completion of the current command buffer, look on the list for
+ * the next one.
+ *
+ * I've decided to implement something much simpler - after each command,
+ * the CPU waits for the DBRI to finish the command by polling the P bit
+ * in DBRI register 0.  I've tried to implement this in such a way
+ * that might make implementing a more sophisticated scheme easier.
+ *
+ * Every time a routine wants to write commands to the DBRI, it
+ * must first call dbri_cmdlock() and get an initial index into dbri->cmd
+ * (currently always 0) in return.  After the commands have been
+ * write (index incremented after each one), dbri_cmdsend() is called
+ * with the final index value.
  */
+
 static int dbri_cmdlock(struct dbri *dbri)
 {
-	unsigned long flags;
-	int was_sleeping = 0;
+       return 0;
+}
 
-	save_flags(flags);
-	cli();
+static void dbri_cmdsend(struct dbri *dbri, int n)
+{
+        int maxloops = 1000000;
 
-	if(dbri_cmdlocked) {
-		interruptible_sleep_on(&dbri->wait);
-		was_sleeping = 1;
-	}
-	if(dbri_cmdlocked)
-		return -EINTR;
-	dbri_cmdlocked = 1;
+        dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
+        dbri->regs->reg8 = (int)dbri->cmd;
 
-	restore_flags(flags);
+        while (maxloops > 0 && (dbri->regs->reg0 & D_P));
 
-	if(was_sleeping)
-		dprintk(D_INT, ("DBRI: Just woke up\n"));
-	return 0;
+        if (maxloops == 0) {
+                printk("DBRI: Maxloops exceeded in dbri_cmdsend\n");
+        }
 }
 
 static void dbri_reset(struct sparcaudio_driver *drv)
@@ -153,7 +182,7 @@
         struct dbri *info = (struct dbri *)drv->private;
 
 	dbri_reset(drv);
-        unregister_sparcaudio_driver(drv);
+        unregister_sparcaudio_driver(drv, 1);
         free_irq(info->irq, drv);
         sparc_free_io(info->regs, info->regs_size);
         kfree(drv->private);
@@ -191,13 +220,12 @@
 	/*
 	 * Set up the interrupt queue
 	 */
-	(void)dbri_cmdlock(dbri);
+	n = dbri_cmdlock(dbri);
 
-	n = 0;
 	dbri->cmd[n++] = DBRI_CMD(D_IIQ, 0, 0);
 	dbri->cmd[n++] = (int)(dbri->intr);
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
-	dbri->regs->reg8 = (int)dbri->cmd;
+
+        dbri_cmdsend(dbri, n);
 }
 
 
@@ -250,9 +278,9 @@
 
 static void mmcodec_init_data(struct dbri *dbri)
 {
-	int val, n = 0;
+	int val, n;
 
-	dbri_cmdlock(dbri);
+	n = dbri_cmdlock(dbri);
 
 	/*
 	 * Data mode:
@@ -340,9 +368,7 @@
         /* CHI: Slave mode; enable interrupts */
 	dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN);
 
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
-
-	dbri->regs->reg8 = (int)dbri->cmd;
+        dbri_cmdsend(dbri, n);
 }
 
 
@@ -351,7 +377,7 @@
  */
 static void mmcodec_setctrl(struct dbri *dbri)
 {
-	int n = 0, val;
+	int n, val;
 
 	/*
 	 * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
@@ -380,7 +406,7 @@
          * by eight clock cycles.  Anybody know why?
          */
 
-	dbri_cmdlock(dbri);
+	n = dbri_cmdlock(dbri);
 
 	/*
 	 * Control mode:
@@ -462,32 +488,24 @@
 	dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
 	dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
 
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
-	dbri->regs->reg8 = (int)dbri->cmd;
-
-
-	/* Wait for the data from the CS4215 */
-        interruptible_sleep_on(&dbri->int_wait);
+        /* Wait for the command to complete */
+        dbri_cmdsend(dbri, n);
 
         /* Switch CS4215 to data mode - data sheet says
          * "Set CLB=1 and send two more frames of valid control info"
          */
-	dbri_cmdlock(dbri);
+	n = dbri_cmdlock(dbri);
 
-        n = 0;
 	dbri->mm.ctrl[0] |= CS4215_CLB;
 	dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
 	dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4);
 
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
-	dbri->regs->reg8 = (int)dbri->cmd;
-
-        dbri_cmdlock(dbri);
+        dbri_cmdsend(dbri, n);
 
         /* Two frames of control info @ 8kHz frame rate = 250 us delay */
         udelay(250);
 
-	n = 0;
+        n = dbri_cmdlock(dbri);
 
 	/* Now switch back to data mode */
 	/* Reset CHI Anchor: Stop Send/Receive */
@@ -504,15 +522,8 @@
 	dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0x16);
 
 
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
-	dbri->regs->reg8 = (int)dbri->cmd;
-
         /* Wait for command to complete */
-        dbri_cmdlock(dbri);
-        n = 0;
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
-	dbri->regs->reg8 = (int)dbri->cmd;
-
+        dbri_cmdsend(dbri, n);
 
         /* Switch CS4215 to data mode - set PIO3 to 1 */
 	dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
@@ -563,6 +574,94 @@
 	return 0;
 }
 
+void dbri_isdn_init(struct dbri *dbri)
+{
+        int n, val;
+
+        /* Pipe  0: Receive D channel
+         * Pipe  8: Receive B1 channel
+         * Pipe  9: Receive B2 channel
+         * Pipe  1: Transmit D channel
+         * Pipe 10: Transmit B1 channel
+         * Pipe 11: Transmit B2 channel
+         */
+
+        n = dbri_cmdlock(dbri);
+
+       /* Pipe 0: SDP */
+       val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+       /* Pipe 8: SDP */
+       val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+       /* Pipe 9: SDP */
+       val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_9);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+       /* Pipe 1: SDP */
+       val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+       /* Pipe 10: SDP */
+       val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+       /* Pipe 11: SDP */
+       val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_11);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = 0;
+
+
+       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+
+        /* Pipe 0: DTS */
+       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_0);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_0);
+       dbri->cmd[n++] = 0;
+
+        /* Pipe 8: DTS */
+       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_8);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_0);
+       dbri->cmd[n++] = 0;
+
+        /* Pipe 9: DTS */
+       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_8) | D_PIPE(D_P_9);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_0);
+       dbri->cmd[n++] = 0;
+
+        /* Pipe 1: DTS */
+       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_1);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = 0;
+       dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_1);
+
+        /* Pipe 10: DTS */
+       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_10);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = 0;
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_1);
+
+        /* Pipe 11: DTS */
+       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_10) | D_PIPE(D_P_11);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = 0;
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_1);
+
+
+        /* Wait for command to complete */
+       dbri_cmdsend(dbri, n);
+}
+
 void dbri_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id;
@@ -610,8 +709,16 @@
 
 		val = D_INTR_GETVAL(x);
 
+                if (D_INTR_GETCODE(x) == D_INTR_SBRI) {
+                        int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
+                        dbri->liu_state = liu_states[val & 0x7];
+                        if (dbri->liu_callback)
+                                dbri->liu_callback(dbri->liu_callback_arg);
+                }
+
 		switch(D_INTR_GETCHAN(x)) {
 			case D_INTR_CMD:
+#if 0
 				if(D_INTR_GETCMD(x) == D_WAIT)
 					if(val == WAIT_INTR1) {
 						dbri_cmdlocked = 0;
@@ -619,25 +726,86 @@
 					}
 					if(val == WAIT_INTR2)
 						wake_up(&dbri->int_wait);
+#endif
 				break;
+
+                        case D_P_0:
+                                /* Pipe 0 - D channel receive */
+                                if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
+                                    dbri->D.input_callback) {
+                                        dbri->D.input_callback(dbri->D.input_callback_arg,
+                                                               DBRI_RD_STATUS(dbri->D.rd.flags),
+                                                               DBRI_RD_CNT(dbri->D.rd.flags)-2);
+                                }
+                                break;
+
+                        case D_P_1:
+                                /* Pipe 1 - D channel transmit */
+                                if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
+                                    dbri->D.output_callback) {
+                                        dbri->D.output_callback(dbri->D.output_callback_arg,
+                                                                DBRI_TD_STATUS(dbri->D.rd.flags)&0xe);
+                                }
+                                break;
+
 			case D_P_4:
+                                /* Pipe 4 - audio transmit */
 				if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
 					sparcaudio_output_done(output_callback_arg, 1);
 				}
 				break;
 
+                        case D_P_8:
+                                /* Pipe 8 - B1 channel receive */
+                                if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
+                                    dbri->B[0].input_callback) {
+                                        dbri->B[0].input_callback(dbri->B[0].input_callback_arg,
+                                                                  DBRI_RD_STATUS(dbri->B[0].rd.flags),
+                                                                  DBRI_RD_CNT(dbri->B[0].rd.flags)-2);
+                                }
+                                break;
+
+                        case D_P_9:
+                                /* Pipe 9 - B2 channel receive */
+                                if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
+                                    dbri->B[1].input_callback) {
+                                        dbri->B[1].input_callback(dbri->B[1].input_callback_arg,
+                                                                DBRI_RD_STATUS(dbri->B[1].rd.flags),
+                                                                DBRI_RD_CNT(dbri->B[1].rd.flags)-2);
+                                }
+                                break;
+
+                        case D_P_10:
+                                /* Pipe 10 - B1 channel transmit */
+                                if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
+                                    dbri->B[0].output_callback) {
+                                        dbri->B[0].output_callback(dbri->B[0].output_callback_arg,
+                                                                   DBRI_TD_STATUS(dbri->B[0].rd.flags)&0xfe);
+                                }
+                                break;
+
+                        case D_P_11:
+                                /* Pipe 11 - B2 channel transmit */
+                                if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
+                                    dbri->B[1].output_callback) {
+                                        dbri->B[1].output_callback(dbri->B[1].output_callback_arg,
+                                                                   DBRI_TD_STATUS(dbri->B[1].rd.flags)&0xfe);
+                                }
+                                break;
+
 			case D_P_18:
+                                /* Pipe 18 - receive CS4215 status */
 				if(val != 0) {
 					x = reverse_bytes(val,2)&CS4215_12_MASK;
-printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl);
-					if(x == (*(int *)dbri->mm.ctrl >> 16))
-{
-printk("Comp ok\n");
-						wake_up(&dbri->int_wait);
-}
+                                        printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl);
+					if(x == (*(int *)dbri->mm.ctrl >> 16)) {
+                                          printk("Comp ok\n");
+                                          wake_up(&dbri->int_wait);
+                                        }
 				}
 				break;
 			case D_P_19:
+                                /* Pipe 19 - receive CS4215 version */
 				if(val != 0) {
 					dbri->mm.version = 
 						reverse_bytes(val, 1) & 0xf;
@@ -671,13 +839,6 @@
 {
 	struct dbri *dbri = (struct dbri *)drv->private;
 
-#if 0
-	/* Set the default audio parameters. */
-	info->rgain = 128;
-	info->pgain = 200;
-	info->mgain = 0;
-#endif
-
 	MOD_INC_USE_COUNT;
 
 	return 0;
@@ -693,17 +854,14 @@
                               __u8 * buffer, unsigned long count)
 {
 	struct dbri *dbri = (struct dbri *)drv->private;
-        int val, n = 0;
+        int val, n;
 
-        /* XXX - This routine can be called via interrupt.  If DBRI
-         * was cmdlocked, that would cause a sleep, which would be
-         * scheduling in an interrupt, and that's not allowed
-         *
-         * Fortunately, there's nothing else talking to our DBRI (yet),
-         * so this isn't a problem (yet)
-         */
+        if (count > (1 << 14) - 1) {
+                printk("dbri_start_output called with count=%d; truncated", count);
+                count = (1 << 14) - 1;
+        }
 
-        dbri_cmdlock(dbri);
+        n = dbri_cmdlock(dbri);
 
         dbri->mm.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_D | DBRI_TD_CNT(count);
         dbri->mm.td.ba = (__u32) buffer;
@@ -715,11 +873,9 @@
 	dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
 	dbri->cmd[n++] = (__u32)&dbri->mm.td;
 
-	dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
-
-	dbri->regs->reg8 = (int)dbri->cmd;
-
         output_callback_arg = drv;
+
+        dbri_cmdsend(dbri, n);
 }
 
 static void dbri_stop_output(struct sparcaudio_driver *drv)
@@ -727,6 +883,8 @@
 	struct dbri *dbri = (struct dbri *)drv->private;
 }
 
+
+
 static struct sparcaudio_operations dbri_ops = {
 	dbri_open,
 	dbri_release,
@@ -773,6 +931,340 @@
 	dummy, /* dbri_get_output_muted, */
 };
 
+/*
+****************************************************************************
+************************** ISDN (Hisax) Interface **************************
+****************************************************************************
+*/
+
+int dbri_get_irqnum(int dev)
+{
+       struct dbri *dbri;
+
+       if (dev > num_drivers) {
+               return(0);
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        /* On the sparc, the cpu's irq number is only part of the "irq" */
+       return (dbri->irq & NR_IRQS);
+}
+
+int dbri_get_liu_state(int dev)
+{
+       struct dbri *dbri;
+
+       if (dev > num_drivers) {
+               return(0);
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+       return dbri->liu_state;
+}
+
+void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg)
+{
+       struct dbri *dbri;
+
+       if (dev > num_drivers) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+       /* Set callback for LIU state change */
+        dbri->liu_callback = callback;
+       dbri->liu_callback_arg = callback_arg;
+
+        dbri_isdn_init(dbri);
+}
+
+void dbri_liu_activate(int dev, int priority)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        n = dbri_cmdlock(dbri);
+
+        /* Turn on the ISDN TE interface and request activation */
+        val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
+        dbri->cmd[n++] = DBRI_CMD(D_TE, 0, val);
+
+       dbri_cmdsend(dbri, n);
+
+        /* Activate the interface */
+        dbri->regs->reg0 |= D_T;
+}
+
+void dbri_liu_deactivate(int dev)
+{
+       struct dbri *dbri;
+
+       if (dev > num_drivers) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        /* Turn off the ISDN TE interface */
+        dbri->regs->reg0 &= ~D_T;
+}
+
+void dbri_dxmit(int dev, __u8 *buffer, unsigned int count,
+                       void (*callback)(void *, int), void *callback_arg)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        if (count > (1 << 14) - 1) {
+                printk("dbri_dxmit called with count=%d; truncated", count);
+                count = (1 << 14) - 1;
+        }
+
+        n = dbri_cmdlock(dbri);
+
+        /* XXX - Shouldn't I check to make sure D.td isn't is use? */
+
+        dbri->D.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count) | DBRI_TD_I;
+        dbri->D.td.ba = (__u32) buffer;
+        dbri->D.td.nda = 0;
+        dbri->D.td.status = 0;
+
+        /* Pipe 1 is D channel transmit */
+       val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = (__u32)&dbri->D.td;
+
+        dbri->D.output_callback = callback;
+        dbri->D.output_callback_arg = callback_arg;
+
+       dbri_cmdsend(dbri, n);
+}
+
+void dbri_drecv(int dev, __u8 *buffer, unsigned int size,
+                       void (*callback)(void *, int, unsigned int),
+                       void *callback_arg)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        if (size > (1 << 14) - 1) {
+                printk("dbri_drecv called with size=%d; truncated", size);
+                size = (1 << 14) - 1;
+        }
+
+        /* Make sure size is a multiple of four */
+        size &= ~3;
+
+        n = dbri_cmdlock(dbri);
+
+        /* XXX - Shouldn't I check to make sure D.rd isn't is use? */
+
+        dbri->D.rd.flags = 0;
+        dbri->D.rd.ba = (__u32) buffer;
+        dbri->D.rd.nda = 0;
+        dbri->D.rd.status = DBRI_RD_B | DBRI_RD_BCNT(size);
+
+        /* Pipe 0 is D channel receive */
+       val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = (__u32)&dbri->D.rd;
+
+       dbri_cmdsend(dbri, n);
+
+        dbri->D.input_callback = callback;
+        dbri->D.input_callback_arg = callback_arg;
+}
+
+int dbri_bopen(int dev, unsigned int chan,
+               int hdlcmode, u_char xmit_idle_char)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers || chan > 1) {
+               return -1;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        if (hdlcmode) {
+
+                return -1;
+
+                /* Pipe 8/9: receive B1/B2 channel */
+                dbri->B[chan].recvSDP = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan);
+
+                /* Pipe 10/11: transmit B1/B2 channel */
+                dbri->B[chan].xmitSDP = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan);
+
+        } else {        /* !hdlcmode means transparent */
+
+                /* Pipe 8/9: receive B1/B2 channel */
+                dbri->B[chan].recvSDP = D_SDP_MEM|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan);
+
+                /* Pipe 10/11: transmit B1/B2 channel */
+                dbri->B[chan].xmitSDP = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan);
+
+        }
+
+        n = dbri_cmdlock(dbri);
+
+        /* Pipe 8/9: receive B1/B2 channel */
+        val = dbri->B[chan].recvSDP | D_SDP_C;
+        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+        dbri->cmd[n++] = 0;
+
+        /* Pipe 10/11: transmit B1/B2 channel */
+        val = dbri->B[chan].xmitSDP | D_SDP_C;
+        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+        dbri->cmd[n++] = 0;
+
+        dbri->B[chan].output_callback = NULL;
+        dbri->B[chan].input_callback = NULL;
+
+       dbri_cmdsend(dbri, n);
+
+        return 0;
+}
+
+void dbri_bclose(int dev, unsigned int chan)
+{
+       struct dbri *dbri;
+
+       if (dev > num_drivers || chan > 1) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        dbri->B[chan].output_callback = NULL;
+        dbri->B[chan].input_callback = NULL;
+}
+
+void dbri_bxmit(int dev, unsigned int chan,
+                       __u8 *buffer, unsigned long count,
+                       void (*callback)(void *, int),
+                       void *callback_arg)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers || chan > 1) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        if (count > (1 << 14) - 1) {
+                printk("dbri_bxmit called with count=%ld; truncated", count);
+                count = (1 << 14) - 1;
+        }
+
+        n = dbri_cmdlock(dbri);
+
+        /* XXX - Shouldn't I check to make sure td isn't is use? */
+
+        dbri->B[chan].td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count);
+        dbri->B[chan].td.ba = (__u32) buffer;
+        dbri->B[chan].td.nda = 0;
+        dbri->B[chan].td.status = 0;
+
+        /* Pipe 10/11 is B1/B2 channel transmit */
+       val = dbri->B[chan].xmitSDP;
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = (__u32)&dbri->B[chan].td;
+
+        dbri->B[chan].output_callback = callback;
+        dbri->B[chan].output_callback_arg = callback_arg;
+
+       dbri_cmdsend(dbri, n);
+}
+
+void dbri_brecv(int dev, unsigned int chan,
+                       __u8 *buffer, unsigned long size,
+                       void (*callback)(void *, int, unsigned int),
+                       void *callback_arg)
+{
+       struct dbri *dbri;
+        int n, val;
+
+       if (dev > num_drivers || chan > 1) {
+               return;
+       }
+
+       dbri = (struct dbri *) drivers[dev].private;
+
+        if (size > (1 << 14) - 1) {
+                printk("dbri_brecv called with size=%ld; truncated", size);
+                size = (1 << 14) - 1;
+        }
+
+        /* Make sure size is a multiple of four */
+        size &= ~3;
+
+        n = dbri_cmdlock(dbri);
+
+        /* XXX - Shouldn't I check to make sure RD isn't is use? */
+
+        dbri->B[chan].rd.flags = 0;
+        dbri->B[chan].rd.ba = (__u32) buffer;
+        dbri->B[chan].rd.nda = 0;
+        dbri->B[chan].rd.status = DBRI_RD_B | DBRI_RD_BCNT(size);
+
+        /* Pipe 8/9 is B1/B2 channel receive */
+       val = dbri->B[chan].recvSDP;
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = (__u32)&dbri->B[chan].rd;
+
+       dbri_cmdsend(dbri, n);
+
+        dbri->B[chan].input_callback = callback;
+        dbri->B[chan].input_callback_arg = callback_arg;
+}
+
+#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
+struct foreign_interface dbri_foreign_interface = {
+        dbri_get_irqnum,
+        dbri_get_liu_state,
+        dbri_liu_init,
+        dbri_liu_activate,
+        dbri_liu_deactivate,
+        dbri_dxmit,
+        dbri_drecv,
+        dbri_bopen,
+        dbri_bclose,
+        dbri_bxmit,
+        dbri_brecv
+};
+EXPORT_SYMBOL(dbri_foreign_interface);
+#endif
+
+/*
+****************************************************************************
+**************************** Initialization ********************************
+****************************************************************************
+*/
 
 static int dbri_attach(struct sparcaudio_driver *drv, 
 			 struct linux_sbus_device *sdev)
@@ -822,7 +1314,7 @@
 	}
 
 	/* Register ourselves with the midlevel audio driver. */
-	err = register_sparcaudio_driver(drv);
+	err = register_sparcaudio_driver(drv,1);
 	if (err) {
 		printk(KERN_ERR "DBRI: unable to register audio\n");
 		free_irq(dbri->irq, drv);
@@ -900,13 +1392,13 @@
  * adjust the settings for this buffer only.  This must remain at the end
  * of the file.
  * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
+ * Local Variables:
+ * c-indent-level: 8
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
  * c-continued-brace-offset: 0
  * indent-tabs-mode: nil
  * tab-width: 8
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/audio/dbri.h linux/drivers/sbus/audio/dbri.h
--- v2.1.128/linux/drivers/sbus/audio/dbri.h	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/audio/dbri.h	Wed Nov 18 09:06:05 1998
@@ -33,6 +33,17 @@
 	__u32	status;
 };
 
+struct dbri_channel {
+        struct dbri_mem td;
+        struct dbri_mem rd;
+        unsigned int recvSDP;
+        unsigned int xmitSDP;
+        void (*output_callback)(void *, int);
+        void *output_callback_arg;
+        void (*input_callback)(void *, int, unsigned int);
+        void *input_callback_arg;
+};
+
 #include "cs4215.h"
 
 /* This structure holds the information for both chips (DBRI & CS4215) */
@@ -49,6 +60,15 @@
  
   struct wait_queue *wait, *int_wait;		/* Where to sleep if busy */
   struct audio_info perchip_info;
+
+  /* Track ISDN LIU and notify changes */
+  int liu_state;
+  void (*liu_callback)(void *);
+  void *liu_callback_arg;
+
+  /* Callback routines and descriptors for ISDN channels */
+  struct dbri_channel D;
+  struct dbri_channel B[2];
 };
 
 
@@ -109,7 +129,7 @@
 
 
 /* Special bits for some commands */
-#define D_PIPE(v)	(v<<0)	/* Pipe Nr: 0-15 long, 16-21 short */
+#define D_PIPE(v)      ((v)<<0)        /* Pipe Nr: 0-15 long, 16-21 short */
 
 /* Setup Data Pipe */
 /* IRM */
@@ -139,8 +159,8 @@
 #define D_DTS_VO	(1<<16) /* Valid Output Time-Slot Descriptor */
 #define D_DTS_INS	(1<<15) /* Insert Time Slot */
 #define D_DTS_DEL	(0<<15) /* Delete Time Slot */
-#define D_DTS_PRVIN(v)	(v<<10) /* Previous In Pipe */
-#define D_DTS_PRVOUT(v)	(v<<5)  /* Previous Out Pipe */
+#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */
+#define D_DTS_PRVOUT(v)        ((v)<<5)  /* Previous Out Pipe */
 
 /* Time Slot defines */
 #define D_TS_LEN(v)	(v<<24)	/* Number of bits in this time slot */
@@ -150,8 +170,8 @@
 #define D_TS_MONITOR	(2<<10)	/* Monitor pipe */
 #define D_TS_NONCONTIG	(3<<10) /* Non contiguous mode */
 #define D_TS_ANCHOR	(7<<10) /* Starting short pipes */
-#define D_TS_MON(v)	(v<<5)	/* Monitor Pipe */
-#define D_TS_NEXT(v)	(v<<0)	/* Pipe Nr: 0-15 long, 16-21 short */
+#define D_TS_MON(v)    ((v)<<5)        /* Monitor Pipe */
+#define D_TS_NEXT(v)   ((v)<<0)        /* Pipe Nr: 0-15 long, 16-21 short */
 
 /* Concentration Highway Interface Modes */
 #define D_CHI_CHICM(v)	(v<<16)	/* Clock mode */
@@ -276,17 +296,19 @@
 #define DBRI_TD_UNR	(1<<3)	/* Underrun: transmitter is out of data */
 #define DBRI_TD_ABT	(1<<2)	/* Abort: frame aborted */
 #define DBRI_TD_TBC	(1<<0)	/* Transmit buffer Complete */
+#define DBRI_TD_STATUS(v)       ((v)&0xff)      /* Transmit status */
 
 /* Receive descriptor defines */
 #define DBRI_RD_F	(1<<31)	/* End of Frame */
 #define DBRI_RD_C	(1<<30)	/* Completed buffer */
 #define DBRI_RD_B	(1<<15)	/* Final interrupt */
 #define DBRI_RD_M	(1<<14)	/* Marker interrupt */
-#define DBRI_RD_CNT(v)	(v<<16)	/* Number of valid bytes in the buffer */
 #define DBRI_RD_BCNT(v)	v	/* Buffer size */
 #define DBRI_RD_CRC	(1<<7)	/* 0: CRC is correct */
 #define DBRI_RD_BBC	(1<<6)	/* 1: Bad Byte recieved */
 #define DBRI_RD_ABT	(1<<5)	/* Abort: frame aborted */
 #define DBRI_RD_OVRN	(1<<3)	/* Overrun: data lost */
+#define DBRI_RD_STATUS(v)      ((v)&0xff)      /* Receive status */
+#define DBRI_RD_CNT(v) ((v>>16)&0x1fff)        /* Number of valid bytes in the buffer */
 
 #endif /* _DBRI_H_ */
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.1.128/linux/drivers/sbus/char/Makefile	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/Makefile	Mon Nov 16 10:37:28 1998
@@ -50,7 +50,7 @@
 else # !eq($(ARCH),sparc64)
 
 ifeq ($(CONFIG_PCI),y)
-O_OBJS += su32.o pcikbd.o
+O_OBJS += su.o pcikbd.o
 endif
 
 endif # !eq($(ARCH),sparc64)
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- v2.1.128/linux/drivers/sbus/char/envctrl.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/envctrl.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.8 1998/08/26 10:29:40 davem Exp $
+/* $Id: envctrl.c,v 1.9 1998/11/06 07:38:20 ecd Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -115,10 +115,7 @@
 	unsigned char dummy;
 	unsigned char stat;
 	int error = -ENODEV;
-	int count = -1;
-
-	if (len == 0)
-		return 0;
+	int count = 0;
 
 	i2c->data = (dev << 1) | I2C_READ;
 
@@ -134,21 +131,26 @@
 
 		if (stat & STATUS_LRB)
 			goto stop;
+
 		error = 0;
-		if (count == (len - 2))
-			goto final;
+		if (len == 0) {
+			count--;
+			break;
+		}
 
-		if (++count > 0) {
+		if (count == (len - 1))
+			break;
+
+		if (count++ > 0) {
 			error = PUT_DATA(&i2c->data, buffer++, user);
 			if (error)
-				goto final;
+				break;
 		} else
 			dummy = i2c->data;
 	} while (1);
 
-final:
 	i2c->csr = CONTROL_ES0;
-	if (!error && (++count > 0))
+	if (!error && (count++ > 0))
 		error = PUT_DATA(&i2c->data, buffer++, user);
 	else
 		dummy = i2c->data;
@@ -159,14 +161,14 @@
 
 stop:
 	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
-	if (!error && (++count > 0))
+	if (!error && (count++ > 0))
 		error = PUT_DATA(&i2c->data, buffer++, user);
 	else
 		dummy = i2c->data;
 
 	if (error)
 		return error;
-	return count;
+	return count - 1;
 }
 
 static int
@@ -189,19 +191,19 @@
 			udelay(1);
 
 		if (stat & STATUS_LRB)
-			goto stop;
+			break;
+
 		error = count;
 		if (count == len)
-			goto stop;
+			break;
 
 		error = GET_DATA(&i2c->data, buffer++, user);
 		if (error)
-			goto stop;
+			break;
 
 		count++;
 	} while (1);
 
-stop:
 	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
 	return error;
 }
@@ -212,7 +214,7 @@
 	int count = 0;
 
 	for (dev = 1; dev < 128; dev++) {
-		if (i2c_write(dev, 0, 0, 0) == 0) {
+		if (i2c_read(dev, 0, 0, 0) == 0) {
 #ifdef DEBUG_BUS_SCAN
 			int i;
 			for (i = 0; i < NR_DEVMAP; i++)
@@ -224,7 +226,11 @@
 			count++;
 		}
 	}
-	return count ? 0 : -ENODEV;
+	if (!count) {
+		printk("%s: no devices found\n", __FUNCTION__);
+		return -ENODEV;
+	}
+	return 0;
 }
 
 static loff_t
@@ -317,6 +323,7 @@
 #ifdef CONFIG_PCI
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev = 0;
+	int err;
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
@@ -327,8 +334,10 @@
 		}
 	}
 ebus_done:
-	if (!edev)
+	if (!edev) {
+		printk("%s: ebus device not found\n", __FUNCTION__);
 		return -ENODEV;
+	}
 
 	if (check_region(edev->base_address[0], sizeof(*i2c))) {
 		printk("%s: Can't get region %lx, %d\n",
@@ -353,7 +362,10 @@
 		release_region((unsigned long)i2c, sizeof(*i2c));
 	}
 
-	return i2c_scan_bus();
+	err = i2c_scan_bus();
+	if (err)
+		release_region((unsigned long)i2c, sizeof(*i2c));
+	return err;
 #else
 	return -ENODEV;
 #endif
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.1.128/linux/drivers/sbus/char/pcikbd.c	Sun Nov  8 14:03:01 1998
+++ linux/drivers/sbus/char/pcikbd.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $
+/* $Id: pcikbd.c,v 1.24 1998/11/08 11:15:24 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -691,7 +691,7 @@
 		    == AUX_STAT_OBF)
 			pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
 		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout((5*HZ + 99)/100);
+		schedule_timeout((5*HZ + 99) / 100);
 		retries++;
 	}
 	return (retries < MAX_RETRIES);
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.1.128/linux/drivers/sbus/char/sab82532.c	Sun Nov  8 14:03:01 1998
+++ linux/drivers/sbus/char/sab82532.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $
+/* $Id: sab82532.c,v 1.27 1998/11/08 11:15:25 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2136,7 +2136,7 @@
 
 __initfunc(static inline void show_serial_version(void))
 {
-	char *revision = "$Revision: 1.26 $";
+	char *revision = "$Revision: 1.27 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.1.128/linux/drivers/sbus/char/su.c	Sun Nov  8 14:03:01 1998
+++ linux/drivers/sbus/char/su.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $
+/* $Id: su.c,v 1.16 1998/11/14 23:02:54 ecd Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -37,7 +37,7 @@
 	printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n",		\
 	       kdevname(tty->device), (info->flags), serial_refcount,	\
 	       info->count,tty->count,s);				\
-} while (0);
+} while (0)
 #else
 #define DBG_CNT(s)
 #endif
@@ -146,7 +146,7 @@
 };
 
 static char *serial_name = "PCIO serial driver";
-static char *serial_version = "1.1";
+static char serial_version[16];
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
@@ -251,10 +251,10 @@
 	/*
 	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
 	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
-	 * gate gives logical one. Since we use level triggered interrupts
+	 * gate outputs a logical one. Since we use level triggered interrupts
 	 * we have lockup and watchdog reset. We cannot mask IRQ because
-	 * keyboard shares IRQ with us (Bob Smelik: I would not hire you).
-	 * P3: Assure that OUT2 never goes down.
+	 * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
+	 * This problem is similar to what Alpha people suffer, see serial.c.
 	 */
 	if (offset == UART_MCR) value |= UART_MCR_OUT2;
 	*(volatile unsigned char *)(info->port + offset) = value;
@@ -386,14 +386,13 @@
 	icount = &info->icount;
 	do {
 		ch = serial_inp(info, UART_RX);
-
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			break;
 		*tty->flip.char_buf_ptr = ch;
 		icount->rx++;
 
 #ifdef SERIAL_DEBUG_INTR
-		printk("DR%02x:%02x...", ch, *status);
+		printk("D%02x:%02x.", ch, *status);
 #endif
 		*tty->flip.flag_buf_ptr = 0;
 		if (*status & (UART_LSR_BI | UART_LSR_PE |
@@ -417,8 +416,12 @@
 			 * should be ignored.
 			 */
 			if (*status & info->ignore_status_mask) {
-				if (++ignored > 100)
+				if (++ignored > 100) {
+#ifdef SERIAL_DEBUG_INTR
+					printk("ign100..");
+#endif
 					break;
+				}
 				goto ignore_char;
 			}
 			*status &= info->read_status_mask;
@@ -454,6 +457,9 @@
 	ignore_char:
 		*status = serial_inp(info, UART_LSR);
 	} while (*status & UART_LSR_DR);
+#ifdef SERIAL_DEBUG_INTR
+	printk("E%02x.R%d", *status, tty->flip.count);
+#endif
 	tty_flip_buffer_push(tty);
 }
 
@@ -490,7 +496,7 @@
 		su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("THRE...");
+	printk("T%d...", info->xmit_cnt);
 #endif
 	if (intr_done)
 		*intr_done = 0;
@@ -580,7 +586,7 @@
 	unsigned char status;
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt(%s)...", __irq_itoa(irq));
+	printk("su_kbd_ms_interrupt(%s)...", __irq_itoa(irq));
 #endif
 	if (!info)
 		return;
@@ -611,12 +617,16 @@
 	int pass_counter = 0;
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt(%s)...", __irq_itoa(irq));
+	printk("su_serial_interrupt(%s)...", __irq_itoa(irq));
 #endif
 	info = (struct su_struct *)dev_id;
-	if (!info || !info->tty)
+	if (!info || !info->tty) {
+#ifdef SERIAL_DEBUG_INTR
+		printk("strain\n");
+#endif
 		return;
-	
+	}
+
 	do {
 		status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
@@ -629,8 +639,8 @@
 			transmit_chars(info, 0);
 
 		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
-			printk("rs loop break\n");
+#ifdef SERIAL_DEBUG_INTR
+			printk("rs loop break");
 #endif
 			break; 	/* Prevent infinite loops */
 		}
@@ -658,18 +668,16 @@
  * interrupt driver proper are done; the interrupt driver schedules
  * them using su_sched_event(), and they get done here.
  */
-static void
-do_serial_bh(void)
+static void do_serial_bh(void)
 {
 	run_task_queue(&tq_serial);
 }
 
-static void
-do_softint(void *private_)
+static void do_softint(void *private_)
 {
 	struct su_struct	*info = (struct su_struct *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -724,7 +732,8 @@
 	cli();
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+	printk("starting up ttys%d (irq %s)...", info->line,
+	       __irq_itoa(info->irq));
 #endif
 
 	if (uart_config[info->type].flags & UART_STARTECH) {
@@ -1269,12 +1278,13 @@
 su_flush_buffer(struct tty_struct *tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->device, "su_flush_buffer"))
 		return;
-	cli();
+	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1313,41 +1323,43 @@
 su_throttle(struct tty_struct * tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 #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, "su_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty))
 		su_send_xchar(tty, STOP_CHAR(tty));
 
 	if (tty->termios->c_cflag & CRTSCTS)
 		info->MCR &= ~UART_MCR_RTS;
 
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 }
 
 static void
 su_unthrottle(struct tty_struct * tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 #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, "su_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
@@ -1356,9 +1368,9 @@
 	}
 	if (tty->termios->c_cflag & CRTSCTS)
 		info->MCR |= UART_MCR_RTS;
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 }
 
 /*
@@ -1382,10 +1394,11 @@
 {
 	unsigned char status;
 	unsigned int result;
+	unsigned long flags;
 
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_LSR);
-	sti();
+	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 	return put_user(result,value);
 }
@@ -1396,11 +1409,12 @@
 {
 	unsigned char control, status;
 	unsigned int result;
+	unsigned long flags;
 
 	control = info->MCR;
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
-	sti();
+	restore_flags(flags);
 	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 #ifdef TIOCM_OUT1
@@ -1419,6 +1433,7 @@
 {
 	int error;
 	unsigned int arg;
+	unsigned long flags;
 
 	error = get_user(arg, value);
 	if (error)
@@ -1465,9 +1480,9 @@
 	default:
 		return -EINVAL;
 	}
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 	return 0;
 }
 
@@ -1589,13 +1604,14 @@
 		default:
 			return -ENOIOCTLCMD;
 		}
-	/* return 0; */ /* Trigger warnings is fall through by a chance. */
+	/* return 0; */ /* Trigger warnings if fall through by a chance. */
 }
 
 static void
 su_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (   (tty->termios->c_cflag == old_termios->c_cflag)
 	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
@@ -1608,11 +1624,11 @@
 	if ((old_termios->c_cflag & CBAUD) &&
 	    !(tty->termios->c_cflag & CBAUD)) {
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 	}
-	
+
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
 	    (tty->termios->c_cflag & CBAUD)) {
@@ -1621,9 +1637,9 @@
 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
 			info->MCR |= UART_MCR_RTS;
 		}
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 	}
 	
 	/* Handle turning off CRTSCTS */
@@ -1771,6 +1787,9 @@
 	if (info->type == PORT_UNKNOWN)
 		return;
 
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case ... */
+
 	orig_jiffies = jiffies;
 	/*
 	 * Set the check interval to be 1/5 of the estimated time to
@@ -1838,8 +1857,9 @@
 		struct su_struct *info)
 {
 	struct wait_queue wait = { current, NULL };
-	int		retval;
-	int		do_clocal = 0;
+	int		  retval;
+	int		  do_clocal = 0, extra_count = 0;
+	unsigned long	  flags;
 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -1909,19 +1929,21 @@
 	printk("block_til_ready before block: ttys%d, count = %d\n",
 	       info->line, info->count);
 #endif
-	cli();
-	if (!tty_hung_up_p(filp)) 
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
 		info->count--;
-	sti();
+	}
+	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
-		cli();
+		save_flags(flags); cli();
 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
 		    (tty->termios->c_cflag & CBAUD))
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
-		sti();
+		restore_flags(flags);
 		current->state = TASK_INTERRUPTIBLE;
 		if (tty_hung_up_p(filp) ||
 		    !(info->flags & ASYNC_INITIALIZED)) {
@@ -1952,7 +1974,7 @@
 	}
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
+	if (extra_count)
 		info->count++;
 	info->blocked_open--;
 #ifdef SERIAL_DEBUG_OPEN
@@ -1982,16 +2004,19 @@
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 	info = su_table + line;
-	if (serial_paranoia_check(info, tty->device, "su_open"))
-		return -ENODEV;
 	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	if (serial_paranoia_check(info, tty->device, "su_open")) {
+		info->count--;
+		return -ENODEV;
+	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,
 	       info->count);
 #endif
-	tty->driver_data = info;
-	info->tty = tty;
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
@@ -2066,8 +2091,9 @@
 static __inline__ int
 line_info(char *buf, struct su_struct *info)
 {
-	char	stat_buf[30], control, status;
-	int	ret;
+	char		stat_buf[30], control, status;
+	int		ret;
+	unsigned long	flags;
 
 	ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
 		      info->line, uart_config[info->type].name, 
@@ -2081,10 +2107,10 @@
 	/*
 	 * Figure out the current RS-232 lines
 	 */
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
 	control = info ? info->MCR : serial_in(info, UART_MCR);
-	sti();
+	restore_flags(flags);
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
@@ -2165,9 +2191,15 @@
  * number, and identifies which options were configured into this
  * driver.
  */
-static __inline__
-void show_su_version(void)
+__initfunc(static __inline__ void show_su_version(void))
 {
+	char *revision = "$Revision: 1.16 $";
+	char *version, *p;
+
+	version = strchr(revision, ' ');
+	strcpy(serial_version, ++version);
+	p = strchr(serial_version, ' ');
+	*p = '\0';
  	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 }
 
@@ -2249,23 +2281,21 @@
 	 * 0x80 is a non-existent port; which should be safe since
 	 * include/asm/io.h also makes this assumption.
 	 */
-	scratch = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, 0);
-	scratch2 = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, scratch);
+	scratch = serial_inp(info, UART_IER);
+	serial_outp(info, UART_IER, 0);
+	scratch2 = serial_inp(info, UART_IER);
+	serial_outp(info, UART_IER, scratch);
 	if (scratch2) {
 		restore_flags(flags);
 		return;		/* We failed; there's nothing here */
 	}
 
-#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
-	scratch = serial_in(info, UART_MCR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
-	scratch2 = serial_in(info, UART_MSR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
-	status1 = serial_in(info, UART_MSR) & 0xF0;
-	su_outb(info, UART_MCR, scratch);
-	su_outb(info, UART_MSR, scratch2);
+#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */
+	scratch = serial_inp(info, UART_MCR);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+	status1 = serial_inp(info, UART_MSR) & 0xF0;
+	serial_outp(info, UART_MCR, scratch);
 	if (status1 != 0x90) {
 		restore_flags(flags);
 		return;
@@ -2273,10 +2303,10 @@
 #endif
 
 	scratch2 = serial_in(info, UART_LCR);
-	su_outb(info, UART_LCR, 0xBF);	/* set up for StarTech test */
-	su_outb(info, UART_EFR, 0);	/* EFR is the same as FCR */
-	su_outb(info, UART_LCR, 0);
-	su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_outp(info, UART_LCR, 0xBF);	/* set up for StarTech test */
+	serial_outp(info, UART_EFR, 0);		/* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, 0);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(info, UART_IIR) >> 6;
 	switch (scratch) {
 		case 0:
@@ -2294,38 +2324,38 @@
 	}
 	if (info->type == PORT_16550A) {
 		/* Check for Startech UART's */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		if (su_inb(info, UART_EFR) == 0) {
+		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		if (serial_in(info, UART_EFR) == 0) {
 			info->type = PORT_16650;
 		} else {
-			su_outb(info, UART_LCR, 0xBF);
-			if (su_inb(info, UART_EFR) == 0)
+			serial_outp(info, UART_LCR, 0xBF);
+			if (serial_in(info, UART_EFR) == 0)
 				info->type = PORT_16650V2;
 		}
 	}
 	if (info->type == PORT_16550A) {
 		/* Check for TI 16750 */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		su_outb(info, UART_FCR,
+		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		serial_outp(info, UART_FCR,
 			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-		scratch = su_inb(info, UART_IIR) >> 5;
+		scratch = serial_in(info, UART_IIR) >> 5;
 		if (scratch == 7) {
-			su_outb(info, UART_LCR, 0);
-			su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-			scratch = su_inb(info, UART_IIR) >> 5;
+			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+			scratch = serial_in(info, UART_IIR) >> 5;
 			if (scratch == 6)
 				info->type = PORT_16750;
 		}
-		su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	}
-	su_outb(info, UART_LCR, scratch2);
+	serial_outp(info, UART_LCR, scratch2);
 	if (info->type == PORT_16450) {
-		scratch = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0xa5);
-		status1 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0x5a);
-		status2 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, scratch);
+		scratch = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0xa5);
+		status1 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0x5a);
+		status2 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, scratch);
 
 		if ((status1 != 0xa5) || (status2 != 0x5a))
 			info->type = PORT_8250;
@@ -2349,9 +2379,10 @@
 	/*
 	 * Reset the UART.
 	 */
-	su_outb(info, UART_MCR, 0x00);
-	su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
-	su_inb(info, UART_RX);
+	serial_outp(info, UART_MCR, 0x00);
+	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT));
+	(void)serial_in(info, UART_RX);
+	serial_outp(info, UART_IER, 0x00);
 
 	restore_flags(flags);
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.1.128/linux/drivers/sbus/char/zs.c	Sun Nov  8 14:03:01 1998
+++ linux/drivers/sbus/char/zs.c	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $
+/* $Id: zs.c,v 1.32 1998/11/08 11:15:29 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1806,7 +1806,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.31 $";
+	char *revision = "$Revision: 1.32 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.1.128/linux/drivers/scsi/ChangeLog.ncr53c8xx	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Sun Nov 15 09:57:00 1998
@@ -1,3 +1,9 @@
+Wed Nov 11  10:00 1998 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.1b
+	- The driver was unhappy when configured with default_tags > MAX_TAGS
+	  Hopefully doubly-fixed.
+	- Update the Configure.help driver section that speaks of TAGS.
+
 Wed Oct 21 21:00 1998 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.1a
 	- Changes from Eddie Dost for Sparc and Alpha:
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.128/linux/drivers/scsi/Config.in	Thu Nov 12 16:21:20 1998
+++ linux/drivers/scsi/Config.in	Sun Nov 15 09:57:00 1998
@@ -80,7 +80,7 @@
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
   dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
-    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 4
+    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
     int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
     int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
     bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.1.128/linux/drivers/scsi/NCR5380.c	Wed Sep  9 14:51:08 1998
+++ linux/drivers/scsi/NCR5380.c	Fri Nov 13 10:29:44 1998
@@ -686,7 +686,7 @@
 	save_flags(flags);
 	cli();
 	for (; expires_first &&
-		((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires <= jiffies; ) 
+		time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); )
 	{
 		instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;
 		((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;
@@ -776,7 +776,7 @@
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
 		      ICR_ASSERT_SEL);
 
-	while (probe_irq == IRQ_NONE && jiffies < timeout)
+	while (probe_irq == IRQ_NONE && time_before(jiffies,timeout))
 		barrier();
 
 	NCR5380_write(SELECT_ENABLE_REG, 0);
@@ -1123,7 +1123,7 @@
 			printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
 			       instance->host_no);
 			timeout = jiffies + 5 * HZ;
-			while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
+			while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY));
 			break;
 		case 2:
 			printk("scsi%d: bus busy, attempting abort\n",
@@ -1417,7 +1417,7 @@
 			    && !hostdata->dmalen
 #endif
 #ifdef USLEEP
-			    && (!hostdata->time_expires || hostdata->time_expires <= jiffies)
+			    && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
 #endif
 			    ) {
 				restore_flags(flags);
@@ -1532,10 +1532,10 @@
 
 								spin_unlock_irq(&io_request_lock);
 								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
-								       && jiffies < timeout);
+								       && time_before(jiffies, timeout));
 								spin_lock_irq(&io_request_lock);
 								
-								if (jiffies >= timeout)
+								if (time_after_eq(jiffies, timeout) )
 									printk("scsi%d: timeout at NCR5380.c:%d\n",
 									       host->host_no, __LINE__);
 							}
@@ -1681,11 +1681,11 @@
 		spin_unlock_irq(&io_request_lock);
 
 		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-		       && jiffies < timeout);
+		       && time_before(jiffies,timeout));
 
 		spin_lock_irq(&io_request_lock);
 		       
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies,timeout)) {
 			printk("scsi: arbitration timeout at %d\n", __LINE__);
 			NCR5380_write(MODE_REG, MR_BASE);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1844,7 +1844,7 @@
 				waiting period */
 #else
 	spin_unlock_irq(&io_request_lock);
-	while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) &
+	while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
 					(SR_BSY | SR_IO)));
 	spin_lock_irq(&io_request_lock);
 #endif
@@ -1915,10 +1915,10 @@
 		unsigned long timeout = jiffies + NCR_TIMEOUT;
 
 		spin_unlock_irq(&io_request_lock);
-		while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout);
+		while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout));
 		spin_lock_irq(&io_request_lock);
 		
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 			return -1;
@@ -3082,7 +3082,7 @@
 		{
 			/* RvC: go to sleep if polling time expired
 			 */
-			if (!cmd->device->disconnect && jiffies >= poll_time) 
+			if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time))
 			{
 				hostdata->time_expires = jiffies + USLEEP_SLEEP;
 #if (NDEBUG & NDEBUG_USLEEP)
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.1.128/linux/drivers/scsi/esp.c	Thu Aug  6 14:06:33 1998
+++ linux/drivers/scsi/esp.c	Mon Nov 16 10:37:28 1998
@@ -1432,7 +1432,6 @@
 			   (SDptr->type != TYPE_ROM ||
 			    strncmp(SDptr->vendor, "TOSHIBA", 7))) {
 				build_wide_nego_msg(esp, 16);
-				esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
 				SDptr->wide = 1;
 				esp->wnip = 1;
 				goto after_nego_msg_built;
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/fd_mcs.c linux/drivers/scsi/fd_mcs.c
--- v2.1.128/linux/drivers/scsi/fd_mcs.c	Thu Nov 12 16:21:21 1998
+++ linux/drivers/scsi/fd_mcs.c	Sun Nov 15 09:52:27 1998
@@ -88,7 +88,6 @@
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
 #include <linux/delay.h>
-#include <linux/config.h>
 #include <linux/mca.h>
 #include <asm/io.h>
 #include <asm/system.h>
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- v2.1.128/linux/drivers/scsi/mesh.c	Thu Aug  6 14:06:33 1998
+++ linux/drivers/scsi/mesh.c	Sun Nov 15 10:51:48 1998
@@ -28,6 +28,7 @@
 #include <asm/hydra.h>
 #include <asm/processor.h>
 #include <asm/spinlock.h>
+#include <asm/feature.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -222,6 +223,13 @@
 	struct Scsi_Host *mesh_host;
 	void *dma_cmd_space;
 
+	if (_machine == _MACH_Pmac) {
+	    use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG);
+	} else {
+	    /* CHRP mac-io */
+	    use_active_neg = SEQ_ACTIVE_NEG;
+	}
+
 	nmeshes = 0;
 	prev_statep = &all_meshes;
 	/*
@@ -245,7 +253,7 @@
 		}
 		mesh_host->unique_id = nmeshes;
 		note_scsi_host(mesh, mesh_host);
-
+		
 		ms = (struct mesh_state *) mesh_host->hostdata;
 		if (ms == 0)
 			panic("no mesh state");
@@ -281,10 +289,6 @@
 		*prev_statep = ms;
 		prev_statep = &ms->next;
 
-		if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
-			printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
-		}
-
 		if ((cfp = (int *) get_property(mesh, "clock-frequency",
 						NULL))) {
 			ms->clk_freq = *cfp;
@@ -298,18 +302,20 @@
 		if (mesh_sync_period < minper)
 			mesh_sync_period = minper;
 
+		feature_set(mesh, FEATURE_MESH_enable);
+		mdelay(200);
+
 		mesh_init(ms);
 
+		if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
+			printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+		}
+
 		++nmeshes;
 	}
-	if (_machine == _MACH_Pmac) {
-	    use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG);
-	    if (nmeshes > 0)
+
+	if ((_machine == _MACH_Pmac) && (nmeshes > 0))
 		register_reboot_notifier(&mesh_notifier);
-	} else {
-	    /* CHRP mac-io */
-	    use_active_neg = SEQ_ACTIVE_NEG;
-	}
 
 	return nmeshes;
 }
@@ -467,12 +473,27 @@
 	volatile struct mesh_regs *mr = ms->mesh;
 	volatile struct dbdma_regs *md = ms->dma;
 
-	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
+	udelay(100);
+
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
+	out_8(&mr->exception, 0xff);	/* clear all exception bits */
+	out_8(&mr->error, 0xff);	/* clear all error bits */
+	out_8(&mr->sequence, SEQ_RESETMESH);
+	udelay(10);
 	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
 	out_8(&mr->source_id, ms->host->this_id);
 	out_8(&mr->sel_timeout, 25);	/* 250ms */
-	out_8(&mr->sync_params, ASYNC_PARAMS);	/* asynchronous initially */
-	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+	udelay(30);			/* leave it on for >= 25us */
+	out_8(&mr->bus_status1, 0);	/* negate RST */
+
+	out_8(&mr->sequence, SEQ_FLUSHFIFO);
+	udelay(1);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
 }
 
 /*
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.128/linux/drivers/scsi/ncr53c8xx.c	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/ncr53c8xx.c	Sun Nov 15 09:57:00 1998
@@ -73,7 +73,7 @@
 */
 
 /*
-**	October 21 1998, version 3.1a
+**	November 11 1998, version 3.1b
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -4319,7 +4319,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = driver_setup.default_tags;
+			tp->usrtags = SCSI_NCR_MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -8208,6 +8208,12 @@
 	if (lp) {
 		XPT_QUEHEAD *qp;
 		/*
+		**	Keep from using more tags than we can handle.
+		*/
+		if (lp->usetags && lp->busyccbs >= lp->maxnxs)
+			return (ccb_p) 0;
+
+		/*
 		**	Allocate a new CCB if needed.
 		*/
 		if (xpt_que_empty(&lp->free_ccbq))
@@ -10072,19 +10078,20 @@
 		lp = tp->lp[device->lun];
 
 		/*
-		**	Donnot use more than our maximum.
 		**	Select queue depth from driver setup.
 		**	Donnot use more than configured by user.
 		**	Use 2 for devices that donnot support tags.
 		**	Use at least 2.
+		**	Donnot use more than our maximum.
 		*/
-		device->queue_depth = SCSI_NCR_MAX_TAGS;
 		device->queue_depth =
 			device_queue_depth(np, device->id, device->lun);
 		if (device->queue_depth > tp->usrtags)
 			device->queue_depth = tp->usrtags;
 		if (!device->tagged_supported || device->queue_depth < 2)
 			device->queue_depth = 2;
+		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
+			device->queue_depth = SCSI_NCR_MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.1.128/linux/drivers/scsi/ncr53c8xx.h	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/ncr53c8xx.h	Wed Nov 18 22:31:57 1998
@@ -45,7 +45,7 @@
 /*
 **	Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 3.1a"
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 3.1b"
 
 /*
 **	Check supported Linux versions
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.128/linux/drivers/scsi/scsi.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/scsi/scsi.c	Fri Nov 13 10:16:15 1998
@@ -226,6 +226,7 @@
 {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
 {"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
+{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},    /* Responds to all lun */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1
 						 * for aha152x controller, which causes
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v2.1.128/linux/drivers/scsi/scsi_proc.c	Tue Jun 23 10:01:24 1998
+++ linux/drivers/scsi/scsi_proc.c	Fri Nov 13 10:16:15 1998
@@ -110,14 +110,29 @@
     return(-EBADF);
 }
 
+static void scsi_proc_fill_inode(struct inode *inode, int fill)
+{
+Scsi_Host_Template *shpnt;
+
+shpnt = scsi_hosts;
+while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
+    shpnt = shpnt->next;
+if (!shpnt || !shpnt->module)
+    return;
+if (fill)
+    __MOD_INC_USE_COUNT(shpnt->module);
+else
+    __MOD_DEC_USE_COUNT(shpnt->module);
+}
+
 void build_proc_dir_entries(Scsi_Host_Template *tpnt)
 {
     struct Scsi_Host *hpnt;
-
     struct scsi_dir *scsi_hba_dir;
 
     proc_scsi_register(0, tpnt->proc_dir);
-    
+    tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
+
     hpnt = scsi_hostlist;
     while (hpnt) {
         if (tpnt == hpnt->hostt) {
diff -u --recursive --new-file v2.1.128/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.128/linux/drivers/scsi/sd.c	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/sd.c	Wed Nov 18 16:42:44 1998
@@ -1758,7 +1758,7 @@
 
 void cleanup_module( void)
 {
-    struct gendisk * prev_sdgd;
+    struct gendisk ** prev_sdgd_link;
     struct gendisk * sdgd;
     int i;
     int removed = 0;
@@ -1778,16 +1778,20 @@
 	scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
 	scsi_init_free((char *) sd,
 		       (sd_template.dev_max << 4) * sizeof(struct hd_struct));
+
 	/*
 	 * Now remove sd_gendisks from the linked list
 	 */
-
-	for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next)
-	{
-	    if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK.max_nr)
-	    	    removed++, sdgd->next = sdgd->next->next;
-	    else sdgd = sdgd->next;
+	prev_sdgd_link = &gendisk_head;
+	while ((sdgd = *prev_sdgd_link) != NULL) {
+	    if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) {
+		removed++;
+		*prev_sdgd_link = sdgd->next;
+		continue;
+	    }
+	    prev_sdgd_link = &sdgd->next;
 	}
+
 	if (removed != N_USED_SD_MAJORS)
 	    printk("%s %d sd_gendisks in disk chain",
 		removed > N_USED_SD_MAJORS ? "total" : "just", removed);
diff -u --recursive --new-file v2.1.128/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.1.128/linux/drivers/sound/Makefile	Fri Oct 23 22:01:21 1998
+++ linux/drivers/sound/Makefile	Mon Nov 16 10:32:58 1998
@@ -41,19 +41,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_SOUND)		+= soundcore.o
-
-ifeq ($(ARCH),m68k)
-
 obj-$(CONFIG_DMASOUND)		+= dmasound.o
-
-else
-
-ifeq ($(CONFIG_PMAC),y)
-
-obj-$(CONFIG_DMASOUND)		+= dmasound.o
-
-else
-
 obj-$(CONFIG_SOUND_OSS)		+= sound.o
 obj-$(CONFIG_SOUND_ADLIB)	+= adlib_card.o opl3.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o ad1848.o 
@@ -89,9 +77,6 @@
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
-
-endif
-endif
 
 # Declare multi-part drivers.
 
diff -u --recursive --new-file v2.1.128/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.1.128/linux/drivers/sound/ad1848.c	Thu Nov 12 16:21:21 1998
+++ linux/drivers/sound/ad1848.c	Fri Nov 13 10:29:44 1998
@@ -1934,7 +1934,7 @@
 
 		if (!share_dma)
 		{
-			if (irq > 0)
+			if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
 				free_irq(devc->irq, (void *)devc->dev_no);
 
 			sound_free_dma(audio_devs[dev]->dmap_out->dma);
diff -u --recursive --new-file v2.1.128/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.1.128/linux/drivers/sound/dmasound.c	Thu Nov 12 16:21:22 1998
+++ linux/drivers/sound/dmasound.c	Sun Nov 15 10:51:48 1998
@@ -107,18 +107,17 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
-#ifdef CONFIG_PMAC_PBOOK
 #include <asm/adb.h>
+#include <asm/cuda.h>
 #include <asm/pmu.h>
-#endif /* CONFIG_PMAC_PBOOK */
 #include "awacs_defs.h"
 #include <linux/nvram.h>
 #include <linux/vt_kern.h>
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 #include "dmasound.h"
 #include <linux/soundcard.h>
@@ -165,7 +164,7 @@
 
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 /*
  * Interrupt numbers and addresses, obtained from the device tree.
  */
@@ -174,6 +173,8 @@
 static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
 static int awacs_rate_index;
 static int awacs_subframe;
+static int awacs_revision;
+static int awacs_spkr_vol;
 
 /*
  * Space for the DBDMA command blocks.
@@ -249,7 +250,7 @@
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 /*** Some declarations *******************************************************/
 
@@ -587,7 +588,7 @@
 			    ssize_t frameLeft);
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
 			   u_char frame[], ssize_t *frameUsed,
 			   ssize_t frameLeft);
@@ -618,7 +619,7 @@
 static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
 			    u_char frame[], ssize_t *frameUsed,
 			    ssize_t frameLeft);
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 /*** Machine definitions *****************************************************/
 
@@ -675,7 +676,7 @@
 	int treble;
 	int gain;
 	int minDev;		/* minor device number currently open */
-#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC)
+#if defined(CONFIG_ATARI) || defined(CONFIG_PPC)
 	int bal;		/* balance factor for expanding (not volume!) */
 	u_long data;		/* data for expanding */
 #endif /* CONFIG_ATARI */
@@ -724,7 +725,7 @@
 static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 static void *PMacAlloc(unsigned int size, int flags) __init;
 static void PMacFree(void *ptr, unsigned int size) __init;
 static int PMacIrqInit(void) __init;
@@ -743,7 +744,7 @@
 static int awacs_volume_setter(int volume, int n, int mute, int lshift);
 static void awacs_mksound(unsigned int hz, unsigned int ticks);
 static void awacs_nosound(unsigned long xx);
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 /*** Mid level stuff *********************************************************/
 
@@ -1777,7 +1778,7 @@
 }
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
 			   u_char frame[], ssize_t *frameUsed,
 			   ssize_t frameLeft)
@@ -2161,7 +2162,7 @@
 	return stereo? utotal * 4: utotal * 2;
 }
 
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 
 #ifdef CONFIG_ATARI
@@ -2191,7 +2192,7 @@
 };
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 static TRANS transAwacsNormal = {
 	pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
 	pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
@@ -2201,7 +2202,7 @@
 	pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
 	pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
 };
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 /*** Low level stuff *********************************************************/
 
@@ -2971,7 +2972,7 @@
 }
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 
 /*
  * PCI PowerMac, with AWACS and DBDMA.
@@ -3226,7 +3227,7 @@
 {
 	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
 		;	/* XXX should have timeout */
-	out_le32(&awacs->codec_ctrl, val);
+	out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
 }
 
 static void awacs_nosound(unsigned long xx)
@@ -3343,7 +3344,38 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-#endif /* CONFIG_PMAC */
+/* Turn on sound output, needed on G3 desktop powermacs */
+static void
+awacs_enable_amp(int spkr_vol)
+{
+	struct adb_request req;
+
+	awacs_spkr_vol = spkr_vol;
+	if (adb_hardware != ADB_VIACUDA)
+		return;
+
+	/* turn on headphones */
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 4, 0);
+	while (!req.complete) cuda_poll();
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 6, 0);
+	while (!req.complete) cuda_poll();
+
+	/* turn on speaker */
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
+	while (!req.complete) cuda_poll();
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+		     0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
+	while (!req.complete) cuda_poll();
+
+	cuda_request(&req, NULL, 5, CUDA_PACKET,
+		     CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
+	while (!req.complete) cuda_poll();
+}
+
+#endif /* CONFIG_PPC */
 
 /*** Machine definitions *****************************************************/
 
@@ -3382,7 +3414,7 @@
 };
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 static MACHINE machPMac = {
 	DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
 #ifdef MODULE
@@ -3683,7 +3715,7 @@
 		break;
 #endif /* CONFIG_AMIGA */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	case DMASND_AWACS:
 		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
@@ -3733,12 +3765,18 @@
 			IOCTL_IN(arg, data);
 			return IOCTL_OUT(arg, sound_set_volume(data));
 		case SOUND_MIXER_READ_SPEAKER:
-			data = (awacs_reg[1] & MASK_CMUTE)? 0:
-				awacs_get_volume(awacs_reg[4], 6);
+			if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA)
+				data = awacs_spkr_vol;
+			else
+				data = (awacs_reg[1] & MASK_CMUTE)? 0:
+					awacs_get_volume(awacs_reg[4], 6);
 			return IOCTL_OUT(arg, data);
 		case SOUND_MIXER_WRITE_SPEAKER:
 			IOCTL_IN(arg, data);
-			data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+			if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA)
+				awacs_enable_amp(data);
+			else
+				data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
 			return IOCTL_OUT(arg, data);
 		case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
 			IOCTL_IN(arg, data);
@@ -3862,10 +3900,10 @@
 
 static void sq_setup(int numBufs, int bufSize, char **buffers)
 {
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	int i;
 	volatile struct dbdma_cmd *cp;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 	sq.max_count = numBufs;
 	sq.max_active = numBufs;
@@ -3887,7 +3925,7 @@
 	sq.block_size_half = sq.block_size>>1;
 	sq.block_size_quarter = sq.block_size_half>>1;
 #endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	cp = awacs_tx_cmds;
 	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
 	for (i = 0; i < numBufs; ++i, ++cp) {
@@ -3897,7 +3935,7 @@
 	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
 	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
 	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 }
 
 static void sq_play(void)
@@ -4206,11 +4244,11 @@
 		sound.dsp.speed = 8000;
 		break;
 #endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	case DMASND_AWACS:
 		sound.dsp.speed = 8000;
 		break;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 	}
 
 	/* before the first open to /dev/dsp this wouldn't be set */
@@ -4251,11 +4289,11 @@
 		mach = "Amiga ";
 		break;
 #endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	case DMASND_AWACS:
 		mach = "PowerMac ";
 		break;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 	}
 	len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
 
@@ -4396,7 +4434,7 @@
 {
 	int has_sound = 0;
 	int i;
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	struct device_node *np;
 #endif
 
@@ -4430,7 +4468,7 @@
 	}
 #endif /* __mc68000__ */
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
 	awacs_subframe = 0;
 	np = find_devices("awacs");
 	if (np == 0) {
@@ -4479,6 +4517,13 @@
 		awacs_write(awacs_reg[2] + MASK_ADDR2);
 		awacs_write(awacs_reg[4] + MASK_ADDR4);
 
+		/* Initialize recent versions of the awacs */
+		awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf;
+		if (awacs_revision >= 3) {
+			awacs_write(0x6000);
+			awacs_enable_amp(100 * 0x101);
+		}
+
 		/* Initialize beep stuff */
 		beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
 		orig_mksound = kd_mksound;
@@ -4492,7 +4537,7 @@
 					&awacs_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 	}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
 
 	if (!has_sound)
 		return;
diff -u --recursive --new-file v2.1.128/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.128/linux/drivers/sound/soundcard.c	Thu Nov 12 16:21:22 1998
+++ linux/drivers/sound/soundcard.c	Fri Nov 13 10:29:44 1998
@@ -292,11 +292,13 @@
         return len;
 }
 
+#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_root_sound = {
         PROC_SOUND, 5, "sound",
         S_IFREG | S_IRUGO, 1, 0, 0,
         0, NULL, sound_proc_get_info
 };
+#endif
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -842,8 +844,10 @@
 		audio_init_devices();
 	}
 #endif
+#ifdef CONFIG_PROC_FS
 	if (proc_register(&proc_root, &proc_root_sound))
 		printk(KERN_ERR "sound: registering /proc/sound failed\n");
+#endif		
 }
 
 static int      sound[20] = {
diff -u --recursive --new-file v2.1.128/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.1.128/linux/drivers/video/Config.in	Fri Oct 23 22:01:22 1998
+++ linux/drivers/video/Config.in	Fri Nov 13 10:10:11 1998
@@ -22,6 +22,7 @@
     tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
+      bool 'Amiga CyberVisionPPC support (experimental)' CONFIG_FB_CVPPC
       tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
       tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
     fi
@@ -55,6 +56,17 @@
     bool 'VESA VGA graphics console' CONFIG_FB_VESA
     define_bool CONFIG_VIDEO_SELECT y
   fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_PCI" != "n" ]; then
+      tristate 'Matrox acceleration' CONFIG_FB_MATROX
+      if  [ "$CONFIG_FB_MATROX" != "n" ]; then
+        bool '  Millenium I/II support' CONFIG_FB_MATROX_MILLENIUM
+        bool '  Mystique support' CONFIG_FB_MATROX_MYSTIQUE
+        bool '  G100/G200 support' CONFIG_FB_MATROX_G100
+        bool '  Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+      fi
+    fi
+  fi
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
     bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS
     if [ "$CONFIG_FB_SBUS" != "n" ]; then
@@ -141,8 +153,9 @@
 	 "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
 	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	 "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
-         "$CONFIG_FB_IGA" = "y" ]; then
+         "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -152,8 +165,9 @@
 	   "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	   "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
-           "$CONFIG_FB_IGA" = "y" ]; then
+           "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
@@ -161,36 +175,44 @@
 	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
 	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
 	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	 "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB16 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 	   "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
 	   "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+ 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	   "$CONFIG_FB_MATROX" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB16 m
       fi
     fi
     if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	 "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" ]; then
+	 "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	  "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
       if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	   "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" ]; then
+	   "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+	   "$CONFIG_FB_MATROX" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB24 m
       fi
     fi
     if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
 	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
 	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	 "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+	 "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	 "$CONFIG_FB_MATROX" = "y" ]; then
       define_bool CONFIG_FBCON_CFB32 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	   "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+	   "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	   "$CONFIG_FB_MATROX" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB32 m
       fi
     fi
diff -u --recursive --new-file v2.1.128/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.1.128/linux/drivers/video/Makefile	Fri Oct 23 22:01:22 1998
+++ linux/drivers/video/Makefile	Fri Nov 13 10:10:11 1998
@@ -123,6 +123,11 @@
   endif
 endif
 
+ifeq ($(CONFIG_FB_CVPPC),y)
+L_OBJS += cvppcfb.o
+CONFIG_FBGEN_BUILTIN = y
+endif
+
 ifeq ($(CONFIG_FB_MAC),y)
 L_OBJS += macfb.o
 endif
@@ -308,6 +313,14 @@
 else
   ifdef CONFIG_FBGEN_MODULE
   MX_OBJS += fbgen.o
+  endif
+endif
+
+ifeq ($(CONFIG_FB_MATROX),y)
+L_OBJS += matroxfb.o
+else
+  ifeq ($(CONFIG_FB_MATROX),m)
+  M_OBJS += matroxfb.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.128/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.1.128/linux/drivers/video/amifb.c	Fri Oct  9 13:27:11 1998
+++ linux/drivers/video/amifb.c	Fri Nov 13 10:10:11 1998
@@ -60,6 +60,7 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/setup.h>
+#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-afb.h>
@@ -1478,7 +1479,8 @@
 			struct fb_fix_screeninfo fix;
 
 			ami_encode_fix(&fix, &par);
-			display->screen_base = fix.smem_start;
+			display->screen_base = 
+				phys_to_virt ((unsigned long) fix.smem_start);
 			display->visual = fix.visual;
 			display->type = fix.type;
 			display->type_aux = fix.type_aux;
@@ -2124,7 +2126,7 @@
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, amifb_name);
-	fix->smem_start = (char *)videomemory;
+	fix->smem_start = (char*) virt_to_phys((void *)videomemory);
 	fix->smem_len = videomemorysize;
 
 #ifdef FBCON_HAS_MFB
diff -u --recursive --new-file v2.1.128/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.1.128/linux/drivers/video/atyfb.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/video/atyfb.c	Fri Nov 13 10:10:11 1998
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.81 1998/10/14 16:45:38 ecd Exp $
+/*  $Id: atyfb.c,v 1.89 1998/11/12 13:07:26 geert Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -400,12 +400,15 @@
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
 static char noaccel __initdata = 0;
+static u32 default_vram __initdata = 0;
+static int default_pll __initdata = 0;
+static int default_mclk __initdata = 0;
 
 static const u32 ref_clk_per = 1000000000000ULL/14318180;
 
 #if defined(CONFIG_PPC)
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
 #endif
 
 #ifdef CONFIG_ATARI
@@ -448,11 +451,11 @@
 };
 
 static const char *aty_gx_ram[8] __initdata = {
-    "DRAM", "VRAM", "VRAM", "DRAM", "GDRAM", "EVRAM", "EVRAM", "RESV"
+    "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"
 };
 
 static const char *aty_ct_ram[8] __initdata = {
-    "OFF", "DRAM", "EDO", "HPDRAM", "SDRAM", "SGRAM", "WRAM", "RESV"
+    "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"
 };
 
 
@@ -540,7 +543,6 @@
 		aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
     /* ensure engine is not locked up by clearing any FIFO or */
     /* HOST errors */
-    aty_st_le32(0xf4,0xa955,info);
     aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
 			  BUS_FIFO_ERR_ACK, info);
 }
@@ -1346,7 +1348,7 @@
 	    aty_st_514(0x03, 0x00, info);	/* Sync Control */
 	    aty_st_514(0x05, 0x00, info);	/* Power Management */
 	    aty_st_514(0x20, pll->m, info);	/* F0 / M0 */
-	    aty_st_514(0x21, pll->m, info);	/* F1 / N0 */
+	    aty_st_514(0x21, pll->n, info);	/* F1 / N0 */
 	    break;
     }
 }
@@ -1492,7 +1494,14 @@
 		    (vclk_fb_div*mclk_post_div*bpp);
     if (xclks_per_row < (1<<11))
 	FAIL("Dotclock to high");
-    fifo_size = 24;
+    if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == VT_CHIP_ID) ||
+	(Gx == VU_CHIP_ID)) {
+	fifo_size = 24;
+	dsp_loop_latency = 0;
+    } else {
+	fifo_size = 32;
+	dsp_loop_latency = 2;
+    }
     dsp_precision = 0;
     y = (xclks_per_row*fifo_size)>>11;
     while (y) {
@@ -1506,21 +1515,21 @@
     if (info->total_vram > 1*1024*1024) {
 	if (info->ram_type >= SDRAM) {
 	    /* >1 MB SDRAM */
-	    dsp_loop_latency = 8;
+	    dsp_loop_latency += 8;
 	    page_size = 8;
 	} else {
 	    /* >1 MB DRAM */
-	    dsp_loop_latency = 6;
+	    dsp_loop_latency += 6;
 	    page_size = 9;
 	}
     } else {
 	if (info->ram_type >= SDRAM) {
 	    /* <2 MB SDRAM */
-	    dsp_loop_latency = 9;
+	    dsp_loop_latency += 9;
 	    page_size = 10;
 	} else {
 	    /* <2 MB DRAM */
-	    dsp_loop_latency = 8;
+	    dsp_loop_latency += 8;
 	    page_size = 10;
 	}
     }
@@ -2385,7 +2394,7 @@
     struct fb_var_screeninfo var;
     struct display *disp;
     const char *chipname = NULL, *ramname = NULL;
-    int pll, mclk;
+    int pll, mclk, gtb_memsize;
 #if defined(CONFIG_PPC)
     int sense;
 #endif
@@ -2463,30 +2472,14 @@
 	    }
 	}
     }
-    if (mclk < 44)
-	info->mem_refresh_rate = 0;	/* 000 = 10 Mhz - 43 Mhz */
-    else if (mclk < 50)
-	info->mem_refresh_rate = 1;	/* 001 = 44 Mhz - 49 Mhz */
-    else if (mclk < 55)
-	info->mem_refresh_rate = 2;	/* 010 = 50 Mhz - 54 Mhz */
-    else if (mclk < 66)
-	info->mem_refresh_rate = 3;	/* 011 = 55 Mhz - 65 Mhz */
-    else if (mclk < 75)
-	info->mem_refresh_rate = 4;	/* 100 = 66 Mhz - 74 Mhz */
-    else if (mclk < 80)
-	info->mem_refresh_rate = 5;	/* 101 = 75 Mhz - 79 Mhz */
-    else if (mclk < 100)
-	info->mem_refresh_rate = 6;	/* 110 = 80 Mhz - 100 Mhz */
-    else
-	info->mem_refresh_rate = 7;	/* 111 = 100 Mhz and above */
-    info->pll_per = 1000000/pll;
-    info->mclk_per = 1000000/mclk;
 
     i = aty_ld_le32(MEM_CNTL, info);
-    if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
-	((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID) ||
-	(Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
-	(Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+    gtb_memsize = (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID)
+		|| ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID)
+		|| (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID)
+		|| (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID)
+		|| (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID));
+    if (gtb_memsize)
 	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
 	    case MEM_SIZE_512K:
 		info->total_vram = 0x80000;
@@ -2538,10 +2531,51 @@
 	  info->total_vram += 0x400000;
     }
 
+    if (default_vram) {
+	info->total_vram = default_vram*1024;
+	i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+	if (info->total_vram <= 0x80000)
+	    i |= MEM_SIZE_512K;
+	else if (info->total_vram <= 0x100000)
+	    i |= MEM_SIZE_1M;
+	else if (info->total_vram <= 0x200000)
+	    i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+	else if (info->total_vram <= 0x400000)
+	    i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+	else if (info->total_vram <= 0x600000)
+	    i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+	else
+	    i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+	aty_st_le32(MEM_CNTL, i, info);
+    }
+    if (default_pll)
+	pll = default_pll;
+    if (default_mclk)
+	mclk = default_mclk;
+
     printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n", 
     	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), 
     	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
 
+    if (mclk < 44)
+	info->mem_refresh_rate = 0;	/* 000 = 10 Mhz - 43 Mhz */
+    else if (mclk < 50)
+	info->mem_refresh_rate = 1;	/* 001 = 44 Mhz - 49 Mhz */
+    else if (mclk < 55)
+	info->mem_refresh_rate = 2;	/* 010 = 50 Mhz - 54 Mhz */
+    else if (mclk < 66)
+	info->mem_refresh_rate = 3;	/* 011 = 55 Mhz - 65 Mhz */
+    else if (mclk < 75)
+	info->mem_refresh_rate = 4;	/* 100 = 66 Mhz - 74 Mhz */
+    else if (mclk < 80)
+	info->mem_refresh_rate = 5;	/* 101 = 75 Mhz - 79 Mhz */
+    else if (mclk < 100)
+	info->mem_refresh_rate = 6;	/* 110 = 80 Mhz - 100 Mhz */
+    else
+	info->mem_refresh_rate = 7;	/* 111 = 100 Mhz and above */
+    info->pll_per = 1000000/pll;
+    info->mclk_per = 1000000/mclk;
+
 #ifdef DEBUG
     if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
 	int i;
@@ -2806,11 +2840,11 @@
 	    if (node == pcp->prom_node) {
 
 		struct fb_var_screeninfo *var = &default_var;
+		unsigned int N, P, Q, M, T;
 		u32 v_total, h_total;
 		struct crtc crtc;
 		u8 pll_regs[16];
 		u8 clock_cntl;
-		unsigned int N, P, Q, M, T;
 
 		crtc.vxres = prom_getintdefault(node, "width", 1024);
 		crtc.vyres = prom_getintdefault(node, "height", 768);
@@ -2833,33 +2867,28 @@
 		 */
     		clock_cntl = aty_ld_8(CLOCK_CNTL, info);
 		/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
-		for (i = 0; i < 16; i++) {
+		for (i = 0; i < 16; i++)
 			pll_regs[i] = aty_ld_pll(i, info);
-			/* printk("atyfb: PLL %2d: %02x\n", i, pll_regs[i]); */
-		}
+
 		/*
 		 * PLL Reference Devider M:
 		 */
 		M = pll_regs[2];
-		/* printk("atyfb: M: %02x\n", M); */
 
 		/*
 		 * PLL Feedback Devider N (Dependant on CLOCK_CNTL):
 		 */
 		N = pll_regs[7 + (clock_cntl & 3)];
-		/* printk("atyfb: N: %02x\n", N); */
 
 		/*
 		 * PLL Post Devider P (Dependant on CLOCK_CNTL):
 		 */
 		P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
-		/* printk("atyfb: P: %2d\n", P); */
 
 		/*
 		 * PLL Devider Q:
 		 */
 		Q = N / P;
-		/* printk("atyfb: Q: %d\n", Q); */
 
 		/*
 		 * Target Frequency:
@@ -2871,11 +2900,8 @@
 		 * where R is XTALIN (= 14318 kHz).
 		 */
 		T = 2 * Q * 14318 / M;
-		/* printk("atyfb: T: %d\n", T); */
 
-		default_var.pixclock =
-			((1000000000000ULL / v_total) * 1000) / (T * h_total);
-		/* printk("atyfb: pixclock: %d\n", default_var.pixclock); */
+		default_var.pixclock = 1000000000 / T;
 	    }
 
 #else /* __sparc__ */
@@ -2984,69 +3010,65 @@
     struct fb_info_aty *info;
     int i;
 
-    for (; dp; dp = dp->next) {
-	switch (dp->n_addrs) {
-	    case 1:
-	    case 2:
-	    case 3:
-		addr = dp->addrs[0].address;
-		break;
-	    case 4:
-		addr = dp->addrs[1].address;
-		break;
-	    default:
-		printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
-		for (i = 0; i < dp->n_addrs; i++)
-		    printk(" %08x-%08x", dp->addrs[i].address,
-			   dp->addrs[i].address+dp->addrs[i].size-1);
-		if (dp->n_addrs)
-		    printk("\n");
-		continue;
-	}
-
-	info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
-	if (!info) {
-	    printk("atyfb_of_init: can't alloc fb_info_aty\n");
+    switch (dp->n_addrs) {
+	case 1:
+	case 2:
+	case 3:
+	    addr = dp->addrs[0].address;
+	    break;
+	case 4:
+	    addr = dp->addrs[1].address;
+	    break;
+	default:
+	    printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
+	    for (i = 0; i < dp->n_addrs; i++)
+		printk(" %08x-%08x", dp->addrs[i].address,
+		       dp->addrs[i].address+dp->addrs[i].size-1);
+	    if (dp->n_addrs)
+		printk("\n");
 	    return;
-	}
-	memset(info, 0, sizeof(struct fb_info_aty));
+    }
+
+    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+    if (!info) {
+	printk("atyfb_of_init: can't alloc fb_info_aty\n");
+	return;
+    }
+    memset(info, 0, sizeof(struct fb_info_aty));
 
-	info->ati_regbase = (unsigned long)ioremap(0x7ff000+addr,
-						   0x1000)+0xc00;
-	info->ati_regbase_phys = 0x7ff000+addr;
-	info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
+    info->ati_regbase_phys = 0x7ff000+addr;
+    info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
 						   0x1000);
-	info->ati_regbase_phys += 0xc00;
-	info->ati_regbase += 0xc00;
+    info->ati_regbase_phys += 0xc00;
+    info->ati_regbase += 0xc00;
 
-	/* enable memory-space accesses using config-space command register */
-	if (pci_device_loc(dp, &bus, &devfn) == 0) {
-	    pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-	    if (cmd != 0xffff) {
-		cmd |= PCI_COMMAND_MEMORY;
-		pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-	    }
+    /* enable memory-space accesses using config-space command register */
+    if (pci_device_loc(dp, &bus, &devfn) == 0) {
+	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+	if (cmd != 0xffff) {
+	    cmd |= PCI_COMMAND_MEMORY;
+	    pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
 	}
+    }
 
 #ifdef __BIG_ENDIAN
-	/* Use the big-endian aperture */
-	addr += 0x800000;
+    /* Use the big-endian aperture */
+    addr += 0x800000;
 #endif
 
-	/* Map in frame buffer */
-	info->frame_buffer_phys = addr;
-	info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+    /* Map in frame buffer */
+    info->frame_buffer_phys = addr;
+    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
-	if (!aty_init(info, dp->full_name)) {
-	    kfree(info);
-	    return;
-	}
+    if (!aty_init(info, dp->full_name)) {
+	kfree(info);
+	return;
+    }
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-	if (!console_fb_info)
-	    console_fb_info = &info->fb_info;
+    if (!console_fb_info)
+	console_fb_info = &info->fb_info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
-    }
 }
 #endif /* CONFIG_FB_OF */
 
@@ -3074,7 +3096,12 @@
 		curblink = 0;
 	} else if (!strncmp(this_opt, "noaccel", 7)) {
 		noaccel = 1;
-	}
+	} else if (!strncmp(this_opt, "vram:", 5))
+		default_vram = simple_strtoul(this_opt+5, NULL, 0);
+	else if (!strncmp(this_opt, "pll:", 4))
+		default_pll = simple_strtoul(this_opt+4, NULL, 0);
+	else if (!strncmp(this_opt, "mclk:", 5))
+		default_mclk = simple_strtoul(this_opt+5, NULL, 0);
 #if defined(CONFIG_PPC)
 	else if (!strncmp(this_opt, "vmode:", 6)) {
 	    unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- v2.1.128/linux/drivers/video/chipsfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/chipsfb.c	Fri Nov 13 10:10:11 1998
@@ -480,7 +480,7 @@
 	{ 0x0b, 0x11 },
 	{ 0x10, 0x0c },
 	{ 0x11, 0xe0 },
-	{ 0x12, 0x40 },
+	/* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */
 	{ 0x20, 0x63 },
 	{ 0x21, 0x68 },
 	{ 0x22, 0x19 },
diff -u --recursive --new-file v2.1.128/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.1.128/linux/drivers/video/clgenfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/clgenfb.c	Fri Nov 13 10:10:11 1998
@@ -89,6 +89,9 @@
     int btype;
     int smallboard;
     unsigned char SFR; /* Shadow of special function register */
+
+    unsigned long fbmem_phys;
+    unsigned long fbregs_phys;
     
     struct clgenfb_par currentmode;
     union {
@@ -333,7 +336,7 @@
     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
     strcpy(fix->id, clgenfb_name);
 	
-    fix->smem_start	= (char*)_info->fbmem;
+    fix->smem_start	= (char*)_info->fbmem_phys;
     
     /* monochrome: only 1 memory plane */
     /* 8 bit and above: Use whole memory area */
@@ -346,7 +349,7 @@
     fix->ypanstep	= 1;
     fix->ywrapstep	= 0;
     fix->line_length	= _par->line_length;
-    fix->mmio_start	= (char *)_info->regs;
+    fix->mmio_start	= (char *)_info->fbregs_phys;
     fix->mmio_len	= 0x10000;
     fix->accel		= FB_ACCEL_NONE;
 
@@ -410,7 +413,7 @@
     
     /* use highest possible virtual resolution */
     if (_par->var.xres_virtual == -1 &&
-	_par->var.xres_virtual == -1)
+	_par->var.yres_virtual == -1)
     {
 	printk("clgen: using maximum available virtual resolution\n");
 	for (i=0; modes[i].xres != -1; i++)
@@ -1534,8 +1537,10 @@
 	                                      KERNELMAP_NOCACHE_SER, NULL);
         DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
 	fb_info->regs += 0x600000;
+	fb_info->fbregs_phys = board_addr + 0x600000;
 
-	fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216, 
+	fb_info->fbmem_phys = board_addr + 16777216;
+	fb_info->fbmem = kernel_map(fb_info->fbmem_phys, 16777216, 
 			      KERNELMAP_NOCACHE_SER, NULL);
 	DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
     }
@@ -1544,6 +1549,7 @@
         cd2 = zorro_get_board(key2);
         printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
 
+	fb_info->fbmem_phys = board_addr;
         if (board_addr > 0x01000000)
 	    fb_info->fbmem = kernel_map(board_addr, board_size, 
 				  KERNELMAP_NOCACHE_SER, NULL);
@@ -1552,6 +1558,7 @@
 
         /* set address for REG area of board */
 	fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr);
+	fb_info->fbregs_phys = (unsigned long) cd2->cd_BoardAddr;
 
         DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
 	DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.1.128/linux/drivers/video/controlfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/controlfb.c	Fri Nov 13 10:10:11 1998
@@ -59,6 +59,9 @@
 
 static int currcon = 0;
 static int switching = 0;
+static char fontname[40] __initdata = { 0 };
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 
 struct fb_par_control {
 	int	vmode, cmode;
@@ -102,7 +105,10 @@
  * Exported functions
  */
 void control_init(void);
+#ifdef CONFIG_FB_OF
 void control_of_init(struct device_node *dp);
+#endif
+void controlfb_setup(char *options, int *ints);
 
 static int control_open(struct fb_info *info, int user);
 static int control_release(struct fb_info *info, int user);
@@ -989,7 +995,7 @@
 	info->node = -1;	/* ??? danj */
 	info->fbops = &controlfb_ops;
 	info->disp = &p->disp;
-	info->fontname[0] = 0;
+	strcpy(info->fontname, fontname);
 	info->changevar = NULL;
 	info->switch_con = &controlfb_switch;
 	info->updatevar = &controlfb_updatevar;
@@ -1016,13 +1022,51 @@
 	}
 }
 
-#if 0
+/* Parse user speficied options (`video=controlfb:') */
 __initfunc(void controlfb_setup(char *options, int *ints))
 {
-    /* Parse user speficied options (`video=controlfb:') */
-	FUNCID;
+	char *this_opt;
+
+	if (!options || !*options)
+		return;
+
+	for (this_opt = strtok(options, ","); this_opt;
+	     this_opt = strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "font:", 5)) {
+			char *p;
+			int i;
+
+			p = this_opt +5;
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (!*p || *p == ' ' || *p == ',')
+					break;
+			memcpy(fontname, this_opt + 5, i);
+			fontname[i] = 0;
+		}
+		if (!strncmp(this_opt, "vmode:", 6)) {
+			int vmode = simple_strtoul(this_opt+6, NULL, 0);
+		if (vmode > 0 && vmode <= VMODE_MAX)
+			default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int depth = simple_strtoul(this_opt+6, NULL, 0);
+			switch (depth) {
+			 case 8:
+				default_cmode = CMODE_8;
+				break;
+			 case 15:
+			 case 16:
+				default_cmode = CMODE_16;
+				break;
+			 case 24:
+			 case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+		}
+	}
 }
 
+#if 0
 static int controlfb_pan_display(struct fb_var_screeninfo *var,
 			   struct controlfb_par *par,
 			   const struct fb_info *fb_info)
@@ -1037,5 +1081,4 @@
 
     return 0;
 }
-
 #endif
diff -u --recursive --new-file v2.1.128/linux/drivers/video/cvppcfb.c linux/drivers/video/cvppcfb.c
--- v2.1.128/linux/drivers/video/cvppcfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/cvppcfb.c	Sun Nov 15 09:52:27 1998
@@ -0,0 +1,606 @@
+/*
+ * CybervisionPPC (TVP4020) low level driver for the frame buffer device
+ *                          ^^^^^^^^^
+ *                          literally ;)
+ *
+ * Copyright (c) 1998 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) (v124)
+ * --------------------------------------------------------------------------
+ * based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven
+ * --------------------------------------------------------------------------
+ * TODO h/w parameters detect/modify, 8-bit CLUT, acceleration
+ * --------------------------------------------------------------------------
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+
+#define ISDIGIT(a) ((a)>='0' && (a)<='9')
+
+#undef CVPPCFB_MASTER_DEBUG
+#ifdef CVPPCFB_MASTER_DEBUG
+#define FBEGIN	if (usr_startup.debug>1)\
+			printk(__FUNCTION__ " {\n")
+#define FEND	if (usr_startup.debug>1)\
+			printk("} /* " __FUNCTION__ " */\n")
+#define DPRINTK(a,b...)	if (usr_startup.debug)\
+			printk("%s: " a, __FUNCTION__ , ## b)
+#else
+#define FBEGIN
+#define FEND
+#define DPRINTK(a,b...)
+#endif 
+
+static const char cvppcfb_name[16]="CybervisionPPC";
+
+struct cvppcfb_startup {		/* startup options */
+	char font[40];
+	u32 xres;
+	u32 yres;
+	u32 bpp;
+	unsigned long debug;
+	unsigned long YANW;			/* You Are Not Welcome */
+	struct fb_monspecs monitor;
+};
+static struct cvppcfb_startup usr_startup = {
+	"\0", 640, 480, 16, 0, 1, { 31, 32, 58, 62, 0 } };
+
+#define CVPPC_BASE	0xe0000000
+#define CVPPC_SIZE	0x00800000
+static char* video_base;	/* virtual address of board video memory */
+static unsigned long video_phys;/* physical address of board video memory */
+static u32 video_size;		/* size of board video memory */
+
+struct cvppcfb_par {		/* board parameters (sort of) */
+	u32 xres;
+	u32 yres;
+	u32 vxres;
+	u32 vyres;
+	u32 vxoff;
+	u32 vyoff;
+	u32 bpp;
+	u32 clock;
+	u32 sflags;
+	u32 left;
+	u32 right;
+	u32 top;
+	u32 bottom;
+	u32 hsynclen;
+	u32 vsynclen;
+};
+
+struct cvppcfb_info {
+	struct fb_info_gen gen;
+	struct cvppcfb_par current_par;
+	int current_par_valid;
+	struct display disp;
+	struct {
+		u8 transp;
+		u8 red;
+		u8 green;
+		u8 blue;
+	} palette[256];
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16 cmap16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+		u32 cmap32[16];
+#endif
+	} cmap;
+};
+static struct cvppcfb_info fb_info;
+
+/*
+ * declaration of hw switch functions
+ */
+static void cvppcfb_detect(void);
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+				const void* par, struct fb_info_gen* info);
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+					void* par, struct fb_info_gen* info);
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+				const void* par, struct fb_info_gen* info);
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info);
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info);
+static int cvppcfb_getcolreg(unsigned regno,
+			unsigned* red, unsigned* green, unsigned* blue,
+				unsigned* transp, struct fb_info* info);
+static int cvppcfb_setcolreg(unsigned regno,
+			unsigned red, unsigned green, unsigned blue,
+				unsigned transp, struct fb_info* info);
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+						struct fb_info_gen* info);
+
+static struct fbgen_hwswitch cvppcfb_hwswitch={
+	cvppcfb_detect, cvppcfb_encode_fix, cvppcfb_decode_var,
+	cvppcfb_encode_var, cvppcfb_get_par, cvppcfb_set_par,
+	cvppcfb_getcolreg, cvppcfb_setcolreg, NULL /* pan_display() */,
+	NULL /* blank() */, cvppcfb_dispsw
+};
+
+/*
+ * declaration of ops switch functions
+ */
+static int cvppcfb_open(struct fb_info* info, int user);
+static int cvppcfb_release(struct fb_info* info, int user);
+
+static struct fb_ops cvppcfb_ops={
+	cvppcfb_open, cvppcfb_release, fbgen_get_fix, fbgen_get_var,
+	fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display,
+	fbgen_ioctl, NULL /* fb_mmap() */
+};
+
+/*
+ * the actual definition of the above mentioned functions follows
+ */
+
+/*
+ * private functions
+ */
+
+static void cvppcfb_set_modename(struct cvppcfb_info* info,
+						struct cvppcfb_startup* s) {
+
+	strcpy(info->gen.info.modename, cvppcfb_name);
+}
+
+static void cvppcfb_decode_opt(struct cvppcfb_startup* s, void* par,
+						struct cvppcfb_info* info) {
+	struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+
+	memset(p, 0, sizeof(struct cvppcfb_par));
+	p->xres=p->vxres=(s->xres+7)&~7;
+	p->yres=p->vyres=s->yres;
+	p->bpp=(s->bpp+7)&~7;
+	if (p->bpp==24)
+		p->bpp=32;
+	if (p->bpp<32)
+		p->clock=6666;
+	else
+		p->clock=10000;
+}
+
+static void cvppcfb_encode_mcap(char* options, struct fb_monspecs* mcap) {
+	char* next;
+	int i=0;
+
+	while (i<4 && options) {
+		if ((next=strchr(options, ';')))
+			*(next++)='\0';
+		switch (i++) {
+			case 0:				/* vmin */
+				mcap->vfmin=(__u16 )
+					simple_strtoul(options, NULL, 0);
+				break;
+			case 1:				/* vmax */
+				mcap->vfmax=(__u16 )
+					simple_strtoul(options, NULL, 0);
+				break;
+			case 2:				/* hmin */
+				mcap->hfmin=(__u32 )
+					simple_strtoul(options, NULL, 0);
+				break;
+			case 3:				/* hmax */
+				mcap->hfmax=(__u32 )
+					simple_strtoul(options, NULL, 0);
+				break;
+		}
+		options=next;
+	}
+}
+
+static void cvppcfb_encode_mode(char* options, struct cvppcfb_startup* s) {
+	char* next;
+	int i=0;
+
+	while (i<3 && options) {
+		if ((next=strchr(options, ';')))
+			*(next++)='\0';
+		switch (i++) {
+			case 0:
+				s->xres=(u32 )
+					simple_strtoul(options, NULL, 0);
+				break;
+			case 1:
+				s->yres=(u32 )
+					simple_strtoul(options, NULL, 0);
+				break;
+			case 2:
+				s->bpp=(u32 )
+					simple_strtoul(options, NULL, 0);
+				break;
+		}
+		options=next;
+	}
+}
+
+/*
+ * protected functions
+ */
+
+static void cvppcfb_detect(void) {
+
+	FBEGIN;
+	FEND;
+}
+
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+			const void* par, struct fb_info_gen* info) {
+
+	FBEGIN;
+	strcpy(fix->id, cvppcfb_name);
+	fix->smem_start=(char* )video_phys;
+	fix->smem_len=(__u32 )video_size;
+	fix->type=FB_TYPE_PACKED_PIXELS;
+	if (((struct cvppcfb_par* )par)->bpp==8)
+		fix->visual=FB_VISUAL_PSEUDOCOLOR;
+	else
+		fix->visual=FB_VISUAL_TRUECOLOR;
+	fix->xpanstep=fix->ypanstep=fix->ywrapstep=0;
+	fix->line_length=0;			/* computed by fbcon */
+	fix->mmio_start=NULL;
+	fix->mmio_len=0;
+	fix->accel=FB_ACCEL_NONE;
+	FEND;
+	return 0;
+}
+
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+				void* par, struct fb_info_gen* info) {
+	struct cvppcfb_par p;
+
+	FBEGIN;
+	memset(&p, 0, sizeof(struct cvppcfb_par));
+	p.bpp=(var->bits_per_pixel+7)&~7;
+	if (p.bpp==24)
+		p.bpp=32;
+	if (p.bpp>32) {
+		DPRINTK("depth too big (%lu)\n", p.bpp);
+		return -EINVAL;
+	}
+	p.xres=(var->xres+7)&~7;
+	p.yres=var->yres;
+	if (p.xres<320 || p.yres<200 || p.xres>2048 || p.yres>2048) {
+		DPRINTK("bad resolution (%lux%lu)\n", p.xres, p.yres);
+		return -EINVAL;
+	}
+	p.vxres=(var->xres_virtual+7)&~7;
+	p.vxoff=(var->xoffset+7)&~7;
+	p.vyres=var->yres_virtual;
+	p.vyoff=var->yoffset;
+	if (p.vxres<p.xres+p.vxoff)
+		p.vxres=p.xres+p.vxoff;
+	if (p.vyres<p.yres+p.vyoff)
+		p.vyres=p.yres+p.vyoff;
+	if (p.vxres*p.vyres*p.bpp/8>video_size) {
+		DPRINTK("no memory for screen (%lux%lux%lu)\n",
+						p.vxres, p.vyres, p.bpp);
+		return -EINVAL;
+	}
+	p.sflags=var->sync&(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT);
+	p.clock=var->pixclock;
+	if (p.clock<6666) {
+		DPRINTK("pixclock too fast (%lu)\n", p.clock);
+		return -EINVAL;
+	}
+	p.left=var->left_margin;
+	p.top=var->upper_margin;
+	p.right=var->right_margin;
+	p.bottom=var->lower_margin;
+	p.hsynclen=var->hsync_len;
+	p.vsynclen=var->vsync_len;
+	*((struct cvppcfb_par* )par)=p;
+	FEND;
+	return 0;
+}
+
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+				const void* par, struct fb_info_gen* info) {
+	struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+	struct fb_var_screeninfo v;
+
+	FBEGIN;
+	memset(&v, 0, sizeof(struct fb_var_screeninfo));
+	v.xres=p->xres;
+	v.yres=p->yres;
+	v.xres_virtual=p->vxres;
+	v.yres_virtual=p->vyres;
+	v.xoffset=p->vxoff;
+	v.yoffset=p->vyoff;
+	v.bits_per_pixel=p->bpp;
+	switch (p->bpp) {
+		case 16:
+			v.red.offset=11;
+			v.red.length=5;
+			v.green.offset=5;
+			v.green.length=6;
+			v.blue.length=5;
+			break;
+		case 32:
+			v.transp.offset=24;
+			v.red.offset=16;
+			v.green.offset=8;
+			v.transp.length=8;
+			/* fallback */
+		case 8:
+			v.red.length=v.green.length=v.blue.length=8;
+			break;
+	}
+	v.activate=FB_ACTIVATE_NOW;
+	v.height=v.width=-1;
+	v.pixclock=p->clock;
+	v.left_margin=p->left;
+	v.right_margin=p->right;
+	v.upper_margin=p->top;
+	v.lower_margin=p->bottom;
+	v.hsync_len=p->hsynclen;
+	v.vsync_len=p->vsynclen;
+	v.sync=p->sflags;
+	v.vmode=FB_VMODE_NONINTERLACED;
+	*var=v;
+	FEND;
+	return 0;
+}
+
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info) {
+	struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+	
+	FBEGIN;
+	if (i->current_par_valid)
+		*((struct cvppcfb_par* )par)=i->current_par;
+	else
+		cvppcfb_decode_opt(&usr_startup, par, i);
+	FEND;
+}
+
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info) {
+	struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+	FBEGIN;
+	i->current_par=*((struct cvppcfb_par* )par);
+	i->current_par_valid=1;
+	FEND;
+}
+
+static int cvppcfb_getcolreg(unsigned regno,
+			unsigned* red, unsigned* green, unsigned* blue,
+				unsigned* transp, struct fb_info* info) {
+	struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+	if (regno<256) {
+		*red=i->palette[regno].red<<8|i->palette[regno].red;
+		*green=i->palette[regno].green<<8|i->palette[regno].green;
+		*blue=i->palette[regno].blue<<8|i->palette[regno].blue;
+		*transp=i->palette[regno].transp<<8|i->palette[regno].transp;
+	}
+	return regno>255;
+}
+
+static int cvppcfb_setcolreg(unsigned regno,
+			unsigned red, unsigned green, unsigned blue,
+				unsigned transp, struct fb_info* info) {
+	struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+	if (regno<16) {
+		switch (i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+			case 8:
+				DPRINTK("8 bit depth not supported yet.\n");
+				return 1;
+#endif
+#ifdef FBCON_HAS_CFB16
+			case 16:
+				i->cmap.cmap16[regno]=
+					((u32 )red & 0xf800) |
+					(((u32 )green & 0xfc00)>>5) |
+					(((u32 )blue & 0xf800)>>11);
+				break;
+#endif
+#ifdef FBCON_HAS_CFB32
+			case 32:
+	   			i->cmap.cmap32[regno]=
+					(((u32 )transp & 0xff00) << 16) |
+		    			(((u32 )red & 0xff00) << 8) |
+					(((u32 )green & 0xff00)) |
+			 		(((u32 )blue & 0xff00) >> 8);
+				break;
+#endif
+		}
+	}
+	if (regno<256) {
+		i->palette[regno].red=red >> 8;
+		i->palette[regno].green=green >> 8;
+		i->palette[regno].blue=blue >> 8;
+		i->palette[regno].transp=transp >> 8;
+	}
+	return regno>255;
+}
+
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+						struct fb_info_gen* info) {
+	struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+	unsigned long flags;
+
+	FBEGIN;
+	save_flags(flags);
+	cli();
+	switch (((struct cvppcfb_par* )par)->bpp) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			disp->dispsw=&fbcon_cfb8;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16:
+			disp->dispsw=&fbcon_cfb16;
+			disp->dispsw_data=i->cmap.cmap16;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32:
+			disp->dispsw=&fbcon_cfb32;
+			disp->dispsw_data=i->cmap.cmap32;
+			break;
+#endif
+		default:
+			disp->dispsw=&fbcon_dummy;
+			break;
+	}
+	restore_flags(flags);
+	FEND;
+}
+
+static int cvppcfb_open(struct fb_info* info, int user) {
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int cvppcfb_release(struct fb_info* info, int user) {
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * public functions
+ */
+
+void cvppcfb_cleanup(struct fb_info* info) {
+
+	unregister_framebuffer(info);
+}
+
+__initfunc(void cvppcfb_init(void)) {
+
+	FBEGIN;
+#ifdef CVPPCFB_MASTER_DEBUG
+	printk("cvppcfb_init():\n");
+	printk("    resolution %ldx%ldx%ld\n", usr_startup.xres,
+					usr_startup.yres, usr_startup.bpp);
+	printk("    debug: %ld, YANW: %ld\n", usr_startup.debug,
+						usr_startup.YANW);
+	printk("    monitorcap: %ld,%ld,%ld,%ld\n",
+			usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+			usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+	if (usr_startup.YANW)			/* cannot probe yet */
+		return;
+	memset(&fb_info, 0, sizeof(struct cvppcfb_info));
+	video_size=CVPPC_SIZE;
+	video_phys=CVPPC_BASE;
+#ifdef CONFIG_APUS
+	video_base=(char* )
+		kernel_map(video_phys, video_size, KERNELMAP_NOCACHE_SER, NULL);
+#else
+	video_base=ioremap(video_phys, video_size);
+#endif
+	DPRINTK("video_phys=%08lx, video_base=%08lx\n", video_phys, video_base);
+	DPRINTK("phys_to_virt(video_phys)=%08lx\n", phys_to_virt(video_phys));
+	DPRINTK("virt_to_phys(video_base)=%08lx\n", virt_to_phys(video_base));
+	fb_info.disp.scrollmode=SCROLL_YREDRAW;
+	fb_info.gen.parsize=sizeof(struct cvppcfb_par);
+	fb_info.gen.fbhw=&cvppcfb_hwswitch;
+	cvppcfb_set_modename(&fb_info, &usr_startup);
+	fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
+	fb_info.gen.info.fbops=&cvppcfb_ops;
+	fb_info.gen.info.monspecs=usr_startup.monitor;
+	fb_info.gen.info.disp=&fb_info.disp;
+	strcpy(fb_info.gen.info.fontname, usr_startup.font);
+	fb_info.gen.info.switch_con=&fbgen_switch;
+	fb_info.gen.info.updatevar=&fbgen_update_var;
+	fb_info.gen.info.blank=&fbgen_blank;
+	fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
+	if (fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen)<0) {
+		printk(	"cvppcfb: bad startup configuration: "
+			"unable to register.\n");
+		return;
+	}
+	fbgen_set_disp(-1, &fb_info.gen);
+	fbgen_install_cmap(0, &fb_info.gen);
+	if (register_framebuffer(&fb_info.gen.info)<0) {
+		printk("cvppcfb: unable to register.\n");
+		return;
+	}
+	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+		GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename,
+					(unsigned long )(video_size>>10));
+	MOD_INC_USE_COUNT;
+	FEND;
+}
+
+__initfunc(void cvppcfb_setup(char* options, int* ints)) {
+	char* next;
+
+	usr_startup.YANW=0;
+	DPRINTK("options: '%s'\n", options);
+	while (options) {
+		if ((next=strchr(options, ',')))
+			*(next++)='\0';
+		if (!strncmp(options, "monitorcap:", 11))
+			cvppcfb_encode_mcap(options+11, &usr_startup.monitor);
+		else if (!strncmp(options, "debug:", 6)) {
+			if (ISDIGIT(options[6]))
+				usr_startup.debug=options[6]-'0';
+			else
+				usr_startup.debug=1;
+		}
+		else if (!strncmp(options, "mode:", 5))
+			cvppcfb_encode_mode(options+5, &usr_startup);
+		else if (!strncmp(options, "font:", 5))
+			strcpy(usr_startup.font, options+5);
+		else
+			DPRINTK("unrecognized option '%s'\n", options);
+		options=next;
+	}
+#ifdef CVPPCFB_MASTER_DEBUG
+	printk("cvppcfb_setup():\n");
+	printk("    resolution %ldx%ldx%ld\n", usr_startup.xres,
+					usr_startup.yres, usr_startup.bpp);
+	printk("    debug: %ld, YANW: %ld\n", usr_startup.debug,
+						usr_startup.YANW);
+	printk("    monitorcap: %ld,%ld,%ld,%ld\n",
+			usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+			usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+}
+
+/*
+ * modularization
+ */
+
+#ifdef MODULE
+int init_module(void) {
+
+	cvppcfb_init();
+}
+
+void cleanup_module(void) {
+
+	cvppcfb_cleanup();
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.1.128/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.1.128/linux/drivers/video/cyberfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/cyberfb.c	Fri Nov 13 10:10:11 1998
@@ -122,6 +122,8 @@
 static unsigned long CyberMem;
 static unsigned long CyberSize;
 static volatile char *CyberRegs;
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
  
 
 /*
@@ -178,6 +180,13 @@
 	    0, 0, -1, -1, FB_ACCELF_TEXT, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	}
+    }, {
+	"1024x768-16", {         /* Cybervision 16 bpp */
+	    1024, 768, 1024, 768, 0, 0, 16, 0,
+	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+	    0, 0, -1, -1, 0, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+       }
     }
 };
 
@@ -372,9 +381,9 @@
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, cyberfb_name);
-	fix->smem_start = (char *)CyberMem;
+	fix->smem_start = (char*) CyberMem_phys;
 	fix->smem_len = CyberSize;
-	fix->mmio_start = (char *)CyberRegs;
+	fix->mmio_start = (char*) CyberRegs_phys;
 	fix->mmio_len = 0x10000;
 
 	fix->type = FB_TYPE_PACKED_PIXELS;
@@ -846,7 +855,7 @@
 	cyberfb_get_fix(&fix, con, info);
 	if (con == -1)
 		con = 0;
-	display->screen_base = fix.smem_start;
+	display->screen_base = (char*) CyberMem;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -1030,7 +1039,9 @@
 	board_addr = (unsigned long)cd->cd_BoardAddr;
 
 	/* This includes the video memory as well as the S3 register set */
-	CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
+	CyberMem_phys = board_addr + 0x01400000;
+	CyberRegs_phys = CyberMem_phys + 0x00c00000;
+	CyberMem = kernel_map (CyberMem_phys, 0x01000000,
 			       KERNELMAP_NOCACHE_SER, NULL);
 	CyberRegs = (char*) (CyberMem + 0x00c00000);
 
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- v2.1.128/linux/drivers/video/fbcon-iplan2p2.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/fbcon-iplan2p2.c	Fri Nov 13 10:10:11 1998
@@ -368,6 +368,30 @@
     }
 }
 
+void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p,
+				  int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+	lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+	offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+	lines = p->var.yres - conp->vc_rows * fontheight(p);
+	offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+	cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
+	memset_even_2p(p->screen_base+offset, lines * bytes, cval);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -376,7 +400,7 @@
 struct display_switch fbcon_iplan2p2 = {
     fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear,
     fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p2_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -402,3 +426,4 @@
 EXPORT_SYMBOL(fbcon_iplan2p2_putc);
 EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p2_revc);
+EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- v2.1.128/linux/drivers/video/fbcon-iplan2p4.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/fbcon-iplan2p4.c	Fri Nov 13 10:10:11 1998
@@ -388,6 +388,30 @@
     }
 }
 
+void fbcon_iplan2p4_clear_margins(struct vc_data *conp, struct display *p,
+				  int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval1, cval2;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+	lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+	offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+	lines = p->var.yres - conp->vc_rows * fontheight(p);
+	offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+	expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
+	memset_even_4p(p->screen_base+offset, lines * bytes, cval1, cval2);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -396,7 +420,7 @@
 struct display_switch fbcon_iplan2p4 = {
     fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear,
     fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p4_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -422,3 +446,4 @@
 EXPORT_SYMBOL(fbcon_iplan2p4_putc);
 EXPORT_SYMBOL(fbcon_iplan2p4_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p4_revc);
+EXPORT_SYMBOL(fbcon_iplan2p4_clear_margins);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- v2.1.128/linux/drivers/video/fbcon-iplan2p8.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/fbcon-iplan2p8.c	Fri Nov 13 10:10:11 1998
@@ -425,6 +425,31 @@
     }
 }
 
+void fbcon_iplan2p8_clear_margins(struct vc_data *conp, struct display *p,
+				  int bottom_only)
+{
+    u32 offset;
+    int bytes;
+    int lines;
+    u32 cval1, cval2, cval3, cval4;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+    bytes = p->next_line;
+    if (fontheightlog(p)) {
+	lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+	offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+    } else {
+	lines = p->var.yres - conp->vc_rows * fontheight(p);
+	offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+    }
+    if (lines) {
+	expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4);
+	memset_even_8p(p->screen_base+offset, lines * bytes,
+		       cval1, cval2, cval3, cval4);
+    }
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -433,7 +458,7 @@
 struct display_switch fbcon_iplan2p8 = {
     fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear,
     fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc, NULL,
-    NULL, NULL, FONTWIDTH(8)
+    NULL, fbcon_iplan2p8_clear_margins, FONTWIDTH(8)
 };
 
 
@@ -459,3 +484,4 @@
 EXPORT_SYMBOL(fbcon_iplan2p8_putc);
 EXPORT_SYMBOL(fbcon_iplan2p8_putcs);
 EXPORT_SYMBOL(fbcon_iplan2p8_revc);
+EXPORT_SYMBOL(fbcon_iplan2p8_clear_margins);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- v2.1.128/linux/drivers/video/fbcon-mfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/fbcon-mfb.c	Fri Nov 13 10:10:11 1998
@@ -66,7 +66,7 @@
 {
     u8 *dest;
     u_int rows;
-    int inverse = conp ? attr_reverse(p,conp->vc_attr) : 0;
+    int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
 
     dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
 
@@ -148,6 +148,28 @@
 	*dest = ~*dest;
 }
 
+void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
+			     int bottom_only)
+{
+    u8 *dest;
+    int height, bottom;
+    int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+    /* XXX Need to handle right margin? */
+
+    height = p->var.yres - conp->vc_rows * fontheight(p);
+    if (!height)
+	return;
+    bottom = conp->vc_rows + p->yscroll;
+    if (bottom >= p->vrows)
+	bottom -= p->vrows;
+    dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+    if (inverse)
+	mymemset(dest, height * p->next_line);
+    else
+	mymemclear(dest, height * p->next_line);
+}
+
 
     /*
      *  `switch' for the low level operations
@@ -155,7 +177,8 @@
 
 struct display_switch fbcon_mfb = {
     fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc,
-    fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, fbcon_mfb_clear_margins,
+    FONTWIDTH(8)
 };
 
 
@@ -181,3 +204,4 @@
 EXPORT_SYMBOL(fbcon_mfb_putc);
 EXPORT_SYMBOL(fbcon_mfb_putcs);
 EXPORT_SYMBOL(fbcon_mfb_revc);
+EXPORT_SYMBOL(fbcon_mfb_clear_margins);
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbgen.c linux/drivers/video/fbgen.c
--- v2.1.128/linux/drivers/video/fbgen.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/fbgen.c	Fri Nov 13 10:10:11 1998
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 
 static int currcon = 0;
@@ -243,7 +244,7 @@
     memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
     fbhw->encode_fix(&fix, &par, info);
 
-    display->screen_base = fix.smem_start;
+    display->screen_base = phys_to_virt((unsigned long)fix.smem_start);
     display->visual = fix.visual;
     display->type = fix.type;
     display->type_aux = fix.type_aux;
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.1.128/linux/drivers/video/fbmem.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/video/fbmem.c	Fri Nov 13 10:10:11 1998
@@ -29,7 +29,7 @@
 #include <linux/kmod.h>
 #endif
 
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 #include <asm/setup.h>
 #endif
 #ifdef __powerpc__
@@ -56,6 +56,8 @@
 extern void macfb_setup(char *options, int *ints);
 extern void cyberfb_init(void);
 extern void cyberfb_setup(char *options, int *ints);
+extern void cvppcfb_init(void);
+extern void cvppcfb_setup(char *options, int *ints);
 extern void retz3fb_init(void);
 extern void retz3fb_setup(char *options, int *ints);
 extern void clgenfb_init(void);
@@ -69,6 +71,7 @@
 extern void igafb_init(void);
 extern void igafb_setup(char *options, int *ints);
 extern void imsttfb_init(void);
+extern void imsttfb_setup(char *options, int *ints);
 extern void dnfb_init(void);
 extern void tgafb_init(void);
 extern void virgefb_init(void);
@@ -78,6 +81,8 @@
 extern void s3triofb_setup(char *options, int *ints);
 extern void vesafb_init(void);
 extern void vesafb_setup(char *options, int *ints);
+extern void matroxfb_init(void);
+extern void matroxfb_setup(char* options, int *ints);
 extern void hpfb_init(void);
 extern void hpfb_setup(char *options, int *ints);
 extern void sbusfb_init(void);
@@ -109,12 +114,18 @@
 #ifdef CONFIG_FB_CYBER
 	{ "cyber", cyberfb_init, cyberfb_setup },
 #endif
+#ifdef CONFIG_FB_CVPPC
+	{ "cvppcfb", cvppcfb_init, cvppcfb_setup },
+#endif
 #ifdef CONFIG_FB_CLGEN
 	{ "clgen", clgenfb_init, clgenfb_setup },
 #endif
 #ifdef CONFIG_FB_OF
 	{ "offb", offb_init, offb_setup },
 #endif
+#ifdef CONFIG_FB_SBUS
+	{ "sbus", sbusfb_init, sbusfb_setup },
+#endif
 #ifdef CONFIG_FB_ATY
 	{ "atyfb", atyfb_init, atyfb_setup },
 #endif
@@ -122,7 +133,7 @@
         { "igafb", igafb_init, igafb_setup },
 #endif
 #ifdef CONFIG_FB_IMSTT
-	{ "imsttfb", imsttfb_init, NULL },
+	{ "imsttfb", imsttfb_init, imsttfb_setup },
 #endif
 #ifdef CONFIG_APOLLO
 	{ "apollo", dnfb_init, NULL },
@@ -139,12 +150,12 @@
 #ifdef CONFIG_FB_VESA
 	{ "vesa", vesafb_init, vesafb_setup },
 #endif 
+#ifdef CONFIG_FB_MATROX
+	{ "matrox", matroxfb_init, matroxfb_setup },
+#endif
 #ifdef CONFIG_FB_HP300
 	{ "hpfb", hpfb_init, hpfb_setup },
 #endif 
-#ifdef CONFIG_FB_SBUS
-	{ "sbus", sbusfb_init, sbusfb_setup },
-#endif
 #ifdef CONFIG_FB_VALKYRIE
 	{ "valkyriefb", valkyriefb_init, valkyriefb_setup },
 #endif
@@ -260,6 +271,23 @@
 }
 
 
+static int set_all_vcs(int fbidx, struct fb_ops *fb,
+		       struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    int unit, err;
+
+    var->activate |= FB_ACTIVATE_TEST;
+    err = fb->fb_set_var(var, PROC_CONSOLE(), info);
+    var->activate &= ~FB_ACTIVATE_TEST;
+    if (err)
+	    return err;
+    info->disp->var = *var;
+    for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+	    if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
+		    fb->fb_set_var(var, unit, info);
+    return 0;
+}
+
 static void set_con2fb_map(int unit, int newidx)
 {
     int oldidx = con2fb_map[unit];
@@ -334,7 +362,10 @@
 	case FBIOPUT_VSCREENINFO:
 		if (copy_from_user(&var, (void *) arg, sizeof(var)))
 			return -EFAULT;
-		if ((i = fb->fb_set_var(&var, PROC_CONSOLE(), info)))
+		i = var.activate & FB_ACTIVATE_ALL
+			    ? set_all_vcs(fbidx, fb, &var, info)
+			    : fb->fb_set_var(&var, PROC_CONSOLE(), info);
+		if (i)
 			return i;
 		if (copy_to_user((void *) arg, &var, sizeof(var)))
 			return -EFAULT;
diff -u --recursive --new-file v2.1.128/linux/drivers/video/fonts.c linux/drivers/video/fonts.c
--- v2.1.128/linux/drivers/video/fonts.c	Mon Oct  5 13:13:42 1998
+++ linux/drivers/video/fonts.c	Fri Nov 13 10:10:12 1998
@@ -90,7 +90,7 @@
     for(i=0; i<num_fonts; i++) {
 	f = fbcon_fonts[i];
 	c = f->pref;
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 #ifdef CONFIG_FONT_PEARL_8x8
 	if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
 	    c = 100;
diff -u --recursive --new-file v2.1.128/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.1.128/linux/drivers/video/imsttfb.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/video/imsttfb.c	Fri Nov 13 10:10:12 1998
@@ -130,17 +130,17 @@
 	CLKCTL		= 0x02,	/* (0x01) Miscellaneous Clock Control */
 	SYNCCTL		= 0x03,	/* (0x00) Sync Control */
 	HSYNCPOS	= 0x04,	/* (0x00) Horizontal Sync Position */
-	PWRMNGMT	= 0x05,	/* (0x00) Power Management  [multiples of 4 unblack screen] */
-	DACOP		= 0x06,	/* (0x02) DAC Operation  [0-3 coloured, 4-7 green, odd light, even dark] */
+	PWRMNGMT	= 0x05,	/* (0x00) Power Management */
+	DACOP		= 0x06,	/* (0x02) DAC Operation */
 	PALETCTL	= 0x07,	/* (0x00) Palette Control */
 	SYSCLKCTL	= 0x08,	/* (0x01) System Clock Control */
 	PIXFMT		= 0x0a,	/* () Pixel Format  [bpp >> 3 + 2] */
 	BPP8		= 0x0b,	/* () 8 Bits/Pixel Control */
-	BPP16		= 0x0c, /* () 16 Bits/Pixel Control  [15 or 1 for 555] */
+	BPP16		= 0x0c, /* () 16 Bits/Pixel Control  [bit 1=1 for 565] */
 	BPP24		= 0x0d,	/* () 24 Bits/Pixel Control */
 	BPP32		= 0x0e,	/* () 32 Bits/Pixel Control */
-	PIXCTL1		= 0x10, /* (0x05) Pixel PLL Control 1  [5-7 ok] */
-	PIXCTL2		= 0x11,	/* (0x00) Pixel PLL Control 2  [multiples of 20 ok] */
+	PIXCTL1		= 0x10, /* (0x05) Pixel PLL Control 1 */
+	PIXCTL2		= 0x11,	/* (0x00) Pixel PLL Control 2 */
 	SYSCLKN		= 0x15,	/* () System Clock N (System PLL Reference Divider) */
 	SYSCLKM		= 0x16,	/* () System Clock M (System PLL VCO Divider) */
 	SYSCLKP		= 0x17,	/* () System Clock P */
@@ -149,18 +149,19 @@
 	 * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
 	 * c is charge pump bias which depends on the VCO frequency  
 	 */
-	PIXCLKM		= 0x20,	/* () Pixel Clock M */
-	PIXCLKN		= 0x21,	/* () Pixel Clock N */
-	PIXCLKP		= 0x22,	/* () Pixel Clock P */
-	PIXCLKC		= 0x23,	/* () Pixel Clock C */
-	CURSCTL		= 0x30,	/* (0x00) Cursor Control  [1=curs1, 2=curs2, 5=curs3] */
+	PIXM0		= 0x20,	/* () Pixel M 0 */
+	PIXN0		= 0x21,	/* () Pixel N 0 */
+	PIXP0		= 0x22,	/* () Pixel P 0 */
+	PIXC0		= 0x23,	/* () Pixel C 0 */
+	CURSCTL		= 0x30,	/* (0x00) Cursor Control */
 	CURSXLO		= 0x31,	/* () Cursor X position, low 8 bits */
 	CURSXHI		= 0x32,	/* () Cursor X position, high 8 bits */
 	CURSYLO		= 0x33,	/* () Cursor Y position, low 8 bits */
 	CURSYHI		= 0x34,	/* () Cursor Y position, high 8 bits */
-	CURSHOTX	= 0x35,	/* () ???  [position relative to CURSX] */
-	CURSHOTY	= 0x36,	/* () ???  [position relative to CURSY] */
-	CURSACAEN	= 0x37,	/* () ???  [even=cursor on, odd=cursor off] */
+	CURSHOTX	= 0x35,	/* () Cursor Hot Spot X */
+	CURSHOTY	= 0x36,	/* () Cursor Hot Spot Y */
+	CURSACCTL	= 0x37,	/* () Advanced Cursor Control Enable */
+	CURSACATTR	= 0x38,	/* () Advanced Cursor Attribute */
 	CURS1R		= 0x40,	/* () Cursor 1 Red */
 	CURS1G		= 0x41,	/* () Cursor 1 Green */
 	CURS1B		= 0x42,	/* () Cursor 1 Blue */
@@ -238,7 +239,7 @@
 	__u8 addr, value;
 };
 
-static struct initvalues ibm_initregs[] = {
+static struct initvalues ibm_initregs[] __initdata = {
 	{ CLKCTL,	0x21 },
 	{ SYNCCTL,	0x00 },
 	{ HSYNCPOS,	0x00 },
@@ -264,10 +265,18 @@
 	{ SYSCLKM,	0x4f },
 	{ SYSCLKP,	0x00 },
 	{ SYSCLKC,	0x00 },
-	{ CURSCTL,	0x00 },
+	{ CURSCTL,	0x02 },
+	{ CURSACCTL,	0x01 },
+	{ CURSACATTR,	0xa8 },
+	{ CURS1R,	0xff },
+	{ CURS1G,	0xff },
+	{ CURS1B,	0xff },
 	{ CURS2R,	0xff },
 	{ CURS2G,	0xff },
 	{ CURS2B,	0xff },
+	{ CURS3R,	0xff },
+	{ CURS3G,	0xff },
+	{ CURS3B,	0xff },
 	{ BORDR,	0xff },
 	{ BORDG,	0xff },
 	{ BORDB,	0xff },
@@ -277,7 +286,7 @@
 	{ KEYCTL,	0x00 }
 };
 
-static struct initvalues tvp_initregs[] = {
+static struct initvalues tvp_initregs[] __initdata = {
 	{ 0x6,	0x00 },
 	{ 0x7,	0xe4 },
 	{ 0xf,	0x06 },
@@ -320,12 +329,12 @@
 };
 
 struct imstt_cursor {
+	struct timer_list timer;
 	int enable;
 	int on;
 	int vbl_cnt;
 	int blink_rate;
-	__u16 x, y;
-	struct timer_list timer;
+	__u16 x, y, width, height;
 };
 
 struct fb_info_imstt {
@@ -349,9 +358,9 @@
 	} palette[256];
 	struct imstt_regvals init;
 	struct imstt_cursor cursor;
-	__u8 *frame_buffer_phys, *frame_buffer;
-	__u32 *dc_regs_phys, *dc_regs;
-	__u8 *cmap_regs_phys, *cmap_regs;
+	volatile __u8 *frame_buffer_phys, *frame_buffer;
+	volatile __u32 *dc_regs_phys, *dc_regs;
+	volatile __u8 *cmap_regs_phys, *cmap_regs;
 	__u32 total_vram;
 	__u32 ramdac;
 };
@@ -364,6 +373,12 @@
 #define CURSOR_DRAW_DELAY	2
 
 static int currcon = 0;
+static char fontname[40] __initdata = { 0 };
+static char curblink __initdata = 1;
+static char noaccel __initdata = 0;
+#if defined(CONFIG_PPC)
+static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
+#endif
 
 static struct imstt_regvals tvp_reg_init_2 = {
 	512,
@@ -504,7 +519,7 @@
 
 	init->hes = hes;
 	init->heb = heb;
-	init->hsb = init->heb + xres / 8;
+	init->hsb = init->heb + (xres >> 3);
 	init->ht = init->hsb + htp;
 	init->ves = 0x0003;
 	init->veb = veb;
@@ -568,16 +583,15 @@
 	__u8 pformat = (bpp >> 3) + 2;
 
 	p->cmap_regs[PIDXHI] = 0;		eieio();
-	p->cmap_regs[PIDXLO] = PIXCLKM;		eieio();
+	p->cmap_regs[PIDXLO] = PIXM0;		eieio();
 	p->cmap_regs[PIDXDATA] = init->pclk_m;	eieio();
-	p->cmap_regs[PIDXLO] = PIXCLKN;		eieio();
+	p->cmap_regs[PIDXLO] = PIXN0;		eieio();
 	p->cmap_regs[PIDXDATA] = init->pclk_n;	eieio();
-	p->cmap_regs[PIDXLO] = PIXCLKP;		eieio();
+	p->cmap_regs[PIDXLO] = PIXP0;		eieio();
 	p->cmap_regs[PIDXDATA] = init->pclk_p;	eieio();
-	p->cmap_regs[PIDXLO] = PIXCLKC;		eieio();
+	p->cmap_regs[PIDXLO] = PIXC0;		eieio();
 	p->cmap_regs[PIDXDATA] = 0x02;		eieio();
 
-	p->cmap_regs[PIDXHI] = 0;		eieio();
 	p->cmap_regs[PIDXLO] = PIXFMT;		eieio();
 	p->cmap_regs[PIDXDATA] = pformat;	eieio();
 }
@@ -652,7 +666,7 @@
 set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
 {
 	struct imstt_regvals *init = &p->init;
-	__u32 ctl, pitch, byteswap, scr;
+	__u32 ctl, pitch, byteswap, scr, line_pitch = init->pitch * (bpp >> 3);
 
 	if (p->ramdac == IBM)
 		set_imstt_regvals_ibm(p, bpp);
@@ -674,23 +688,23 @@
 	switch (bpp) {
 		case 8:
 			ctl = 0x17b1;
-			pitch = init->pitch / 4;
-			byteswap = 0x0;
+			pitch = init->pitch >> 2;
+			byteswap = 0x000;
 			break;
 		case 16:
 			ctl = 0x17b3;
-			pitch = init->pitch / 2;
-			byteswap = 0x1;
+			pitch = init->pitch >> 1;
+			byteswap = 0x100;
 			break;
 		case 24:
 			ctl = 0x17b9;
-			pitch = init->pitch - (p->init.pitch / 4);
-			byteswap = 0x2;
+			pitch = init->pitch - (p->init.pitch >> 2);
+			byteswap = 0x200;
 			break;
 		case 32:
 			ctl = 0x17b5;
 			pitch = init->pitch;
-			byteswap = 0x3;
+			byteswap = 0x300;
 			break;
 	}
 	if (p->ramdac == TVP)
@@ -712,7 +726,6 @@
 	out_le32(&p->dc_regs[RRSC], 0x980);
 	out_le32(&p->dc_regs[RRCR], 0x11);
 
-	out_le32(&p->dc_regs[SSR], 0);
 	if (p->ramdac == IBM) {
 		out_le32(&p->dc_regs[HRIR], 0x0100);
 		out_le32(&p->dc_regs[CMR], 0x00ff);
@@ -725,20 +738,19 @@
 
 	switch (p->total_vram) {
 		case 0x00200000:
-			scr = 0x059d | (byteswap << 8);
+			scr = 0x059d | byteswap;
 			break;
 		case 0x00400000:
-			pitch /= 2;
-			scr = 0xd0dc | (byteswap << 8);
-			break;
 		case 0x00800000:
 			pitch /= 2;
-			scr = 0x150dd | (byteswap << 8);
+			scr = 0x150dd | byteswap;
 			break;
 	}
 
 	out_le32(&p->dc_regs[SCR], scr);
 	out_le32(&p->dc_regs[SPR], pitch);
+	out_le32(&p->dc_regs[SP], (line_pitch << 16) | line_pitch);
+	out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
 
 	out_le32(&p->dc_regs[STGCTL], ctl);
 }
@@ -755,8 +767,8 @@
 	}
 }
 
-#define set_555(_p)	set_16(_p, 15)
-#define set_565(_p)	set_16(_p, 0)	/* 220, 224 is darker in X */
+#define set_555(_p)	set_16(_p, 0x01)
+#define set_565(_p)	set_16(_p, 0x03)
 
 static void
 imstt_set_cursor (struct fb_info_imstt *p, int on)
@@ -765,19 +777,19 @@
 
 	p->cmap_regs[PIDXHI] = 0;
 	if (!on) {
-		p->cmap_regs[PIDXLO] = CURSCTL;
-		p->cmap_regs[PIDXDATA] = 0x00;
+		p->cmap_regs[PIDXLO] = CURSCTL;	eieio();
+		p->cmap_regs[PIDXDATA] = 0x00;	eieio();
 	} else {
-		p->cmap_regs[PIDXLO] = CURSXHI;
-		p->cmap_regs[PIDXDATA] = c->x >> 8;
-		p->cmap_regs[PIDXLO] = CURSXLO;
-		p->cmap_regs[PIDXDATA] = c->x & 0xff;
-		p->cmap_regs[PIDXLO] = CURSYHI;
-		p->cmap_regs[PIDXDATA] = c->y >> 8;
-		p->cmap_regs[PIDXLO] = CURSYLO;
-		p->cmap_regs[PIDXDATA] = c->y & 0xff;
-		p->cmap_regs[PIDXLO] = CURSCTL;
-		p->cmap_regs[PIDXDATA] = 0x02;
+		p->cmap_regs[PIDXLO] = CURSXHI;		eieio();
+		p->cmap_regs[PIDXDATA] = c->x >> 8;	eieio();
+		p->cmap_regs[PIDXLO] = CURSXLO;		eieio();
+		p->cmap_regs[PIDXDATA] = c->x & 0xff;	eieio();
+		p->cmap_regs[PIDXLO] = CURSYHI;		eieio();
+		p->cmap_regs[PIDXDATA] = c->y >> 8;	eieio();
+		p->cmap_regs[PIDXLO] = CURSYLO;		eieio();
+		p->cmap_regs[PIDXDATA] = c->y & 0xff;	eieio();
+		p->cmap_regs[PIDXLO] = CURSCTL;		eieio();
+		p->cmap_regs[PIDXDATA] = 0x02;		eieio();
 	}
 }
 
@@ -796,8 +808,8 @@
 	c->enable = 0;
 	if (c->on)
 		imstt_set_cursor(p, 0);
-	c->x = x;
-	c->y = y;
+	c->x = x - disp->var.xoffset;
+	c->y = y - disp->var.yoffset;
 
 	switch (mode) {
 		case CM_ERASE:
@@ -817,6 +829,28 @@
 static int
 imsttfb_set_font (struct display *disp, int width, int height)
 {
+	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
+	struct imstt_cursor *c = &p->cursor;
+	u_int x, y;
+
+	if (width > 32 || height > 32)
+		return -EINVAL;
+
+	c->height = height;
+	c->width = width;
+
+	p->cmap_regs[PIDXHI] = 1;	eieio();
+	for (x = 0; x < 0x100; x++) {
+		p->cmap_regs[PIDXLO] = x;	eieio();
+		p->cmap_regs[PIDXDATA] = 0x00;	eieio();
+	}
+	p->cmap_regs[PIDXHI] = 1;	eieio();
+	for (y = 0; y < height; y++)
+		for (x = 0; x < width >> 2; x++) {
+			p->cmap_regs[PIDXLO] = x + y * 8;	eieio();
+			p->cmap_regs[PIDXDATA] = 0xff;		eieio();
+		}
+
 	return 1;
 }
 
@@ -845,64 +879,59 @@
 {
 	struct imstt_cursor *c = &p->cursor;
 
+	imsttfb_set_font(&p->disp, fontwidth(&p->disp), fontheight(&p->disp));
+
 	c->enable = 1;
 	c->on = 1;
-	c->blink_rate = CURSOR_BLINK_RATE;
-	c->vbl_cnt = CURSOR_DRAW_DELAY;
 	c->x = c->y = 0;
+	c->blink_rate = 0;
+	c->vbl_cnt = CURSOR_DRAW_DELAY;
 
-	init_timer(&c->timer);
-	c->timer.expires = jiffies + (HZ / 50);
-	c->timer.data = (unsigned long)p;
-	c->timer.function = imstt_cursor_timer_handler;
-	add_timer(&c->timer);
+	if (curblink) {
+		c->blink_rate = CURSOR_BLINK_RATE;
+		init_timer(&c->timer);
+		c->timer.expires = jiffies + (HZ / 50);
+		c->timer.data = (unsigned long)p;
+		c->timer.function = imstt_cursor_timer_handler;
+		add_timer(&c->timer);
+	}
 }
 
 static void
 imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
-	__u32 cnt_reg, stat, xxx = 0;
-	__u32	line_pitch = disp->var.xres * (disp->var.bits_per_pixel >> 3),
-		rect_height = height,
-		rect_width = width * (disp->var.bits_per_pixel >> 3),
-		fb_offset_old = sy * line_pitch + (sx * (disp->var.bits_per_pixel >> 3)),
-		fb_offset_new = dy * line_pitch + (dx * (disp->var.bits_per_pixel >> 3));
+	__u32	Bpp = disp->var.bits_per_pixel >> 3,
+		line_pitch = disp->line_length,
+		fb_offset_old, fb_offset_new;
 
-	stat = in_le32(&p->dc_regs[SSTATUS]) & 0xff;
+	fb_offset_old = sy * line_pitch + sx * Bpp;
+	fb_offset_new = dy * line_pitch + dx * Bpp;
 
-	cnt_reg = ((rect_height - 1) << 16) | (rect_width - 1);
-	out_le32(&p->dc_regs[CNT], cnt_reg);
+	while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+	out_le32(&p->dc_regs[CNT], ((height - 1) << 16) | (width * Bpp - 1));
 	out_le32(&p->dc_regs[S1SA], fb_offset_old);
-	out_le32(&p->dc_regs[DSA], fb_offset_old);
-	out_le32(&p->dc_regs[SP], line_pitch);
-	out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
-	out_le32(&p->dc_regs[BLTCTL], 0x5);
-
-	if (++stat == 0x20)
-		stat = 0x10;
-	while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
-		eieio();
-
-	cnt_reg = ((rect_height - 1) << 16) | (0xffff - (rect_width - 2));
-	out_le32(&p->dc_regs[CNT], cnt_reg);
+	/* out_le32(&p->dc_regs[S2SA], fb_offset_new); */
 	out_le32(&p->dc_regs[DSA], fb_offset_new);
-#if 0
-	out_le32(&p->dc_regs[S1SA], fb_offset_old);
-	out_le32(&p->dc_regs[SP], line_pitch);
-	out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
-#endif
-	out_le32(&p->dc_regs[BLTCTL], 0x85);
-
-	if (++stat == 0x20)
-		stat = 0x10;
-	while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
-		eieio();
+	out_le32(&p->dc_regs[BLTCTL], 0xc0000005);
+	while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+	while (in_le32(&p->dc_regs[SSTATUS]) & 0x40);
 }
 
 static void
 imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
 {
+	/* XXX .. */
+	if (sy < dy || (sy == dy && sx < dx)) {
+		switch (disp->var.bits_per_pixel) {
+		case 8: fbcon_cfb8_bmove(disp, sy, sx, dy, dx, height, width); break;
+		case 16: fbcon_cfb16_bmove(disp, sy, sx, dy, dx, height, width); break;
+		case 24: fbcon_cfb24_bmove(disp, sy, sx, dy, dx, height, width); break;
+		case 32: fbcon_cfb32_bmove(disp, sy, sx, dy, dx, height, width); break;
+		}
+		return;
+	}
+
 	sy *= fontheight(disp);
 	sx *= fontwidth(disp);
 	dy *= fontheight(disp);
@@ -1020,7 +1049,7 @@
 	p->palette[regno].blue = blue;
 
 	/* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
-	if (p->ramdac == TVP && fb_display[currcon].var.green.length == 5 /* && bpp == 16 */) {
+	if (bpp == 16 && p->ramdac == TVP && fb_display[currcon].var.green.length == 5) {
 		p->cmap_regs[PADDRW] = regno << 3;	eieio();
 	} else {
 		p->cmap_regs[PADDRW] = regno;		eieio();
@@ -1100,12 +1129,10 @@
 }
 
 static void
-set_dispsw (struct display *disp, struct fb_info_imstt *p)
+set_disp (struct display *disp, struct fb_info_imstt *p)
 {
 	u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
 
-	disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
-					 	     : FB_VISUAL_DIRECTCOLOR;
 	p->dispsw = fbcon_dummy;
 	disp->dispsw = &p->dispsw;
 	disp->dispsw_data = 0;
@@ -1124,7 +1151,7 @@
 #endif
 			break;
 		case 16:	/* RGB 555 */
-			if (disp->var.red.offset != 11)
+			if (disp->var.green.length != 6)
 				disp->var.red.offset = 10;
 			disp->var.red.length = 5;
 			disp->var.green.offset = 5;
@@ -1173,6 +1200,47 @@
 		p->dispsw.cursor = imsttfb_cursor;
 		p->dispsw.set_font = imsttfb_set_font;
 	}
+
+	disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
+					 	     : FB_VISUAL_DIRECTCOLOR;
+	disp->screen_base = (__u8 *)p->frame_buffer;
+	disp->visual = p->fix.visual;
+	disp->type = p->fix.type;
+	disp->type_aux = p->fix.type_aux;
+	disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
+	disp->can_soft_blank = 1;
+	disp->inverse = 0;
+	disp->ypanstep = 1;
+	disp->ywrapstep = 0;
+	if (accel) {
+		disp->scrollmode = SCROLL_YNOMOVE;
+		if (disp->var.yres == disp->var.yres_virtual) {
+			__u32 vram = (p->total_vram - (PAGE_SIZE << 2));
+			disp->var.yres_virtual = ((vram << 3) / disp->var.bits_per_pixel) / disp->var.xres_virtual;
+			if (disp->var.yres_virtual < disp->var.yres)
+				disp->var.yres_virtual = disp->var.yres;
+		}
+	} else {
+		disp->scrollmode = SCROLL_YREDRAW;
+		disp->var.yoffset = disp->var.xoffset = 0;
+		out_le32(&p->dc_regs[SSR], 0);
+	}
+
+	disp->var.activate = 0;
+	disp->var.red.msb_right = 0;
+	disp->var.green.msb_right = 0;
+	disp->var.blue.msb_right = 0;
+	disp->var.transp.msb_right = 0;
+	disp->var.height = -1;
+	disp->var.width = -1;
+	disp->var.vmode = FB_VMODE_NONINTERLACED;
+	disp->var.left_margin = disp->var.right_margin = 16;
+	disp->var.upper_margin = disp->var.lower_margin = 16;
+	disp->var.hsync_len = disp->var.vsync_len = 8;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	set_display_info(disp);
+#endif
 }
 
 static int
@@ -1180,7 +1248,7 @@
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
 	struct display *disp;
-	u_int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
+	u_int oldbpp, oldxres, oldyres, oldgreenlen;
 
 	disp = &fb_display[con];
 
@@ -1205,37 +1273,16 @@
 	oldxres = disp->var.xres;
 	oldyres = disp->var.yres;
 	oldgreenlen = disp->var.green.length;
-	oldaccel = disp->var.accel_flags;
-
-	disp->var = *var;
-
-	disp->var.activate = 0;
-	disp->var.red.msb_right = 0;
-	disp->var.green.msb_right = 0;
-	disp->var.blue.msb_right = 0;
-	disp->var.transp.msb_right = 0;
-	disp->var.height = -1;
-	disp->var.width = -1;
-	disp->var.vmode = FB_VMODE_NONINTERLACED;
-	disp->var.left_margin = disp->var.right_margin = 16;
-	disp->var.upper_margin = disp->var.lower_margin = 16;
-	disp->var.hsync_len = disp->var.vsync_len = 8;
 
-	disp->screen_base = p->frame_buffer;
-	disp->inverse = 0;
-	disp->ypanstep = 1;
-	disp->ywrapstep = 0;
-	disp->scrollmode = SCROLL_YREDRAW;
+	disp->var.bits_per_pixel = var->bits_per_pixel;
+	disp->var.xres = var->xres;
+	disp->var.yres = var->yres;
+	disp->var.xres_virtual = var->xres_virtual;
+	disp->var.yres_virtual = var->yres_virtual;
+	disp->var.green.length = var->green.length;
+	disp->var.accel_flags = var->accel_flags;
 
-	if (oldbpp != disp->var.bits_per_pixel || oldgreenlen != disp->var.green.length || oldaccel != disp->var.accel_flags)
-		set_dispsw(disp, p);
-
-	if (oldxres != disp->var.xres || oldbpp != disp->var.bits_per_pixel)
-		disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-	set_display_info(disp);
-#endif
+	set_disp(disp, p);
 
 	if (info->changevar)
 		(*info->changevar)(con);
@@ -1267,17 +1314,18 @@
 imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
-	u_int off;
+	struct display *disp = &fb_display[con];
+	__u32 off;
 
-	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
-	    || var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+	if (var->xoffset + disp->var.xres > disp->var.xres_virtual
+	    || var->yoffset + disp->var.yres > disp->var.yres_virtual)
 		return -EINVAL;
 
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
+	disp->var.xoffset = var->xoffset;
+	disp->var.yoffset = var->yoffset;
 	if (con == currcon) {
-		off = var->yoffset * (fb_display[con].line_length / 8)
-		      + (var->xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
+		off = var->yoffset * (disp->line_length >> 3)
+		      + ((var->xoffset * (disp->var.bits_per_pixel >> 3)) >> 3);
 		out_le32(&p->dc_regs[SSR], off);
 	}
 
@@ -1321,8 +1369,8 @@
 #define FBIMSTT_GETREG		0x545402
 #define FBIMSTT_SETCMAPREG	0x545403
 #define FBIMSTT_GETCMAPREG	0x545404
-#define FBIMSTT_SETINITREG	0x545405
-#define FBIMSTT_GETINITREG	0x545406
+#define FBIMSTT_SETIDXREG	0x545405
+#define FBIMSTT_GETIDXREG	0x545406
 
 static int
 imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
@@ -1337,34 +1385,34 @@
 			if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
 			out_le32(&p->dc_regs[reg[0]], reg[1]);
-			break;
+			return 0;
 		case FBIMSTT_GETREG:
 			if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
 			reg[1] = in_le32(&p->dc_regs[reg[0]]);
 			if (copy_to_user((void *)(arg + 4), &reg[1], 4))
 				return -EFAULT;
-			break;
+			return 0;
 		case FBIMSTT_SETCMAPREG:
 			if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
 			out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]);
-			break;
+			return 0;
 		case FBIMSTT_GETCMAPREG:
 			if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
 				return -EFAULT;
 			reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]);
 			if (copy_to_user((void *)(arg + 4), &reg[1], 4))
 				return -EFAULT;
-			break;
-		case FBIMSTT_SETINITREG:
+			return 0;
+		case FBIMSTT_SETIDXREG:
 			if (copy_from_user(init, (void *)arg, 2))
 				return -EFAULT;
 			p->cmap_regs[PIDXHI] = 0;		eieio();
 			p->cmap_regs[PIDXLO] = init[0];		eieio();
 			p->cmap_regs[PIDXDATA] = init[1];	eieio();
-			break;
-		case FBIMSTT_GETINITREG:
+			return 0;
+		case FBIMSTT_GETIDXREG:
 			if (copy_from_user(init, (void *)arg, 1))
 				return -EFAULT;
 			p->cmap_regs[PIDXHI] = 0;		eieio();
@@ -1372,12 +1420,10 @@
 			init[1] = p->cmap_regs[PIDXDATA];
 			if (copy_to_user((void *)(arg + 1), &init[1], 1))
 				return -EFAULT;
-			break;
+			return 0;
 		default:
 			return -ENOIOCTLCMD;
 	}
-
-	return 0;
 }
 
 static struct fb_ops imsttfb_ops = {
@@ -1397,6 +1443,7 @@
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
 	struct display *old = &fb_display[currcon], *new = &fb_display[con];
+	__u32 off;
 
 	if (old->cmap.len)
 		fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
@@ -1410,7 +1457,7 @@
 	    || old->var.yres != new->var.yres
 	    || old->var.bits_per_pixel != new->var.bits_per_pixel
 	    || old->var.green.length != new->var.green.length) {
-		set_dispsw(new, p);
+		set_disp(new, p);
 		if (!compute_imstt_regvals(p, new->var.xres, new->var.yres))
 			return -1;
 		if (new->var.bits_per_pixel == 16) {
@@ -1420,9 +1467,11 @@
 				set_555(p);
 		}
 		set_imstt_regvals(p, new->var.bits_per_pixel);
-#ifdef CONFIG_FB_COMPAT_XPMAC
-		set_display_info(new);
-#endif
+	}
+	if (old->var.yoffset != new->var.yoffset || old->var.xoffset != new->var.xoffset) {
+		off = new->var.yoffset * (new->line_length >> 3)
+		      + ((new->var.xoffset * (new->var.bits_per_pixel >> 3)) >> 3);
+		out_le32(&p->dc_regs[SSR], off);
 	}
 
 	do_install_cmap(con, info);
@@ -1430,18 +1479,44 @@
 	return 0;
 }
 
+static inline void
+imsttfb_rectfill (struct display *disp, u_int sy, u_int sx, u_int height, u_int width, __u32 bgx)
+{
+	memset(disp->screen_base + sy + sx, bgx, height * width * (disp->var.bits_per_pixel >> 3));
+}
+
 static int
 imsttfbcon_updatevar (int con, struct fb_info *info)
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
-	u_int off;
+	struct display *disp = &fb_display[con];
+	struct vc_data *conp = disp->conp;
+	__u32 off, yres, yoffset, sy, height;
 
-	if (con == currcon) {
-		off = fb_display[con].var.yoffset * (fb_display[con].line_length / 8)
-		      + (fb_display[con].var.xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
-		out_le32(&p->dc_regs[SSR], off);
+	if (con != currcon)
+		goto out;
+
+	yres = disp->var.yres;
+	yoffset = disp->var.yoffset;
+	sy = (conp->vc_rows + disp->yscroll) * fontheight(disp);
+	height = yres - conp->vc_rows * fontheight(disp);
+
+	if (height && (yoffset + yres > sy)) {
+		__u32 bgx = attr_bgcol_ec(disp, conp);
+
+		if (sy + height > disp->var.yres_virtual)
+			printk("updatevar: %u + %u > %u\n", sy, height, disp->var.yres_virtual);
+		imsttfb_rectfill(disp, sy, disp->var.xoffset, height, disp->var.xres, bgx);
 	}
 
+	if (p->ramdac == IBM && (yoffset + yres <= sy))
+		imsttfb_cursor(disp, CM_ERASE, p->cursor.x, p->cursor.y);
+
+	off = disp->var.yoffset * (disp->line_length >> 3)
+	      + ((disp->var.xoffset * (disp->var.bits_per_pixel >> 3)) >> 3); 
+	out_le32(&p->dc_regs[SSR], off);
+
+out:
 	return 0;
 }
 
@@ -1455,7 +1530,21 @@
 	if (blank > 0) {
 		switch (blank - 1) {
 			case VESA_NO_BLANKING:
+			case VESA_POWERDOWN:
 				ctrl &= ~0x00000380;
+				if (p->ramdac == IBM) {
+					p->cmap_regs[PIDXHI] = 0;	eieio();
+					p->cmap_regs[PIDXLO] = MISCTL2;	eieio();
+					p->cmap_regs[PIDXDATA] = 0x55;	eieio();
+					p->cmap_regs[PIDXLO] = MISCTL1;	eieio();
+					p->cmap_regs[PIDXDATA] = 0x11;	eieio();
+					p->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
+					p->cmap_regs[PIDXDATA] = 0x0f;	eieio();
+					p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+					p->cmap_regs[PIDXDATA] = 0x1f;	eieio();
+					p->cmap_regs[PIDXLO] = CLKCTL;	eieio();
+					p->cmap_regs[PIDXDATA] = 0xc0;
+				}
 				break;
 			case VESA_VSYNC_SUSPEND:
 				ctrl &= ~0x00000020;
@@ -1463,12 +1552,23 @@
 			case VESA_HSYNC_SUSPEND:
 				ctrl &= ~0x00000010;
 				break;
-			case VESA_POWERDOWN:
-				ctrl &= ~0x00000380;
-				break;
 		}
 	} else {
-		ctrl |= p->ramdac == IBM ? 0x000017b0 : 0x00001780;
+		if (p->ramdac == IBM) {
+			ctrl |= 0x000017b0;
+			p->cmap_regs[PIDXHI] = 0;	eieio();
+			p->cmap_regs[PIDXLO] = CLKCTL;	eieio();
+			p->cmap_regs[PIDXDATA] = 0x01;	eieio();
+			p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
+			p->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
+			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
+			p->cmap_regs[PIDXLO] = MISCTL1;	eieio();
+			p->cmap_regs[PIDXDATA] = 0x01;	eieio();
+			p->cmap_regs[PIDXLO] = MISCTL2;	eieio();
+			p->cmap_regs[PIDXDATA] = 0x45;	eieio();
+		} else
+			ctrl |= 0x00001780;
 	}
 	out_le32(&p->dc_regs[STGCTL], ctrl);
 }
@@ -1477,6 +1577,7 @@
 init_imstt(struct fb_info_imstt *p))
 {
 	__u32 i, tmp;
+	__u32 *ip, *end;
 
 	tmp = in_le32(&p->dc_regs[PRC]);
 	if (p->ramdac == IBM)
@@ -1484,15 +1585,19 @@
 	else
 		p->total_vram = 0x00800000;
 
-	memset(p->frame_buffer, 0, p->total_vram);
+	ip = (__u32 *)p->frame_buffer;
+	end = (__u32 *)(p->frame_buffer + p->total_vram);
+	while (ip < end)
+		*ip++ = 0;
 
 	/* initialize the card */
 	tmp = in_le32(&p->dc_regs[STGCTL]);
 	out_le32(&p->dc_regs[STGCTL], tmp & ~0x1);
+	out_le32(&p->dc_regs[SSR], 0);
 
 	/* set default values for DAC registers */ 
 	if (p->ramdac == IBM) {
-		p->cmap_regs[PPMASK] = 0xff;
+		p->cmap_regs[PPMASK] = 0xff;	eieio();
 		p->cmap_regs[PIDXHI] = 0;	eieio();
 		for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
 			p->cmap_regs[PIDXLO] = ibm_initregs[i].addr;	eieio();
@@ -1507,14 +1612,18 @@
 
 #if USE_NV_MODES && defined(CONFIG_PPC)
 	{
-		int vmode, cmode;
+		int vmode = init_vmode, cmode = init_cmode;
 
-		vmode = nvram_read_byte(NV_VMODE);
-		if (vmode <= 0 || vmode > VMODE_MAX)
-			vmode = VMODE_640_480_67;
-		cmode = nvram_read_byte(NV_CMODE);
-		if (cmode < CMODE_8 || cmode > CMODE_32)
-			cmode = CMODE_8;
+		if (vmode == -1) {
+			vmode = nvram_read_byte(NV_VMODE);
+			if (vmode <= 0 || vmode > VMODE_MAX)
+				vmode = VMODE_640_480_67;
+		}
+		if (cmode == -1) {
+			cmode = nvram_read_byte(NV_CMODE);
+			if (cmode < CMODE_8 || cmode > CMODE_32)
+				cmode = CMODE_8;
+		}
 		if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) {
 			p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES;
 			p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES;
@@ -1527,22 +1636,6 @@
 	p->disp.var.bits_per_pixel = INIT_BPP;
 #endif
 
-	p->disp.var.height = p->disp.var.width = -1;
-	p->disp.var.vmode = FB_VMODE_NONINTERLACED;
-	p->disp.var.left_margin = p->disp.var.right_margin = 16;
-	p->disp.var.upper_margin = p->disp.var.lower_margin = 16;
-	p->disp.var.hsync_len = p->disp.var.vsync_len = 8;
-	p->disp.var.accel_flags = 0; /* FB_ACCELF_TEXT; */
-
-	set_dispsw(&p->disp, p);
-	if (p->ramdac == IBM)
-		imstt_cursor_init(p);
-
-	if (p->disp.var.green.length == 6)
-		set_565(p);
-	else
-		set_555(p);
-
 	if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram
 	    || !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
 		printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
@@ -1550,10 +1643,6 @@
 		return;
 	}
 
-	set_imstt_regvals(p, p->disp.var.bits_per_pixel);
-
-	p->disp.var.pixclock = 1000000 / getclkMHz(p);
-
 	sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP");
 	p->fix.smem_start = (__u8 *)p->frame_buffer_phys;
 	p->fix.smem_len = p->total_vram;
@@ -1568,21 +1657,24 @@
 	p->fix.ypanstep = 1;
 	p->fix.ywrapstep = 0;
 
-	p->disp.screen_base = p->frame_buffer;
-	p->disp.visual = p->fix.visual;
-	p->disp.type = p->fix.type;
-	p->disp.type_aux = p->fix.type_aux;
-	p->disp.line_length = p->fix.line_length;
-	p->disp.can_soft_blank = 1;
-	p->disp.ypanstep = 1;
-	p->disp.ywrapstep = 0;
-	p->disp.scrollmode = SCROLL_YREDRAW;
+	p->disp.var.accel_flags = noaccel ? 0 : FB_ACCELF_TEXT;
+	set_disp(&p->disp, p);
+
+	if (p->ramdac == IBM)
+		imstt_cursor_init(p);
+	if (p->disp.var.green.length == 6)
+		set_565(p);
+	else
+		set_555(p);
+	set_imstt_regvals(p, p->disp.var.bits_per_pixel);
+
+	p->disp.var.pixclock = 1000000 / getclkMHz(p);
 
 	strcpy(p->info.modename, p->fix.id);
+	strcpy(p->info.fontname, fontname);
 	p->info.node = -1;
 	p->info.fbops = &imsttfb_ops;
 	p->info.disp = &p->disp;
-	p->info.fontname[0] = 0;
 	p->info.changevar = 0;
 	p->info.switch_con = &imsttfbcon_switch;
 	p->info.updatevar = &imsttfbcon_updatevar;
@@ -1606,18 +1698,18 @@
 		GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20, tmp);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-	strncpy(display_info.name, p->fix.id, sizeof display_info.name);
+	strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
 	display_info.fb_address = (__u32)p->frame_buffer_phys;
 	display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW];
 	display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
-	display_info.disp_reg_address = 0;
+	display_info.disp_reg_address = (__u32)p->dc_regs_phys;
 	set_display_info(&p->disp);
 	if (!console_fb_info)
 		console_fb_info = &p->info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
-#if defined(CONFIG_FB_OF) || defined(CONFIG_PPC)
+#if defined(CONFIG_FB_OF)
 __initfunc(void
 imsttfb_of_init(struct device_node *dp))
 {
@@ -1667,22 +1759,60 @@
 __initfunc(void
 imsttfb_init(void))
 {
-#if defined(CONFIG_PPC)
-	u_int i;
-	struct device_node *dp;
-	char *names[4] = {"IMS,tt128mb","IMS,tt128mbA","IMS,tt128mb8","IMS,tt128mb8A"};
+#if !defined(CONFIG_FB_OF)
+	/* ... */
+#endif
+}
 
-#ifdef CONFIG_FB_OF
-	if (prom_num_displays)
+__initfunc(void
+imsttfb_setup(char *options, int *ints))
+{
+	char *this_opt;
+
+	if (!options || !*options)
 		return;
-#endif
 
-	for (i = 0; i < 4; i++) {
-		dp = find_devices(names[i]);
-		if (dp)
-			imsttfb_of_init(dp);
-	}
-#else
-	/* ... */
+	for (this_opt = strtok(options, ","); this_opt;
+	     this_opt = strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "font:", 5)) {
+			char *p;
+			int i;
+
+			p = this_opt + 5;
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (!*p || *p == ' ' || *p == ',')
+					break;
+			memcpy(fontname, this_opt + 5, i);
+			fontname[i] = 0;
+		} else if (!strncmp(this_opt, "noblink", 7)) {
+			curblink = 0;
+		} else if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+		}
+#if defined(CONFIG_PPC)
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				init_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case CMODE_8:
+				case 8:
+					init_cmode = CMODE_8;
+					break;
+				case CMODE_16:
+				case 15:
+				case 16:
+					init_cmode = CMODE_16;
+					break;
+				case CMODE_32:
+				case 24:
+				case 32:
+					init_cmode = CMODE_32;
+					break;
+			}
+		}
 #endif
+	}
 }
diff -u --recursive --new-file v2.1.128/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.1.128/linux/drivers/video/matroxfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/matroxfb.c	Fri Nov 13 10:10:12 1998
@@ -0,0 +1,4373 @@
+/*
+ *
+ * Hardware accelerated Matrox Millenium I, II, Mystique and G200
+ *
+ * (c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.3 1998/10/28 
+ *
+ * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@kg1.ping.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <tmrini@ntplx.net>
+ *                     MTRR stuff, betatesting, fixes, ideas
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting 
+ *                     
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifndef __i386__
+#ifndef ioremap_nocache
+#define ioremap_nocache(X,Y) ioremap(X,Y)
+#endif 
+#endif
+
+#ifdef DEBUG
+#define dprintk(X...)	printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF	0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX		PCI_VENDOR_ID_MATROX
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G200_AGP
+#define PCI_DEVICE_ID_MATROX_G200_AGP	0x0521
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100
+#define PCI_DEVICE_ID_MATROX_G100	0x1000
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
+#define PCI_DEVICE_ID_MATROX_G100_AGP	0x1001
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_UNSPECIFIED		0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP	0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP	0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP	0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP	0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI		0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP		0x1001
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP		0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP		0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR	FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR	FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR	FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G100, G200 and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
+#define NEED_DAC1064 1
+#endif
+
+struct matroxfb_par
+{
+	struct fb_var_screeninfo var;
+
+	unsigned int	final_bppShift;
+	int		visual;		/* unfortunately, fix */
+	int		video_type;
+	int		cmap_len;
+};
+
+struct my_timming {
+	unsigned int pixclock;
+	unsigned int HDisplay;
+	unsigned int HSyncStart;
+	unsigned int HSyncEnd;
+	unsigned int HTotal;
+	unsigned int VDisplay;
+	unsigned int VSyncStart;
+	unsigned int VSyncEnd;
+	unsigned int VTotal;
+	unsigned int sync;
+	int	     dblscan;
+	int	     interlaced;
+};
+
+struct matrox_fb_info;
+
+#define MATROX_2MB_WITH_4MB_ADDON
+
+struct matrox_pll_features {
+	unsigned int	vco_freq_min;	
+	unsigned int	ref_freq;
+	unsigned int	feed_div_min;
+	unsigned int	feed_div_max;
+	unsigned int	in_div_min;
+	unsigned int	in_div_max;
+	unsigned int	post_shift_max;
+};
+
+struct matrox_DAC1064_features {
+	u_int8_t	xvrefctrl;
+};
+
+struct matrox_accel_features {
+	int		has_cacheflush;
+};
+
+/* current hardware status */
+struct matrox_hw_state {
+	u_int32_t	MXoptionReg;
+	unsigned char	DACclk[6];
+	unsigned char	DACreg[64];
+	unsigned char	MiscOutReg;
+	unsigned char	DACpal[768];
+	unsigned char	CRTC[25];
+	unsigned char	CRTCEXT[6];
+	unsigned char	SEQ[5];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	GCTL[9];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	ATTR[21];
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	unsigned char	ramdac_rev;
+#endif
+	u_int32_t	m_dwg_rect;
+};
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+#define ACCESS_FBINFO(x) (minfo->x)
+#define ACCESS_FBINFO2(info, x) (((struct matrox_fb_info*)info)->x)
+
+#define MINFO minfo
+
+#define WPMINFO struct matrox_fb_info* minfo,
+#define CPMINFO	const struct matrox_fb_info* minfo,
+#define PMINFO  minfo,
+
+static struct matrox_fb_info* mxinfo(struct display* p) {
+	return (struct matrox_fb_info*)p->fb_info;
+}
+
+#define PMXINFO(p) mxinfo(p),
+#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+
+#else
+
+struct matrox_fb_info global_mxinfo;
+struct display global_disp;
+
+#define ACCESS_FBINFO(x) (global_mxinfo.x)
+#define ACCESS_FBINFO2(info, x) (global_mxinfo.x)
+
+#define MINFO (&global_mxinfo)
+
+#define WPMINFO
+#define CPMINFO
+#define PMINFO
+
+#if 0
+static struct matrox_fb_info* mxinfo(struct display* p) {
+	return &global_mxinfo;
+}
+#endif
+
+#define PMXINFO(p)
+#define MINFO_FROM_DISP(x)
+
+#endif
+
+struct matrox_switch {
+	int	(*preinit)(WPMINFO struct matrox_hw_state*);
+	void	(*reset)(WPMINFO struct matrox_hw_state*);
+	int	(*init)(CPMINFO struct matrox_hw_state*, struct my_timming*);
+	void	(*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
+};
+
+struct matrox_fb_info {
+	/* fb_info must be first */
+	struct fb_info		fbcon;
+
+	struct matrox_fb_info*	next_fb;
+
+	struct matroxfb_par	curr;
+	struct matrox_hw_state	hw1;
+	struct matrox_hw_state	hw2;
+	struct matrox_hw_state*	newhw;
+	struct matrox_hw_state*	currenthw;
+
+	struct matrox_accel_data accel;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+	unsigned int	_mga_ydstorg;
+	unsigned int	_curr_ydstorg;
+#endif
+
+	struct pci_dev*		pcidev;
+
+	unsigned long	video_base;	/* physical */
+	char*		video_vbase;	/* CPU view */
+	unsigned int	video_len;
+
+	unsigned long	mmio_base;	/* physical */
+	unsigned char*	mmio;		/* CPU view */
+	unsigned int	mmio_len;
+
+	unsigned int	max_pixel_clock;
+
+	struct matrox_switch*	hw_switch;
+	int		currcon;
+
+	struct {
+		struct matrox_pll_features pll;
+		struct matrox_DAC1064_features DAC1064;
+		struct matrox_accel_features accel;
+		} features;
+
+	int			interleave;
+	int			millenium;
+	int			milleniumII;
+	struct {
+		int		cfb4;
+		const int*	vxres;
+			      } capable;
+#ifdef CONFIG_MTRR
+	struct {
+		int		vram;
+		int		vram_valid;
+			      } mtrr;
+#endif
+	struct {
+		int		precise_width;
+		int		mga_24bpp_fix;
+		int		novga;
+		int		nobios;
+		int		nopciretry;
+		int		inverse;
+		int		hwcursor;
+
+		int		accelerator;
+		int		video64bits;
+			      } devflags;
+	struct display_switch	dispsw;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	struct {
+		unsigned int x;
+		unsigned int y;
+		unsigned int w;
+		unsigned int h;
+		volatile unsigned int mode;
+			      } cursor;
+#endif
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
+	union {
+#ifdef FBCON_HAS_CFB16
+		u_int16_t	cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+		u_int32_t	cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+		u_int32_t	cfb32[16];
+#endif
+	} cmap;
+#endif
+	struct { unsigned red, green, blue, transp; } palette[256];
+};
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#define mga_ydstorg(x)	ACCESS_FBINFO2(x, _mga_ydstorg)
+#define curr_ydstorg(x)	ACCESS_FBINFO2(x, _curr_ydstorg)
+#else
+#define mga_ydstorg(x) (0)
+#define curr_ydstorg(x) (0)
+#endif
+
+#define PCI_OPTION_REG	0x40
+#define PCI_MGA_INDEX	0x44
+#define PCI_MGA_DATA	0x48
+
+#define M_DWGCTL	0x1C00
+#define M_MACCESS	0x1C04
+#define M_CTLWTST	0x1C08
+
+#define M_PLNWT		0x1C1C
+
+#define M_BCOL		0x1C20
+#define M_FCOL		0x1C24
+
+#define M_SGN		0x1C58
+#define M_LEN		0x1C5C
+#define M_AR0		0x1C60
+#define M_AR1		0x1C64
+#define M_AR2		0x1C68
+#define M_AR3		0x1C6C
+#define M_AR4		0x1C70
+#define M_AR5		0x1C74
+#define M_AR6		0x1C78
+
+#define M_CXBNDRY	0x1C80
+#define M_FXBNDRY	0x1C84
+#define M_YDSTLEN	0x1C88
+#define M_PITCH		0x1C8C
+#define M_YDST		0x1C90
+#define M_YDSTORG	0x1C94
+#define M_YTOP		0x1C98
+#define M_YBOT		0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH	0x1FFF
+
+#define M_EXEC		0x0100
+
+#define M_DWG_TRAP	0x04
+#define M_DWG_BITBLT	0x08
+#define M_DWG_ILOAD	0x09
+
+#define M_DWG_LINEAR	0x0080
+#define M_DWG_SOLID	0x0800
+#define M_DWG_ARZERO	0x1000
+#define M_DWG_SGNZERO	0x2000
+#define M_DWG_SHIFTZERO	0x4000
+
+#define M_DWG_REPLACE	0x000C0000
+#define M_DWG_REPLACE2	(M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR	0x00060010
+
+#define M_DWG_BFCOL	0x04000000
+#define M_DWG_BMONOWF	0x08000000
+
+#define M_DWG_TRANSC	0x40000000
+
+#define M_FIFOSTATUS	0x1E10
+#define M_STATUS	0x1E14
+
+#define M_IEN		0x1E1C
+
+#define M_VCOUNT	0x1E20
+
+#define M_RESET		0x1E40
+
+#define M_OPMODE	0x1E54
+#define     M_OPMODE_DMA_GEN_WRITE	0x00
+#define     M_OPMODE_DMA_BLIT		0x04
+#define     M_OPMODE_DMA_VECTOR_WRITE	0x08
+#define     M_OPMODE_DMA_LE		0x0000		/* little endian - no transformation */
+#define     M_OPMODE_DMA_BE_8BPP	0x0000
+#define     M_OPMODE_DMA_BE_16BPP	0x0100
+#define     M_OPMODE_DMA_BE_32BPP	0x0200
+#define     M_OPMODE_DIR_LE		0x000000	/* little endian - no transformation */
+#define     M_OPMODE_DIR_BE_8BPP	0x000000
+#define     M_OPMODE_DIR_BE_16BPP	0x010000
+#define     M_OPMODE_DIR_BE_32BPP	0x020000
+
+#define M_ATTR_INDEX	0x1FC0
+#define M_ATTR_DATA	0x1FC1
+
+#define M_MISC_REG	0x1FC2
+#define M_3C2_RD	0x1FC2
+
+#define M_SEQ_INDEX	0x1FC4
+#define M_SEQ_DATA	0x1FC5
+
+#define M_MISC_REG_READ	0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA	0x1FCF
+
+#define M_CRTC_INDEX	0x1FD4
+
+#define M_ATTR_RESET	0x1FDA
+#define M_3DA_WR	0x1FDA
+
+#define M_EXTVGA_INDEX	0x1FDE
+#define M_EXTVGA_DATA	0x1FDF
+
+#define M_RAMDAC_BASE	0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG	(M_RAMDAC_BASE+0)
+#define M_DAC_VAL	(M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK	(M_RAMDAC_BASE+2)
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define TVP3026_INDEX		0x00
+#define TVP3026_PALWRADD	0x00
+#define TVP3026_PALDATA		0x01
+#define TVP3026_PIXRDMSK	0x02
+#define TVP3026_PALRDADD	0x03
+#define TVP3026_CURCOLWRADD	0x04
+#define     TVP3026_CLOVERSCAN		0x00
+#define     TVP3026_CLCOLOR0		0x01
+#define     TVP3026_CLCOLOR1		0x02
+#define     TVP3026_CLCOLOR2		0x03
+#define TVP3026_CURCOLDATA	0x05
+#define TVP3026_CURCOLRDADD	0x07
+#define TVP3026_CURCTRL		0x09
+#define TVP3026_X_DATAREG	0x0A
+#define TVP3026_CURRAMDATA	0x0B
+#define TVP3026_CURPOSXL	0x0C
+#define TVP3026_CURPOSXH	0x0D
+#define TVP3026_CURPOSYL	0x0E
+#define TVP3026_CURPOSYH	0x0F
+
+#define TVP3026_XSILICONREV	0x01
+#define TVP3026_XCURCTRL	0x06
+#define     TVP3026_XCURCTRL_DIS	0x00	/* transparent, transparent, transparent, transparent */
+#define     TVP3026_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     TVP3026_XCURCTRL_XGA	0x02	/* 0, 1, transparent, complement */
+#define     TVP3026_XCURCTRL_XWIN	0x03	/* transparent, transparent, 0, 1 */
+#define     TVP3026_XCURCTRL_BLANK2048	0x00
+#define     TVP3026_XCURCTRL_BLANK4096	0x10
+#define     TVP3026_XCURCTRL_INTERLACED	0x20
+#define     TVP3026_XCURCTRL_ODD	0x00 /* ext.signal ODD/\EVEN */
+#define     TVP3026_XCURCTRL_EVEN	0x40 /* ext.signal EVEN/\ODD */
+#define     TVP3026_XCURCTRL_INDIRECT	0x00
+#define     TVP3026_XCURCTRL_DIRECT	0x80
+#define TVP3026_XLATCHCTRL	0x0F
+#define     TVP3026_XLATCHCTRL_1_1	0x06
+#define     TVP3026_XLATCHCTRL_2_1	0x07
+#define     TVP3026_XLATCHCTRL_4_1	0x06
+#define     TVP3026_XLATCHCTRL_8_1	0x06
+#define     TVP3026_XLATCHCTRL_16_1	0x06
+#define     TVP3026A_XLATCHCTRL_4_3	0x07
+#define     TVP3026B_XLATCHCTRL_4_3	0x08
+#define     TVP3026B_XLATCHCTRL_8_3	0x06	/* ??? do not understand... but it works... ??? */
+#define TVP3026_XTRUECOLORCTRL	0x18
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL	0x00
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP	0x20
+#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR		0x80
+#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR		0x40 /* paletized */
+#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR		0x00
+#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE		0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define     TVP3026_XTRUECOLORCTRL_RGB_888		0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define	    TVP3026_XTRUECOLORCTRL_BGR_888		0x17
+#define     TVP3026_XTRUECOLORCTRL_ORGB_8888		0x06
+#define     TVP3026_XTRUECOLORCTRL_BGRO_8888		0x07
+#define     TVP3026_XTRUECOLORCTRL_RGB_565		0x05
+#define     TVP3026_XTRUECOLORCTRL_ORGB_1555		0x04
+#define     TVP3026_XTRUECOLORCTRL_RGB_664		0x03
+#define     TVP3026_XTRUECOLORCTRL_RGBO_4444		0x01
+#define TVP3026_XMUXCTRL	0x19
+#define     TVP3026_XMUXCTRL_MEMORY_8BIT			0x01 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_16BIT			0x02 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_32BIT			0x03 /* 2MB RAM, 512K * 4 */
+#define     TVP3026_XMUXCTRL_MEMORY_64BIT			0x04 /* >2MB RAM, 512K * 8 & more */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT				0x40 /* L0,H0,L1,H1... */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED			0x60 /* H0,L0,H1,L1... */
+#define     TVP3026_XMUXCTRL_PIXEL_8BIT				0x48
+#define     TVP3026_XMUXCTRL_PIXEL_16BIT			0x50
+#define     TVP3026_XMUXCTRL_PIXEL_32BIT			0x58
+#define     TVP3026_XMUXCTRL_VGA				0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL	0x1A
+#define     TVP3026_XCLKCTRL_DIV1	0x00
+#define     TVP3026_XCLKCTRL_DIV2	0x10
+#define     TVP3026_XCLKCTRL_DIV4	0x20
+#define     TVP3026_XCLKCTRL_DIV8	0x30
+#define     TVP3026_XCLKCTRL_DIV16	0x40
+#define     TVP3026_XCLKCTRL_DIV32	0x50
+#define     TVP3026_XCLKCTRL_DIV64	0x60
+#define     TVP3026_XCLKCTRL_CLKSTOPPED	0x70
+#define     TVP3026_XCLKCTRL_SRC_CLK0	0x00
+#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
+#define     TVP3026_XCLKCTRL_SRC_CLK2	0x02	/* CLK2 is TTL source*/
+#define     TVP3026_XCLKCTRL_SRC_NCLK2	0x03	/* not CLK2 is TTL source */
+#define     TVP3026_XCLKCTRL_SRC_ECLK2	0x04	/* CLK2 and not CLK2 is ECL source */
+#define     TVP3026_XCLKCTRL_SRC_PLL	0x05
+#define     TVP3026_XCLKCTRL_SRC_DIS	0x06	/* disable & poweroff internal clock */
+#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE	0x1C
+#define TVP3026_XGENCTRL	0x1D
+#define     TVP3026_XGENCTRL_HSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_HSYNC_NEG	0x01
+#define     TVP3026_XGENCTRL_VSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_VSYNC_NEG	0x02
+#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
+#define     TVP3026_XGENCTRL_BLACK_0IRE		0x00
+#define     TVP3026_XGENCTRL_BLACK_75IRE	0x10
+#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN	0x00
+#define     TVP3026_XGENCTRL_SYNC_ON_GREEN	0x20
+#define     TVP3026_XGENCTRL_OVERSCAN_DIS	0x00
+#define     TVP3026_XGENCTRL_OVERSCAN_EN	0x40
+#define TVP3026_XMISCCTRL	0x1E
+#define     TVP3026_XMISCCTRL_DAC_PUP	0x00
+#define     TVP3026_XMISCCTRL_DAC_PDOWN	0x01
+#define     TVP3026_XMISCCTRL_DAC_EXT	0x00 /* or 8, bit 3 is ignored */
+#define     TVP3026_XMISCCTRL_DAC_6BIT	0x04
+#define     TVP3026_XMISCCTRL_DAC_8BIT	0x0C
+#define     TVP3026_XMISCCTRL_PSEL_DIS	0x00
+#define     TVP3026_XMISCCTRL_PSEL_EN	0x10
+#define     TVP3026_XMISCCTRL_PSEL_LOW	0x00 /* PSEL high selects directcolor */
+#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL	0x2A
+#define TVP3026_XGENIODATA	0x2B
+#define TVP3026_XPLLADDR	0x2C
+#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define     TVP3026_XPLLDATA_N		0x00
+#define     TVP3026_XPLLDATA_M		0x01
+#define     TVP3026_XPLLDATA_P		0x02
+#define     TVP3026_XPLLDATA_STAT	0x03
+#define TVP3026_XPIXPLLDATA	0x2D
+#define TVP3026_XMEMPLLDATA	0x2E
+#define TVP3026_XLOOPPLLDATA	0x2F
+#define TVP3026_XCOLKEYOVRMIN	0x30
+#define TVP3026_XCOLKEYOVRMAX	0x31
+#define TVP3026_XCOLKEYREDMIN	0x32
+#define TVP3026_XCOLKEYREDMAX	0x33
+#define TVP3026_XCOLKEYGREENMIN	0x34
+#define TVP3026_XCOLKEYGREENMAX	0x35
+#define TVP3026_XCOLKEYBLUEMIN	0x36
+#define TVP3026_XCOLKEYBLUEMAX	0x37
+#define TVP3026_XCOLKEYCTRL	0x38
+#define     TVP3026_XCOLKEYCTRL_OVR_EN	0x01
+#define     TVP3026_XCOLKEYCTRL_RED_EN	0x02
+#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define     TVP3026_XCOLKEYCTRL_BLUE_EN	0x08
+#define     TVP3026_XCOLKEYCTRL_NEGATE	0x10
+#define     TVP3026_XCOLKEYCTRL_ZOOM1	0x00
+#define     TVP3026_XCOLKEYCTRL_ZOOM2	0x20
+#define     TVP3026_XCOLKEYCTRL_ZOOM4	0x40
+#define     TVP3026_XCOLKEYCTRL_ZOOM8	0x60
+#define     TVP3026_XCOLKEYCTRL_ZOOM16	0x80
+#define     TVP3026_XCOLKEYCTRL_ZOOM32	0xA0
+#define TVP3026_XMEMPLLCTRL	0x39
+#define     TVP3026_XMEMPLLCTRL_DIV(X)	(((X)-1)>>1)	/* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define     TVP3026_XMEMPLLCTRL_STROBEMKC4	0x08
+#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK	0x00	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL	0x10	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL	0x00
+#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL	0x20
+#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN	0x40	/* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST	0x3A
+#define TVP3026_XTESTMODEDATA	0x3B
+#define TVP3026_XCRCREML	0x3C
+#define TVP3026_XCRCREMH	0x3D
+#define TVP3026_XCRCBITSEL	0x3E
+#define TVP3026_XID		0x3F
+
+#endif
+
+#ifdef NEED_DAC1064
+
+#define DAC1064_OPT_SCLK_PCI	0x00
+#define DAC1064_OPT_SCLK_PLL	0x01
+#define DAC1064_OPT_SCLK_EXT	0x02
+#define DAC1064_OPT_SCLK_MASK	0x03
+#define DAC1064_OPT_GDIV1	0x04	/* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3	0x00
+#define DAC1064_OPT_MDIV1	0x08
+#define DAC1064_OPT_MDIV2	0x00
+#define DAC1064_OPT_RESERVED	0x10
+
+#define M1064_INDEX	0x00
+#define M1064_PALWRADD	0x00
+#define M1064_PALDATA	0x01
+#define M1064_PIXRDMSK	0x02
+#define M1064_PALRDADD	0x03
+#define M1064_X_DATAREG	0x0A
+#define M1064_CURPOSXL	0x0C	/* can be accessed as DWORD */
+#define M1064_CURPOSXH	0x0D
+#define M1064_CURPOSYL	0x0E
+#define M1064_CURPOSYH	0x0F
+
+#define M1064_XCURADDL		0x04
+#define M1064_XCURADDH		0x05
+#define M1064_XCURCTRL		0x06
+#define     M1064_XCURCTRL_DIS		0x00	/* transparent, transparent, transparent, transparent */
+#define     M1064_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     M1064_XCURCTRL_XGA		0x02	/* 0, 1, transparent, complement */
+#define     M1064_XCURCTRL_XWIN		0x03	/* transparent, transparent, 0, 1 */
+#define M1064_XCURCOL0RED	0x08
+#define M1064_XCURCOL0GREEN	0x09
+#define M1064_XCURCOL0BLUE	0x0A
+#define M1064_XCURCOL1RED	0x0C
+#define M1064_XCURCOL1GREEN	0x0D
+#define M1064_XCURCOL1BLUE	0x0E
+#define M1064_XCURCOL2RED	0x10
+#define M1064_XCURCOL2GREEN	0x11
+#define M1064_XCURCOL2BLUE	0x12
+#define DAC1064_XVREFCTRL	0x18
+#define      DAC1064_XVREFCTRL_INTERNAL		0x3F
+#define      DAC1064_XVREFCTRL_EXTERNAL		0x00
+#define      DAC1064_XVREFCTRL_G100_DEFAULT	0x03
+#define M1064_XMULCTRL		0x19
+#define      M1064_XMULCTRL_DEPTH_8BPP		0x00	/* 8 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_15BPP_1BPP	0x01	/* 15 bpp paletized + 1 bpp overlay */
+#define      M1064_XMULCTRL_DEPTH_16BPP		0x02	/* 16 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP		0x03	/* 24 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP_8BPP	0x04	/* 24 bpp direct + 8 bpp overlay paletized */
+#define      M1064_XMULCTRL_2G8V16		0x05	/* 15 bpp video direct, half xres, 8bpp paletized */
+#define      M1064_XMULCTRL_G16V16		0x06	/* 15 bpp video, 15bpp graphics, one of them paletized */
+#define      M1064_XMULCTRL_DEPTH_32BPP		0x07	/* 24 bpp paletized + 8 bpp unused */
+#define      M1064_XMULCTRL_GRAPHICS_PALETIZED	0x00
+#define      M1064_XMULCTRL_VIDEO_PALETIZED	0x08
+#define M1064_XPIXCLKCTRL	0x1A
+#define      M1064_XPIXCLKCTRL_SRC_PCI		0x00
+#define      M1064_XPIXCLKCTRL_SRC_PLL		0x01
+#define      M1064_XPIXCLKCTRL_SRC_EXT		0x02
+#define      M1064_XPIXCLKCTRL_SRC_MASK		0x03
+#define      M1064_XPIXCLKCTRL_EN		0x00
+#define      M1064_XPIXCLKCTRL_DIS		0x04
+#define      M1064_XPIXCLKCTRL_PLL_DOWN		0x00
+#define      M1064_XPIXCLKCTRL_PLL_UP		0x08
+#define M1064_XGENCTRL		0x1D
+#define      M1064_XGENCTRL_VS_0		0x00
+#define      M1064_XGENCTRL_VS_1		0x01
+#define      M1064_XGENCTRL_ALPHA_DIS		0x00
+#define      M1064_XGENCTRL_ALPHA_EN		0x02
+#define      M1064_XGENCTRL_BLACK_0IRE		0x00
+#define      M1064_XGENCTRL_BLACK_75IRE		0x10
+#define      M1064_XGENCTRL_SYNC_ON_GREEN	0x00
+#define      M1064_XGENCTRL_NO_SYNC_ON_GREEN	0x20
+#define      M1064_XGENCTRL_SYNC_ON_GREEN_MASK	0x20
+#define M1064_XMISCCTRL		0x1E
+#define      M1064_XMISCCTRL_DAC_DIS		0x00
+#define      M1064_XMISCCTRL_DAC_EN		0x01
+#define      M1064_XMISCCTRL_MFC_VGA		0x00
+#define      M1064_XMISCCTRL_MFC_MAFC		0x02
+#define      M1064_XMISCCTRL_MFC_DIS		0x06
+#define      M1064_XMISCCTRL_DAC_6BIT		0x00
+#define      M1064_XMISCCTRL_DAC_8BIT		0x08
+#define      M1064_XMISCCTRL_LUT_DIS		0x00
+#define      M1064_XMISCCTRL_LUT_EN		0x10
+#define M1064_XGENIOCTRL	0x2A
+#define M1064_XGENIODATA	0x2B
+#define DAC1064_XSYSPLLM	0x2C
+#define DAC1064_XSYSPLLN	0x2D
+#define DAC1064_XSYSPLLP	0x2E
+#define DAC1064_XSYSPLLSTAT	0x2F
+#define M1064_XZOOMCTRL		0x38
+#define      M1064_XZOOMCTRL_1			0x00
+#define      M1064_XZOOMCTRL_2			0x01
+#define      M1064_XZOOMCTRL_4			0x03
+#define M1064_XSENSETEST	0x3A
+#define      M1064_XSENSETEST_BCOMP		0x01
+#define      M1064_XSENSETEST_GCOMP		0x02
+#define      M1064_XSENSETEST_RCOMP		0x04
+#define      M1064_XSENSETEST_PDOWN		0x00
+#define      M1064_XSENSETEST_PUP		0x80
+#define M1064_XCRCREML		0x3C
+#define M1064_XCRCREMH		0x3D
+#define M1064_XCRCBITSEL	0x3E
+#define M1064_XCOLKEYMASKL	0x40
+#define M1064_XCOLKEYMASKH	0x41
+#define M1064_XCOLKEYL		0x42
+#define M1064_XCOLKEYH		0x43
+#define M1064_XPIXPLLAM		0x44
+#define M1064_XPIXPLLAN		0x45
+#define M1064_XPIXPLLAP		0x46
+#define M1064_XPIXPLLBM		0x48
+#define M1064_XPIXPLLBN		0x49
+#define M1064_XPIXPLLBP		0x4A
+#define M1064_XPIXPLLCM		0x4C
+#define M1064_XPIXPLLCN		0x4D
+#define M1064_XPIXPLLCP		0x4E
+#define M1064_XPIXPLLSTAT	0x4F
+
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define MX_OPTION_BSWAP		0x00000000
+
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define MX_OPTION_BSWAP		0x80000000
+
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)	/* TODO */
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_BE_8BPP  | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)	/* TODO, ?32 */
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr)	(*(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr)))
+/* #define mga_inw(addr)	*(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr)) */
+#define mga_inl(addr)	(*(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr)))
+#define mga_outb(addr,val) *(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+/* #define mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val) */
+#define mga_outl(addr,val) *(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
+#ifdef __LITTLE_ENDIAN
+#define __mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_setr(addr,port,val) __mga_outw(addr, ((val)<<8) | (port))
+#else
+#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define mga_fifo(n)	do {} while (mga_inb(M_FIFOSTATUS) < (n))
+#else
+#define mga_fifo(n)	do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+#endif
+
+static void WaitTillIdle(const struct matrox_fb_info* minfo) {
+	do {} while (mga_inl(M_STATUS) & 0x10000);
+}
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x)	 (x->interleave)
+#define isMillenium(x)	 (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x)  (0)
+#define isMillenium(x)	 (0)
+#define isMilleniumII(x) (0)
+#endif
+
+static void matrox_cfbX_init(struct matrox_fb_info* minfo) {
+	u_int32_t maccess;
+	u_int32_t mpitch;
+	u_int32_t mopmode;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+	curr_ydstorg(MINFO) = mga_ydstorg(MINFO);
+#endif
+	mpitch = ACCESS_FBINFO(curr.var.xres_virtual);
+	switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+		case 4:		maccess = 0x00000000;	/* accelerate as 8bpp video */
+				mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+				mopmode = M_OPMODE_4BPP;
+				break;
+    		case 8:		maccess = 0x00000000; 
+				mopmode = M_OPMODE_8BPP;
+				break;
+    		case 16:	if (ACCESS_FBINFO(curr.var.green.length) == 5)
+					maccess = 0xC0000001; 
+				else
+    				    	maccess = 0x40000001; 
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+				curr_ydstorg(MINFO) >>= 1;
+#endif
+				mopmode = M_OPMODE_16BPP;
+				break;
+		case 24:	maccess = 0x00000003;
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+				curr_ydstorg(MINFO) /= 3;
+#endif
+				mopmode = M_OPMODE_24BPP;
+				break;
+		case 32:	maccess = 0x00000002; 
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+				curr_ydstorg(MINFO) >>= 2;
+#endif
+				mopmode = M_OPMODE_32BPP;
+				break;
+		default:	maccess = 0x00000000; 
+				mopmode = 0x00000000;
+				break;	/* turn off acceleration!!! */
+	}
+	mga_fifo(8);
+	mga_outl(M_PITCH, mpitch);
+	mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
+	mga_outl(M_PLNWT, -1);
+	mga_outl(M_OPMODE, mopmode);
+	mga_outl(M_CXBNDRY, 0xFFFF0000);
+	mga_outl(M_YTOP, 0);
+	mga_outl(M_YBOT, 0x007FFFFF);
+	mga_outl(M_MACCESS, maccess);
+	ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+	if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
+}
+
+static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+	int pixx = p->var.xres_virtual, start, end;
+	MINFO_FROM_DISP(p);
+
+	sx *= fontwidth(p);
+	dx *= fontwidth(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+	sy *= fontheight(p);
+	dy *= fontheight(p);
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(2);
+		mga_outl(M_AR5, pixx);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			       M_DWG_BFCOL | M_DWG_REPLACE);
+		width--;
+		start = sy*pixx+sx+curr_ydstorg(MINFO);
+		end = start+width;
+	} else {
+		mga_fifo(3);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -pixx);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		width--;
+		end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(4);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+	WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+	int pixx, start, end;
+	MINFO_FROM_DISP(p);
+	/* both (sx or dx or width) and fontwidth() are odd, so their multiply is
+	   also odd, that means that we cannot use acceleration */
+	if ((sx | dx | width) & fontwidth(p) & 1) {
+		fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
+		return;
+	}
+	sx *= fontwidth(p);
+	dx *= fontwidth(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+	sy *= fontheight(p);
+	dy *= fontheight(p);
+	pixx = p->var.xres_virtual >> 1;
+	sx >>= 1;
+	dx >>= 1;
+	width >>= 1;
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(2);
+		mga_outl(M_AR5, pixx);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			M_DWG_BFCOL | M_DWG_REPLACE);
+		width--;
+		start = sy*pixx+sx+curr_ydstorg(MINFO);
+		end = start+width;
+	} else {
+		mga_fifo(3);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -pixx);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		width--;
+		end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(5);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_outl(M_YDST, dy*pixx >> 5);
+	mga_outl(M_LEN | M_EXEC, height);
+	WaitTillIdle(MINFO);
+}
+#endif
+
+static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height, 
+		int width) {
+	mga_fifo(4);
+	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
+	mga_outl(M_FCOL, color);
+	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+	mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+	WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
+	matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
+			     height * fontheight(p), width * fontwidth(p));
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+	u_int32_t bgx;
+	int whattodo;
+	MINFO_FROM_DISP(p);
+
+	whattodo = 0; 
+	bgx = attr_bgcol_ec(p, conp);
+	bgx |= bgx << 4;
+	bgx |= bgx << 8;
+	bgx |= bgx << 16;
+	sy *= fontheight(p);
+	sx *= fontwidth(p);
+	height *= fontheight(p);
+	width *= fontwidth(p);
+	if (sx & 1) {
+		sx ++;
+		if (!width) return;
+		width --;
+		whattodo = 1;
+	}
+	if (width & 1) {
+		whattodo |= 2;
+	}
+	width >>= 1;
+	sx >>= 1;
+	if (width) {
+		mga_fifo(5);
+		mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
+		mga_outl(M_FCOL, bgx);
+		mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+		mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
+		mga_outl(M_LEN | M_EXEC, height);
+		WaitTillIdle(MINFO);
+	}
+	if (whattodo) {
+		u_int32_t step = p->var.xres_virtual >> 1;
+		if (whattodo & 1) {
+			u_int8_t* uaddr = p->screen_base + sy * step + sx - 1;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0xF0;
+			for (loop = height; loop > 0; loop --) {
+				*uaddr = (*uaddr & 0x0F) | bgx2;
+				uaddr += step;
+			}
+		}
+		if (whattodo & 2) {
+			u_int8_t* uaddr = p->screen_base + sy * step + sx + width;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0x0F;
+			for (loop = height; loop > 0; loop --) {
+				*uaddr = (*uaddr & 0xF0) | bgx2;
+				uaddr += step;
+			}
+		}
+	}
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+	u_int32_t bgx;
+
+	bgx = attr_bgcol_ec(p, conp);
+	bgx |= bgx << 8;
+	bgx |= bgx << 16;
+	matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+	u_int32_t bgx;
+
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+	u_int32_t bgx;
+
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
+	u_int32_t ar0;
+	u_int32_t step;
+	MINFO_FROM_DISP(p);
+
+	yy *= fontheight(p);
+	xx *= fontwidth(p);
+	mga_fifo(7);
+	mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+
+	mga_outl(M_FCOL, fgx);
+	mga_outl(M_BCOL, bgx);
+	ar0 = fontwidth(p) - 1;
+	mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
+	if (fontwidth(p) <= 8)
+		step = 1;
+	else if (fontwidth(p) <= 16)
+		step = 2;
+	else 
+		step = 4;
+	/* TODO: set OPMODE_DMA_LE for BE */
+	if (fontwidth(p) == step << 3) {
+		size_t charcell = fontheight(p)*step;
+		/* TODO: Align charcell to 4B for BE */
+		mga_outl(M_AR3, 0);
+		mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
+		mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+		memcpy(ACCESS_FBINFO(mmio), p->fontdata+(c&p->charmask)*charcell, charcell);
+	} else {
+		u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
+		u_int32_t ydstlen_tmp = (yy << 16) | 1;
+		int i;
+		switch (step) {
+		case 1:	
+			for (i = fontheight(p); i > 0; i--) {
+				mga_fifo(3);
+				mga_outl(M_AR0, ar0);
+				mga_outl(M_AR3, 0);
+				mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+				*(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+				*(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+				ydstlen_tmp += 0x10000;
+			}
+			break;
+		case 2:
+			for (i = fontheight(p); i > 0; i--) {
+				mga_fifo(3);
+				mga_outl(M_AR0, ar0);
+				mga_outl(M_AR3, 0);
+				mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+				*(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+				*(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 16;
+#endif
+				ydstlen_tmp += 0x10000;
+				chardata += 2;
+			}
+			break;
+		case 4:
+			for (i = fontheight(p); i > 0; i--) {
+				mga_fifo(3);
+				mga_outl(M_AR0, ar0);
+				mga_outl(M_AR3, 0);
+				mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+				*(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+				ydstlen_tmp += 0x10000;
+				chardata += 4;
+			}
+			break;
+		}
+	}
+	/* TODO: restore OPMODE for BE */
+	WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
+	fgx |= (fgx << 8);
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+	matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 16);
+	matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
+	matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int32_t step;
+	u_int32_t ydstlen;
+	u_int32_t xlen;
+	u_int32_t ar0;
+	u_int32_t charcell;
+	u_int32_t fxbndry;
+	int easy;
+	MINFO_FROM_DISP(p);
+
+	yy *= fontheight(p);
+	xx *= fontwidth(p);
+	if (fontwidth(p) <= 8)
+		step = 1;
+	else if (fontwidth(p) <= 16)
+		step = 2;
+	else
+		step = 4;
+	charcell = fontheight(p)*step;
+	xlen = (charcell + 3) & ~3;
+	if (fontwidth(p) == step << 3) {
+		ydstlen = (yy<<16) | fontheight(p);
+		ar0 = fontheight(p)*fontwidth(p) - 1;
+		easy = 1;
+	} else {
+		ydstlen = (yy<<16) | 1;
+		ar0 = fontwidth(p) - 1;
+		easy = 0;
+	}
+	mga_fifo(3);
+	mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+	mga_outl(M_FCOL, fgx);
+	mga_outl(M_BCOL, bgx);
+	/* TODO: set OPMODE_DMA_LE for BE */
+	fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
+	while (count--) {
+		u_int8_t* chardata = p->fontdata + (*s++ & p->charmask)*charcell;
+
+		mga_fifo(4);
+		mga_outl(M_FXBNDRY, fxbndry);
+		if (easy) {
+			mga_outl(M_AR0, ar0);
+			mga_outl(M_AR3, 0);
+			mga_outl(M_YDSTLEN | M_EXEC, ydstlen);
+			memcpy(ACCESS_FBINFO(mmio), chardata, xlen);
+		} else {
+			u_int32_t ydstlen_tmp = ydstlen;
+			int i;
+			switch (step) {
+				case 1:	
+					for (i = fontheight(p); i > 0; i--) {
+						mga_fifo(3);
+						mga_outl(M_AR0, ar0);
+						mga_outl(M_AR3, 0);
+						mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+						*(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+						*(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+						ydstlen_tmp += 0x10000;
+					}
+					break;
+				case 2:
+					for (i = fontheight(p); i > 0; i--) {
+						mga_fifo(3);
+						mga_outl(M_AR0, ar0);
+						mga_outl(M_AR3, 0);
+						mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+						*(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+						*(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 32;
+#endif
+						ydstlen_tmp += 0x10000;
+						chardata += 2;
+					}
+					break;
+				case 4:
+					for (i = fontheight(p); i > 0; i--) {
+						mga_fifo(3);
+						mga_outl(M_AR0, ar0);
+						mga_outl(M_AR3, 0);
+						mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+						*(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+						ydstlen_tmp += 0x10000;
+						chardata += 4;
+					}
+					break;
+			}
+		}
+		fxbndry += fontwidth(p) + (fontwidth(p) << 16);
+	}
+	/* TODO: restore OPMODE for BE */
+	WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = attr_fgcol(p, *s);
+	bgx = attr_bgcol(p, *s);
+	fgx |= (fgx << 8);
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+	matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 16);
+	matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+	u_int32_t fgx, bgx;
+
+	fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+	matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
+	MINFO_FROM_DISP(p);
+
+	if (fontwidth(p) & 1) {
+		fbcon_cfb4_revc(p, xx, yy);
+		return;
+	}
+	yy *= fontheight(p);
+	xx *= fontwidth(p);
+	xx |= (xx + fontwidth(p)) << 16;
+	xx >>= 1;
+
+	mga_fifo(5);
+	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+	mga_outl(M_FCOL, 0xFFFFFFFF);
+	mga_outl(M_FXBNDRY, xx);
+	mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
+	mga_outl(M_LEN | M_EXEC, fontheight(p));
+	WaitTillIdle(MINFO);
+} 
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
+	MINFO_FROM_DISP(p);
+
+	yy *= fontheight(p);
+	xx *= fontwidth(p);
+
+	mga_fifo(4);
+	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+	mga_outl(M_FCOL, 0x0F0F0F0F);
+	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	WaitTillIdle(MINFO);
+}
+#endif
+
+static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
+	MINFO_FROM_DISP(p);
+
+	yy *= fontheight(p);
+	xx *= fontwidth(p);
+
+	mga_fifo(4);
+	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+	mga_outl(M_FCOL, 0xFFFFFFFF);
+	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
+	unsigned int bottom_height, right_width;
+	unsigned int bottom_start, right_start;
+	unsigned int cell_h, cell_w;
+
+	cell_w = fontwidth(p);
+	if (!cell_w) return;	/* PARANOID */
+	right_width = p->var.xres % cell_w;
+	right_start = p->var.xres - right_width;
+	if (!bottom_only && right_width) {
+		matroxfb_accel_clear(     PMXINFO(p)
+			     /* color */  0x00000000,
+			     /* y */      p->var.yoffset,
+			     /* x */      p->var.xoffset + right_start,
+			     /* height */ p->var.yres,
+			     /* width */  right_width);
+	}
+	cell_h = fontheight(p);
+	if (!cell_h) return;	/* PARANOID */
+	bottom_height = p->var.yres % cell_h;
+	if (bottom_height) {
+		bottom_start = p->var.yres - bottom_height;
+		matroxfb_accel_clear(		  PMXINFO(p)
+				     /* color */  0x00000000,
+				     /* y */	  p->var.yoffset + bottom_start,
+				     /* x */	  p->var.xoffset,
+				     /* height */ bottom_height,
+				     /* width */  right_start);
+	}
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void outTi3026(CPMINFO int reg, int val) {
+	mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+	mga_outb(M_RAMDAC_BASE+TVP3026_X_DATAREG, val);
+}
+
+static int inTi3026(CPMINFO int reg) {
+	mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+	return mga_inb(M_RAMDAC_BASE+TVP3026_X_DATAREG);
+}
+
+#define POS3026_XCURCTRL	20
+
+static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
+	MINFO_FROM_DISP(p);
+
+	if (mode == CM_ERASE) {
+		outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+		return;
+	}
+	x *= fontwidth(p);
+	y *= fontheight(p);
+	y -= p->var.yoffset;
+	if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y))) {
+		ACCESS_FBINFO(cursor.x) = x;
+		ACCESS_FBINFO(cursor.y) = y;
+		x += 64;
+		y += 64;
+		outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
+	}
+	outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | 2);
+}
+#undef POS3026_XCURCTRL
+
+static void matroxfb_ti3026_createcursor(WPMINFO int w, int h) {
+	u_int32_t xline;
+	int i;
+
+	ACCESS_FBINFO(cursor.w) = w;
+	ACCESS_FBINFO(cursor.h) = h;
+	xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
+	mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
+	for (i = 0; i < ACCESS_FBINFO(cursor.h); i++) {
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+	}
+	i *= 8;
+	for (; i < 512; i++)
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+	for (i = 0; i < 512; i++) 
+		mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
+}
+	
+static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
+	matroxfb_ti3026_createcursor(PMXINFO(p) width, height);
+	return 0;
+}
+#endif
+
+#define matrox_cfb16_revc matrox_cfbX_revc
+#define matrox_cfb24_revc matrox_cfbX_revc
+#define matrox_cfb32_revc matrox_cfbX_revc
+
+#define matrox_cfb24_clear matrox_cfb32_clear
+#define matrox_cfb24_putc matrox_cfb32_putc
+#define matrox_cfb24_putcs matrox_cfb32_putcs
+
+#ifdef FBCON_HAS_CFB4
+static struct display_switch matroxfb_cfb4 = {
+	fbcon_cfb4_setup,     matrox_cfb4_bmove,  matrox_cfb4_clear,
+	fbcon_cfb4_putc,      fbcon_cfb4_putcs,	  matrox_cfb4_revc,
+	NULL,		      NULL,		  NULL,
+	/* cursor... */       /* set_font... */
+	FONTWIDTH(8) /* fix, fix, fix it */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch matroxfb_cfb8 = {
+	fbcon_cfb8_setup,     matrox_cfbX_bmove,  matrox_cfb8_clear,
+	matrox_cfb8_putc,     matrox_cfb8_putcs,  matrox_cfb8_revc,
+	NULL,		      NULL,		  matrox_cfbX_clear_margins,
+	~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch matroxfb_cfb16 = {
+	fbcon_cfb16_setup,    matrox_cfbX_bmove,  matrox_cfb16_clear,
+	matrox_cfb16_putc,    matrox_cfb16_putcs, matrox_cfb16_revc,
+	NULL,		      NULL,		  matrox_cfbX_clear_margins,
+	~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static struct display_switch matroxfb_cfb24 = {
+	fbcon_cfb24_setup,    matrox_cfbX_bmove,  matrox_cfb24_clear,
+	matrox_cfb24_putc,    matrox_cfb24_putcs, matrox_cfb24_revc,
+	NULL,		      NULL,		  matrox_cfbX_clear_margins,
+	~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch matroxfb_cfb32 = {
+	fbcon_cfb32_setup,    matrox_cfbX_bmove,  matrox_cfb32_clear,
+	matrox_cfb32_putc,    matrox_cfb32_putcs, matrox_cfb32_revc,
+	NULL,		      NULL,		  matrox_cfbX_clear_margins,
+	~1 /* FONTWIDTHS */
+};
+#endif
+
+static struct pci_dev* pci_find(struct pci_dev* p) {
+	if (p) return p->next;
+	return pci_devices;
+}
+
+static void initMatrox(WPMINFO int con, struct display* p) {
+	struct display_switch *swtmp;
+
+	p->dispsw_data = NULL;
+	if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
+		switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+			case 4:
+				swtmp = &fbcon_cfb4;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB8
+			case 8:
+				swtmp = &fbcon_cfb8;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB16
+			case 16:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+				swtmp = &fbcon_cfb16;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB24
+			case 24:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+				swtmp = &fbcon_cfb24;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB32
+			case 32:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+				swtmp = &fbcon_cfb32;
+				break;
+#endif
+			default:
+				p->dispsw = &fbcon_dummy;
+				return;
+		}
+		dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
+	} else {
+		switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+			case 4:
+				swtmp = &matroxfb_cfb4;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB8
+			case 8:
+				swtmp = &matroxfb_cfb8;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB16
+			case 16:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+				swtmp = &matroxfb_cfb16;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB24
+			case 24:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+				swtmp = &matroxfb_cfb24;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB32
+			case 32:
+				p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+				swtmp = &matroxfb_cfb32;
+				break;
+#endif
+			default:
+				p->dispsw = &fbcon_dummy;
+				return;
+		}
+		dprintk(KERN_INFO "matroxfb: now accelerated\n");
+	}
+	memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
+	p->dispsw = &ACCESS_FBINFO(dispsw);
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	if (isMillenium(MINFO) && ACCESS_FBINFO(devflags.hwcursor)) {
+		ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
+		ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
+	}
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined __initdata = {
+	0,0,0,0,	/* W,H, W, H (virtual) load xres,xres_virtual*/
+	0,0,		/* virtual -> visible no offset */
+	8,		/* depth -> load bits_per_pixel */
+	0,		/* greyscale ? */
+	{0,0,0},	/* R */
+	{0,0,0},	/* G */
+	{0,0,0},	/* B */
+	{0,0,0},	/* transparency */
+	0,		/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	-1,-1,
+	FB_ACCELF_TEXT,	/* accel flags */
+	0L,0L,0L,0L,0L,
+	0L,0L,0,	/* No sync info */
+	FB_VMODE_NONINTERLACED,
+	{0,0,0,0,0,0}
+};
+
+
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(struct fb_var_screeninfo *var, struct matrox_fb_info* minfo) {
+	struct matroxfb_par* p = &ACCESS_FBINFO(curr);
+	unsigned int pos;
+	unsigned short p0, p1, p2;
+
+	p->var.xoffset = var->xoffset;
+	p->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		p->var.vmode |= FB_VMODE_YWRAP;
+	else
+		p->var.vmode &= FB_VMODE_YWRAP;
+	
+	pos = (p->var.yoffset * p->var.xres_virtual + p->var.xoffset) * p->final_bppShift / 32;
+	if (mga_ydstorg(MINFO)) {
+		if (isInterleave(MINFO))
+			pos += mga_ydstorg(MINFO) >> 3;
+		else
+			pos += mga_ydstorg(MINFO) >> 2;
+	}
+
+	p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
+	p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+	mga_setr(M_CRTC_INDEX, 0x0D, p0);
+	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+	mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+}
+
+	/*
+	 * Open/Release the frame buffer device
+	 */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+	/*
+	 * Nothing, only a usage count for the moment
+	 */
+	MOD_INC_USE_COUNT;
+	return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
+		struct fb_info* info) {
+#define minfo ((struct matrox_fb_info*)info)
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+			return -EINVAL;
+	}
+	if (con == ACCESS_FBINFO(currcon))
+		matrox_pan_var(var, MINFO);
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+#undef minfo
+}
+	
+static int matroxfb_updatevar(int con, struct fb_info *info)
+{
+	matrox_pan_var(&fb_display[con].var, (struct matrox_fb_info*)info);
+	return 0;
+}
+
+static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
+	int bppshft2;
+
+	bppshft2 = bpp;
+	if (isInterleave(MINFO))
+		bppshft2 >>= 1;
+	if (ACCESS_FBINFO(devflags.video64bits))
+		bppshft2 >>= 1;
+	return bppshft2;
+}
+				
+static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
+	int over;
+	int rounding;
+
+	switch (bpp) {
+		case 4:		rounding = 128;
+				break;
+		case 8:		rounding = 64;
+				break;
+		case 16:	rounding = 32;
+				break;
+		case 24:	rounding = 64;
+				break;
+		default:	rounding = 16;
+				break;
+	}
+	if (isInterleave(MINFO)) {
+		rounding *= 2;
+	}
+	over = xres % rounding;
+	if (over) 
+		xres += rounding-over;
+	return xres;
+}
+
+static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
+	const int* width;
+	int xres_new;
+
+	width = ACCESS_FBINFO(capable.vxres);
+
+	if (ACCESS_FBINFO(devflags.precise_width)) {
+		while (*width) {
+			if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
+				break;
+			}
+			width++;
+		}
+		xres_new = *width;
+	} else {
+		xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
+	}
+	if (!xres_new) return 0;
+	if (xres != xres_new) {
+		printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
+	}
+	return xres_new;
+}
+
+#ifdef NEED_DAC1064
+static void outDAC1064(CPMINFO int reg, int val) {
+	mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+	mga_outb(M_RAMDAC_BASE+M1064_X_DATAREG, val);
+}
+
+static int inDAC1064(CPMINFO int reg) {
+	mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+	return mga_inb(M_RAMDAC_BASE+M1064_X_DATAREG);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, 
+  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, 
+  TVP3026_XPALETTEPAGE, 
+  TVP3026_XGENCTRL, 
+  TVP3026_XMISCCTRL, 
+  TVP3026_XGENIOCTRL,
+  TVP3026_XGENIODATA, 
+  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+  TVP3026_XCOLKEYCTRL,
+  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL	0
+#define POS3026_XTRUECOLORCTRL	1
+#define POS3026_XMUXCTRL	2
+#define POS3026_XCLKCTRL	3
+#define POS3026_XGENCTRL	5
+#define POS3026_XMISCCTRL	6
+#define POS3026_XMEMPLLCTRL	18
+#define POS3026_XCURCTRL	20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, 
+  0x00, 
+  TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, 
+  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, 
+  0x00, 
+  0x1E, 
+  0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  TVP3026_XCOLKEYCTRL_ZOOM1, 
+  0x00, 0x00, TVP3026_XCURCTRL_DIS };
+#endif	/* CONFIG_FB_MATROX_MILLENIUM */
+
+static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int bestdiff = ~0;
+	unsigned int bestvco = 0;
+	unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq);
+	unsigned int fwant;
+	int p;
+
+	fwant = freq;
+
+#ifdef DEBUG
+	printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max));
+	printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq));
+	printk(KERN_ERR "freq: %d\n", freq);
+	printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min));
+	printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min));
+	printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max));
+	printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min));
+	printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max));
+	printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+	for (p = 0; p < ACCESS_FBINFO(features.pll.post_shift_max); p++) {
+		if (fwant * 2 > fmax)
+			break;
+		fwant *= 2;
+	}
+	if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min);
+	if (fwant > fmax) fwant = fmax;
+	for (; p >= 0; fwant >>= 1, bestdiff >>= 1, --p) {
+		int m;
+
+		if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break;
+		for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) {
+			unsigned int diff, fvco;
+			int n;
+
+			n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+			if (n > ACCESS_FBINFO(features.pll.feed_div_max)) 
+				break;
+			if (n < ACCESS_FBINFO(features.pll.feed_div_min))
+				n = ACCESS_FBINFO(features.pll.feed_div_min);
+			fvco = (fxtal * (n + 1)) / (m + 1);
+			if (fvco < fwant)
+				diff = fwant - fvco;
+			else
+				diff = fvco - fwant;
+			if (diff < bestdiff) {
+				bestdiff = diff;
+				*post = p;
+				*in = m;
+				*feed = n;
+				bestvco = fvco;
+			}
+		}
+	}
+	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+	return bestvco;
+}
+
+#ifdef NEED_DAC1064
+static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int fvco;
+	unsigned int p;
+
+	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
+	*post = p;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
+	unsigned int fvco;
+	unsigned int lin, lfeed, lpost;
+
+	fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
+	fvco >>= (*post = lpost);
+	*in = 64 - lin;
+	*feed = 64 - lfeed;
+	return fvco;
+}
+
+static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, int Bpp) {
+	unsigned int f_pll;
+	unsigned int pixfeed, pixin, pixpost;
+	unsigned int loopfeed, loopin, looppost, loopdiv, z;
+	
+	f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
+	
+	hw->DACclk[0] = pixin | 0xC0;
+	hw->DACclk[1] = pixfeed;
+	hw->DACclk[2] = pixpost | 0xB0;
+	if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+		loopfeed = 3;		/* set lm to any possible value */
+		loopin = 3 * 32 / Bpp;
+	} else {
+		loopfeed = 4;
+		loopin = 4 * 32 / Bpp;
+	}
+	z = (110000 * loopin) / (f_pll * loopfeed);
+	loopdiv = 0; /* div 2 */
+	if (z < 2)
+		looppost = 0;
+	else if (z < 4)
+		looppost = 1;
+	else if (z < 8)
+		looppost = 2;
+	else {
+		looppost = 3;
+		loopdiv = z/16; 
+	}
+	if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+		hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+		hw->DACclk[4] = (65 - loopfeed) | 0x80;
+		if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
+			if (isInterleave(MINFO))
+				hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+			else {
+				hw->DACclk[4] &= ~0xC0;
+				hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+			}
+		}
+		hw->DACclk[5] = looppost | 0xF8;
+		if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
+			hw->DACclk[5] ^= 0x40;
+	} else {
+		hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+		hw->DACclk[4] = 65 - loopfeed;
+		hw->DACclk[5] = looppost | 0xF0;
+	}
+	hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+	return 0;
+}
+#endif
+
+static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+	unsigned int pixclock = var->pixclock;
+	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+	mt->pixclock = 1000000000 / pixclock;
+	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+	mt->HDisplay = var->xres;
+	mt->HSyncStart = mt->HDisplay + var->right_margin;
+	mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+	mt->HTotal = mt->HSyncEnd + var->left_margin;
+	mt->VDisplay = var->yres;
+	mt->VSyncStart = mt->VDisplay + var->lower_margin;
+	mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+	mt->VTotal = mt->VSyncEnd + var->upper_margin;
+	mt->sync = var->sync;
+}
+
+static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	unsigned int hd, hs, he, ht;
+	unsigned int vd, vs, ve, vt;
+	unsigned int wd;
+	unsigned int divider;
+	int i;
+
+	hw->SEQ[0] = 0x00;
+	hw->SEQ[1] = 0x01;	/* or 0x09 */
+	hw->SEQ[2] = 0x0F;	/* bitplanes */
+	hw->SEQ[3] = 0x00;
+	hw->SEQ[4] = 0x0E;
+	/* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */
+	if (m->dblscan) {
+		m->VTotal <<= 1;
+		m->VDisplay <<= 1;
+		m->VSyncStart <<= 1;
+		m->VSyncEnd <<= 1;
+	}
+	if (m->interlaced) {
+		m->VTotal >>= 1;
+		m->VDisplay >>= 1;
+		m->VSyncStart >>= 1;
+		m->VSyncEnd >>= 1;
+	}
+
+	/* GCTL is ignored when not using 0xA0000 aperture */
+	hw->GCTL[0] = 0x00;
+	hw->GCTL[1] = 0x00;
+	hw->GCTL[2] = 0x00;
+	hw->GCTL[3] = 0x00;
+	hw->GCTL[4] = 0x00;
+	hw->GCTL[5] = 0x40;
+	hw->GCTL[6] = 0x05;
+	hw->GCTL[7] = 0x0F;
+	hw->GCTL[8] = 0xFF;
+
+	/* Whole ATTR is ignored in PowerGraphics mode */
+	for (i = 0; i < 16; i++)
+		hw->ATTR[i] = i;
+	hw->ATTR[16] = 0x41;
+	hw->ATTR[17] = 0xFF;
+	hw->ATTR[18] = 0x0F;
+	hw->ATTR[19] = 0x00;
+	hw->ATTR[20] = 0x00;
+
+	hd = m->HDisplay >> 3;
+	hs = m->HSyncStart >> 3;
+	he = m->HSyncEnd >> 3;
+	ht = m->HTotal >> 3;
+	/* standard timmings are in 8pixels, but for interleaved we cannot */
+	/* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+	/* using 16 or more pixels per unit can save us */
+	divider = ACCESS_FBINFO(curr.final_bppShift);
+	while (divider & 3) {
+		hd >>= 1;
+		hs >>= 1;
+		he >>= 1;
+		ht >>= 1;
+		divider <<= 1;
+	}
+	divider = divider / 4;
+	/* divider can be from 1 to 8 */
+	while (divider > 8) {
+		hd <<= 1;
+		hs <<= 1;
+		he <<= 1;
+		ht <<= 1;
+		divider >>= 1;
+	}
+	hd = hd - 1;
+	hs = hs - 1;
+	he = he - 1;
+	ht = ht - 1;
+	vd = m->VDisplay - 1;
+	vs = m->VSyncStart - 1;
+	ve = m->VSyncEnd - 1;
+	vt = m->VTotal - 2;
+	if (((ht & 0x0F) == 0x0E) || ((ht & 0x0F) == 0x04))
+		ht++;
+	wd = ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.final_bppShift) / 64;
+
+	hw->CRTCEXT[0] = 0;
+	hw->CRTCEXT[5] = 0;
+	if (m->interlaced) {
+		hw->CRTCEXT[0] = 0x80;
+		hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+		if (!m->dblscan)
+			wd <<= 1;
+		vt &= ~1;
+	}
+	hw->CRTCEXT[0] |=  (wd & 0x300) >> 4;
+	hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+			  ((hd      & 0x100) >> 7) | /* blanking */
+			  ((hs      & 0x100) >> 6) | /* sync start */
+			   (ht      & 0x040);	 /* end hor. blanking */
+	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
+			  ((vd & 0x400) >>  8) |	/* disp end */
+			  ((vd & 0xC00) >>  7) |	/* vblanking start */
+			  ((vs & 0xC00) >>  5);
+	hw->CRTCEXT[3] = (divider - 1) | 0x80;
+	hw->CRTCEXT[4] = 0;
+
+	hw->CRTC[0] = ht-4;
+	hw->CRTC[1] = hd;
+	hw->CRTC[2] = hd;
+	hw->CRTC[3] = (ht & 0x1F) | 0x80;
+	hw->CRTC[4] = hs;
+	hw->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F);
+	hw->CRTC[6] = vt & 0xFF;
+	hw->CRTC[7] = ((vt & 0x100) >> 8) |
+		      ((vd & 0x100) >> 7) |
+		      ((vs & 0x100) >> 6) |
+		      ((vd & 0x100) >> 5) |
+		      0x10                |
+		      ((vt & 0x200) >> 4) |
+		      ((vd & 0x200) >> 3) |
+		      ((vs & 0x200) >> 2);
+	hw->CRTC[8] = 0x00;
+	hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
+	if (m->dblscan && !m->interlaced)
+		hw->CRTC[9] |= 0x80;
+	for (i = 10; i < 16; i++)
+		hw->CRTC[i] = 0x00;
+	hw->CRTC[16] = vs /* & 0xFF */;
+	hw->CRTC[17] = (ve & 0x0F) | 0x20;
+	hw->CRTC[18] = vd /* & 0xFF */;
+	hw->CRTC[19] = wd /* & 0xFF */;
+	hw->CRTC[20] = 0x00;
+	hw->CRTC[21] = vd /* & 0xFF */;
+	hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+	hw->CRTC[23] = 0xC3;
+	hw->CRTC[24] = 0xFF;
+	return 0;
+};
+
+#ifdef NEED_DAC1064
+
+static const unsigned char MGA1064_DAC_regs[] = {
+		M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+		M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+		M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+		M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, 
+		DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, 
+		M1064_XMISCCTRL,
+		M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, 
+		M1064_XCRCBITSEL,
+		M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+#define POS1064_XVREFCTRL		12
+#define POS1064_XMULCTRL		13
+#define POS1064_XGENCTRL		15
+
+static const unsigned char MGA1064_DAC[] = {
+		0xFF, 0x1F/*Memsizedependent*/, M1064_XCURCTRL_DIS,
+		0x00, 0x00, 0x00, 	/* black */
+		0xFF, 0xFF, 0xFF,	/* white */
+		0xFF, 0x00, 0x00,	/* red */ 
+		0x00, 0,  
+		M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, 
+		M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, 
+		M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_VGA | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN,
+		0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, 
+		0x00,
+		0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
+	unsigned int m, n, p;
+
+	DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+	hw->DACclk[0] = m;
+	hw->DACclk[1] = n;
+	hw->DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem) {
+	u_int32_t mx;
+
+	mx = hw->MXoptionReg | 0x00000004;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	mx &= ~0x000000BB;
+	if (oscinfo & DAC1064_OPT_GDIV1)
+		mx |= 0x00000008;
+	if (oscinfo & DAC1064_OPT_MDIV1)
+		mx |= 0x00000010;
+	if (oscinfo & DAC1064_OPT_RESERVED)
+		mx |= 0x00000080;
+	if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+		/* select PCI clock until we have setup oscilator... */
+		int clk;
+		unsigned int m, n, p;
+
+		/* powerup system PLL, select PCI clock */
+		mx |= 0x00000020;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+		mx &= ~0x00000004;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+
+		/* !!! you must not access device if MCLK is not running !!!
+		   Doing so cause immediate PCI lockup :-( Maybe they should
+		   generate ABORT or I/O (parity...) error and Linux should 
+		   recover from this... (kill driver/process). But world is not
+		   perfect... */
+		/* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+		   select PLL... because of PLL can be stopped at this time) */
+		DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+		outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+		outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+		outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+		for (clk = 65536; clk; --clk) {
+			if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+				break;
+		}
+		if (!clk)
+			printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+		/* select PLL */
+		mx |= 0x00000005;
+	} else {
+		/* select specified system clock source */
+		mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+	}
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	mx &= ~0x00000004;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	hw->MXoptionReg = mx;
+}
+
+static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+	switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+		/* case 4: not supported by MGA1064 DAC */
+		case 8:	
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 16:
+			if (ACCESS_FBINFO(curr.var.green.length) == 5)
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			else
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 24: 
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 32:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		default:
+			return 1;	/* unsupported depth */
+	}
+	hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
+	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+	return 0;
+}
+
+static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	DAC1064_setpclk(PMINFO hw, m->pixclock);
+	if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 16) {	/* 256 entries */
+		int i;
+
+		for (i = 0; i < 256; i++) {
+			hw->DACpal[i * 3 + 0] = i;
+			hw->DACpal[i * 3 + 1] = i;
+			hw->DACpal[i * 3 + 2] = i;
+		}
+	} else if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 8) {
+		if (ACCESS_FBINFO(curr.var.green.length) == 5) {	/* 0..31, 128..159 */
+			int i;
+
+			for (i = 0; i < 32; i++) {
+				/* with p15 == 0 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 3;
+				hw->DACpal[i * 3 + 2] = i << 3;
+				/* with p15 == 1 */
+				hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+			}
+		} else {
+			int i;
+
+			for (i = 0; i < 64; i++) {		/* 0..63 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 2;
+				hw->DACpal[i * 3 + 2] = i << 3;
+			}
+		}
+	} else {
+		memset(hw->DACpal, 0, 768);
+	}
+	return 0;
+}
+
+static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+	outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
+	outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
+	outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
+	if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
+		int i;
+
+		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
+			outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
+	}
+}
+
+static void DAC1064_restore_2(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+	int i;
+	for (i = 0; i < 3; i++)
+		outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
+	while (!(inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40));
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "DAC1064regs ");
+	for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+		dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+	}
+	dprintk("\n" KERN_DEBUG "DAC1064clk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+	dprintk("\n");
+#endif
+}
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	if (DAC1064_init_1(PMINFO hw, m)) return 1;
+	if (vgaHWinit(PMINFO hw, m)) return 1;
+
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(PMINFO hw, m)) return 1;
+	return 0;		
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	if (DAC1064_init_1(PMINFO hw, m)) return 1;
+	hw->MXoptionReg &= ~0x2000;
+	if (vgaHWinit(PMINFO hw, m)) return 1;
+
+	hw->MiscOutReg = 0xEF;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(PMINFO hw, m)) return 1;
+	return 0;		
+}
+#endif	/* G100 */
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+	u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+
+	memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+	switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;	/* or _4_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 16:
+			/* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(curr.var.green.length) == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+			break;
+		case 24:
+			/* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			break;
+		case 32:
+			/* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			break;
+		default:
+			return 1;	/* TODO: failed */
+	}
+	if (vgaHWinit(PMINFO hw, m)) return 1;
+
+	/* set SYNC */
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+	if (m->sync & FB_SYNC_ON_GREEN)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+	/* set DELAY */
+	if (ACCESS_FBINFO(video_len) < 0x400000)
+		hw->CRTCEXT[3] |= 0x08;
+	else if (ACCESS_FBINFO(video_len) > 0x400000)
+		hw->CRTCEXT[3] |= 0x10;
+
+	/* set HWCURSOR */
+	if (m->interlaced) {
+		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+	}
+
+	/* set interleaving */
+	hw->MXoptionReg &= ~0x00001000;
+	if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+
+	/* set DAC */
+	Ti3026_setpclk(PMINFO hw, m->pixclock, ACCESS_FBINFO(curr.final_bppShift));
+	return 0;
+}
+#endif	/* CONFIG_FB_MATROX_MILLENIUM */
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+		case 4:
+			return 16;	/* pseudocolor... 16 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			return 256;	/* pseudocolor... 256 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB24
+		case 24:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+	}
+	return 16;	/* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len) {
+	unsigned int vramlen;
+	unsigned int memlen;
+
+	if ((var->xres > var->xres_virtual) || (var->yres > var->yres_virtual) || 
+	    (var->xoffset > var->xres_virtual) || (var->yoffset > var->yres_virtual))
+		return -EINVAL;
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+		case 4:	 if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
+			 break;
+#endif
+#ifdef FBCON_HAS_CFB8
+		case 8:	 break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16: break;
+#endif
+#ifdef FBCON_HAS_CFB24
+		case 24: break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32: break;
+#endif
+		default: return -EINVAL;
+	}
+	vramlen = ACCESS_FBINFO(video_len);
+	if (vramlen > 0x800000) vramlen = 0x800000;
+	var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
+	memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+	if (memlen > vramlen) 
+		return -EINVAL;	/* out of memory */
+	/* There is hardware bug that no line can cross 4MB boundary */
+	/* give up for CFB24, it is impossible to easy workaround it */
+	/* for other try to do something */
+	if ((memlen > 0x400000) && (var->bits_per_pixel != 24)) {
+		int new_xres = var->xres_virtual;
+
+		if (new_xres <= 512)
+			new_xres = 512;
+		else if (new_xres <= 1024)
+			new_xres = 1024;
+		else if (new_xres <= 2048)
+			new_xres = 2048;
+		else
+			new_xres = var->xres_virtual;
+		memlen = new_xres * var->bits_per_pixel / 8;
+		/* if now out of memory, try shrink virtual height */
+		/* but if new virtual height is smaller than visible height, return -EINVAL */
+		if (var->yres_virtual * memlen > vramlen) {
+			int new_yres;
+
+			new_yres = vramlen / memlen;
+			if (new_yres < var->yres)
+				return -EINVAL;
+			var->yres_virtual = new_yres;
+		}
+		var->xres_virtual = new_xres;
+	}
+
+	if (var->bits_per_pixel == 4) {
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		*visual = MX_VISUAL_PSEUDOCOLOR;
+	} else if (var->bits_per_pixel <= 8) {
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		*visual = MX_VISUAL_PSEUDOCOLOR;
+	} else {
+		if (var->bits_per_pixel <= 16) {
+			if (var->green.length == 5) {
+				var->red.offset    = 10;
+				var->red.length    = 5;
+				var->green.offset  = 5;
+				var->green.length  = 5;
+				var->blue.offset   = 0;
+				var->blue.length   = 5;
+				var->transp.offset = 15;
+				var->transp.length = 1;
+			} else {
+				var->red.offset    = 11;
+				var->red.length    = 5;
+				var->green.offset  = 5;
+				var->green.length  = 6;
+				var->blue.offset   = 0;
+				var->blue.length   = 5;
+				var->transp.offset = 0;
+				var->transp.length = 0;
+			}
+		} else if (var->bits_per_pixel <= 24) {
+			var->red.offset    = 16;
+			var->red.length    = 8;
+			var->green.offset  = 8;
+			var->green.length  = 8;
+			var->blue.offset   = 0;
+			var->blue.length   = 8;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		} else {
+			var->red.offset    = 16;
+			var->red.length    = 8;
+			var->green.offset  = 8;
+			var->green.length  = 8;
+			var->blue.offset   = 0;
+			var->blue.length   = 8;
+			var->transp.offset = 24;
+			var->transp.length = 8;
+		}
+		dprintk("matroxfb: truecolor: "
+		       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+		       var->transp.length,
+		       var->red.length,
+		       var->green.length,
+		       var->blue.length,
+		       var->transp.offset,
+		       var->red.offset,
+		       var->green.offset,
+		       var->blue.offset);
+		*visual = MX_VISUAL_DIRECTCOLOR;
+	}
+	*video_cmap_len = matroxfb_get_cmap_len(var);
+	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+				var->xres_virtual, var->yres_virtual);
+	return 0;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+	unsigned int f_pll;
+	unsigned int pclk_m, pclk_n, pclk_p;
+	unsigned int mclk_m, mclk_n, mclk_p;
+	unsigned int rfhcnt, mclk_ctl;
+	int tmout;
+
+	f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
+
+	/* save pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
+	pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	
+	/* stop pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	/* set pclk to new mclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+	
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	};
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+	/* output pclk on mclk pin */
+	mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop MCLK */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
+
+	/* set mclk to new freq */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) 
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+	f_pll = f_pll * 333 / (10000 << mclk_p);	
+	if (isMilleniumII(MINFO)) {
+		rfhcnt = (f_pll - 128) / 256;
+		if (rfhcnt > 15)
+			rfhcnt = 15;
+	} else {
+		rfhcnt = (f_pll - 64) / 128;
+		if (rfhcnt > 15)
+			rfhcnt = 0;
+	}
+	hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); 
+
+	/* output MCLK to MCLK pin */	
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop PCLK */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	/* restore pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+	ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; 
+	ACCESS_FBINFO(features.pll.ref_freq)     = 114545;
+	ACCESS_FBINFO(features.pll.feed_div_min) = 2;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 24;
+	ACCESS_FBINFO(features.pll.in_div_min)   = 2;
+	ACCESS_FBINFO(features.pll.in_div_max)   = 63;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	ACCESS_FBINFO(max_pixel_clock) = 220000;
+	ti3026_setMCLK(PMINFO hw, 60000);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+	unsigned char rev;
+
+	/* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
+	ACCESS_FBINFO(features.pll.vco_freq_min) = 50000; 
+	ACCESS_FBINFO(features.pll.ref_freq)     = 14318;
+	ACCESS_FBINFO(features.pll.feed_div_min) = 100;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+	ACCESS_FBINFO(features.pll.in_div_min)   = 1;
+	ACCESS_FBINFO(features.pll.in_div_max)   = 31;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
+	/* I hope */
+	pci_read_config_byte(ACCESS_FBINFO(pcidev), PCI_REVISION_ID, &rev);
+	if (rev < 3)
+		ACCESS_FBINFO(max_pixel_clock) = 170000;
+	else
+		ACCESS_FBINFO(max_pixel_clock) = 220000;
+	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+	DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+
+__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960, 
+					     1024, 1152, 1280,      1600, 1664, 1920, 
+					     2048,    0};
+	/* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+	ACCESS_FBINFO(capable.vxres) = vxres_mystique;
+	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00094E20;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+	mga_outl(M_CTLWTST, 0x00000000);
+	udelay(200);
+	mga_outl(M_MACCESS, 0x00008000);
+	udelay(100);
+	mga_outl(M_MACCESS, 0x0000C000);
+	return 0;
+}
+
+__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+	MGA1064_ramdac_init(PMINFO hw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+/* BIOS environ */
+static int x7AF4 = 0;    /* flags */
+#if 0
+static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+#if 0
+__initfunc(static int G100_ReadFeatureConn(const struct matrox_fb_info* minfo)) {
+	int ret;
+
+	mga_outb(M_3DA_WR, 0x01);
+	ret =        (mga_inb(M_3C2_RD) >> 5) & 0x03;
+	mga_outb(M_3DA_WR, 0x02);
+	return ret | ((mga_inb(M_3C2_RD) >> 3) & 0x0C);
+}
+#endif
+
+__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+	int reg;
+	int selClk;
+	int clk;
+
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS);
+	switch (flags & 3) {
+		case 0:		reg = M1064_XPIXPLLAM; break;
+		case 1:		reg = M1064_XPIXPLLBM; break;
+		default:	reg = M1064_XPIXPLLCM; break;
+	}
+	outDAC1064(PMINFO reg++, m);
+	outDAC1064(PMINFO reg++, n);
+	outDAC1064(PMINFO reg, p);
+	selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+	/* there should be flags & 0x03 & case 0/1/else */
+	/* and we should first select source and after that we should wait for PLL */
+	/* and we are waiting for PLL with oscilator disabled... Is it right? */
+	switch (flags & 0x03) {
+		case 0x00:	break;
+		case 0x01:	selClk |= 4; break;
+		default:	selClk |= 0x0C; break;
+	}
+	mga_outb(M_MISC_REG, selClk);
+	for (clk = 65536; clk; clk--)
+		if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+			break;
+	if (!clk)
+		printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+	selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+	switch (flags & 0x0C) {
+		case 0x00:	selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+		case 0x04:	selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+		default:	selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+	}
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+	unsigned int m, n, p;
+
+	DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+	MGAG100_progPixClock(PMINFO flags, m, n, p);
+}
+
+__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960, 
+                                          1024, 1152, 1280,      1600, 1664, 1920, 
+                                          2048, 0};
+#if 0
+	u_int32_t reg50;
+	u_int32_t q;
+#endif
+
+	/* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+	ACCESS_FBINFO(capable.vxres) = vxres_g100;
+	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+	
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00078C20;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+	mga_outl(M_CTLWTST, 0x03258A31);	/* 03258A31 is x7AF0, default is 0x02032521 */
+#if 0
+	hw->MXoptionReg |= 0x1000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, &reg50);
+	q = def50 & 0x3000;
+	reg50 = (reg50 & ~0x3000) | q;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
+	mga_outb(0x1C05, 0x00);
+	mga_outb(0x1C05, 0x80);
+	udelay(100);
+	mga_outb(0x1C05, 0x40);
+	mga_outb(0x1C05, 0xC0);
+	pci_write_config_byte(ACCESS_FBINFO(pcidev), 0x50, def50 & 0x0F);
+	{
+		volatile u_int8_t* ptr;
+		mga_outb(M_GRAPHICS_INDEX, 6);
+		mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+		mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+		mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+		ptr = ACCESS_FBINFO(video_vbase);
+		ptr[0x000] = 0xAA;
+		ptr[0x800] = 0x55;
+		if (ptr[0x000] != 0xAA) {
+			hw->MXoptionReg &= ~0x1000;
+		}
+	}
+#endif
+	hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
+#if 0
+	if (!(x7AF4 & 0x10))
+		hw->MXoptionReg |= 0x4000;
+#endif
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	return 0;
+}
+	
+__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+	u_int8_t b;
+
+	ACCESS_FBINFO(features.pll.vco_freq_min) = 50000;
+	ACCESS_FBINFO(features.pll.ref_freq)     = 27000;
+	ACCESS_FBINFO(features.pll.feed_div_min) = 7;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+	ACCESS_FBINFO(features.pll.in_div_min)   = 1;
+	ACCESS_FBINFO(features.pll.in_div_max)   = 31;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
+	ACCESS_FBINFO(max_pixel_clock) = 220000;
+
+	{
+#ifdef G100_BROKEN_IBM_82351
+		u_int32_t d;
+
+		find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+		pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+		if (b == ACCESS_FBINFO(pcidev)->bus->number) {
+			pci_write_config_byte(ibm, PCI_COMMAND+1, 0);	/* disable back-to-back & SERR */
+			pci_write_config_byte(ibm, 0x41, 0xF4);		/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);	/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00);	/* ??? */
+		}
+#endif
+		if (x7AF4 & 8) {
+			hw->MXoptionReg |= 0x40;
+			pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+		}
+		mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
+	}
+	DAC1064_setmclk(PMINFO hw, DAC1064_OPT_SCLK_PLL, 120000);
+	MGAG100_setPixClock(PMINFO 4, 25175);
+	MGAG100_setPixClock(PMINFO 5, 28322);
+	if (x7AF4 & 0x10) {
+		b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
+		outDAC1064(PMINFO M1064_XGENIODATA, b);
+		b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
+		outDAC1064(PMINFO M1064_XGENIOCTRL, b);
+	}
+}
+#endif
+
+static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
+	int i;
+
+	dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+	dprintk(KERN_INFO "SEQ regs:   ");
+	for (i = 0; i < 5; i++)
+		dprintk("%02X:", hw->SEQ[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "GDC regs:   ");
+	for (i = 0; i < 9; i++)
+		dprintk("%02X:", hw->GCTL[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "CRTC regs: ");
+	for (i = 0; i < 25; i++)
+		dprintk("%02X:", hw->CRTC[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "ATTR regs: ");
+	for (i = 0; i < 21; i++)
+		dprintk("%02X:", hw->ATTR[i]);
+	dprintk("\n");
+
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0);
+	mga_outb(M_MISC_REG, hw->MiscOutReg);
+	for (i = 1; i < 5; i++)
+		mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+	mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+	for (i = 0; i < 25; i++)
+		mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+	for (i = 0; i < 9; i++)
+		mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+	for (i = 0; i < 21; i++) {
+		mga_inb(M_ATTR_RESET);
+		mga_outb(M_ATTR_INDEX, i);
+		mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+	}
+	mga_outb(M_PALETTE_MASK, 0xFF);
+	mga_outb(M_DAC_REG, 0x00);
+	for (i = 0; i < 768; i++)
+		mga_outb(M_DAC_VAL, hw->DACpal[i]);
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0x20);
+}
+
+static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *fb_info)
+{
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+	struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+#endif
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+	
+	if (regno >= ACCESS_FBINFO(curr.cmap_len))
+		return 1;
+	
+	ACCESS_FBINFO(palette[regno].red)   = red;
+	ACCESS_FBINFO(palette[regno].green) = green;
+	ACCESS_FBINFO(palette[regno].blue)  = blue;
+	ACCESS_FBINFO(palette[regno].transp) = transp;
+
+	red = CNVT_TOHW(red, ACCESS_FBINFO(curr.var.red.length));
+	green = CNVT_TOHW(green, ACCESS_FBINFO(curr.var.green.length));
+	blue = CNVT_TOHW(blue, ACCESS_FBINFO(curr.var.blue.length));
+	transp = CNVT_TOHW(transp, ACCESS_FBINFO(curr.var.transp.length));
+
+	switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4)
+#ifdef FBCON_HAS_CFB4
+	case 4:
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+#endif
+		mga_outb(M_DAC_REG, regno);
+		mga_outb(M_DAC_VAL, red);
+		mga_outb(M_DAC_VAL, green);
+		mga_outb(M_DAC_VAL, blue);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16	
+	case 16:
+		ACCESS_FBINFO(cmap.cfb16[regno]) =
+			(red << ACCESS_FBINFO(curr.var.red.offset))     | 
+			(green << ACCESS_FBINFO(curr.var.green.offset)) | 
+			(blue << ACCESS_FBINFO(curr.var.blue.offset))   |
+			(transp << ACCESS_FBINFO(curr.var.transp.offset)); /* for 1:5:5:5 */
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		ACCESS_FBINFO(cmap.cfb24[regno]) =
+			(red   << ACCESS_FBINFO(curr.var.red.offset))   |
+			(green << ACCESS_FBINFO(curr.var.green.offset)) |
+			(blue  << ACCESS_FBINFO(curr.var.blue.offset));
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		ACCESS_FBINFO(cmap.cfb32[regno]) =
+			(red   << ACCESS_FBINFO(curr.var.red.offset))   |
+			(green << ACCESS_FBINFO(curr.var.green.offset)) |
+			(blue  << ACCESS_FBINFO(curr.var.blue.offset))  |
+			(transp << ACCESS_FBINFO(curr.var.transp.offset));	/* 8:8:8:8 */
+		break;
+#endif
+	}
+	return 0;
+}
+
+static void do_install_cmap(WPMINFO int con)
+{
+	struct display* dsp;
+
+	if (con != ACCESS_FBINFO(currcon))
+		return;
+	if (con >= 0)
+		dsp = fb_display+con;
+	else
+		dsp = ACCESS_FBINFO(fbcon.disp);
+	if (dsp->cmap.len)
+		fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+	else
+		fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
+			    1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+}
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+	int i;
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	mga_outb(M_IEN, 0x00);
+	mga_outb(M_CACHEFLUSH, 0x00);
+	DAC1064_restore_1(PMINFO hw, oldhw);
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	vgaHWrestore(PMINFO hw, oldhw);
+	DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+	int i;
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	DAC1064_restore_1(PMINFO hw, oldhw);
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	vgaHWrestore(PMINFO hw, oldhw);
+	DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+	int i;
+
+	dprintk(KERN_INFO "EXTVGA regs: ");
+	for (i = 0; i < 6; i++)
+		dprintk("%02X:", hw->CRTCEXT[i]);
+	dprintk("\n");
+
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+	vgaHWrestore(PMINFO hw, oldhw);
+
+	for (i = 0; i < 21; i++) {
+		outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
+	}
+	if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
+		/* agrhh... setting up PLL is very slow on Millenium... */
+		/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
+		/* Maybe even we should call schedule() ? */
+
+		outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+		outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
+		outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
+
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+		for (i = 0; i < 3; i++)
+			outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+		/* wait for PLL only if PLL clock requested (always for PowerMode) */
+		if (hw->MiscOutReg & 0x08) {
+			int tmout;
+			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) 
+					break;
+				udelay(10);
+			}
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+		}
+		outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+		for (i = 3; i < 6; i++)
+			outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[3] & 0xC0) == 0xC0)) {
+			int tmout;
+
+			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) 
+					break;
+				udelay(10);
+			}
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+		}
+	}
+	matroxfb_ti3026_createcursor(PMINFO fontwidth(p), fontheight(p));
+
+	dprintk(KERN_DEBUG "3026DACregs ");
+	for (i = 0; i < 21; i++) {
+		dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+	}
+	dprintk("\n" KERN_DEBUG "DACclk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+	dprintk("\n");
+}
+#endif
+
+static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id,"MATROX");
+
+	fix->smem_start = (void*)ACCESS_FBINFO(video_base);
+	fix->smem_len = ACCESS_FBINFO(video_len);
+	fix->type = ACCESS_FBINFO(curr.video_type);
+	fix->visual = ACCESS_FBINFO(curr.visual);
+	fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = (ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.var.bits_per_pixel)) >> 3;
+	fix->mmio_start = (void*)ACCESS_FBINFO(mmio_base);
+	fix->mmio_len = ACCESS_FBINFO(mmio_len);
+	fix->accel = ACCESS_FBINFO(devflags.accelerator);
+	return 0;
+#undef minfo
+}
+
+static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	if(con < 0)
+		*var=ACCESS_FBINFO2(info, curr.var);
+	else
+		*var=fb_display[con].var;
+	return 0;
+}
+
+static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+	int err;
+	int visual;
+	int cmap_len;
+	struct display* display;
+	int chgvar;
+
+	if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len)) != 0) 
+		return err;
+	switch (var->activate & FB_ACTIVATE_MASK) {
+		case FB_ACTIVATE_TEST:	return 0;
+		case FB_ACTIVATE_NXTOPEN:	/* ?? */
+		case FB_ACTIVATE_NOW:   break;	/* continue */
+		default:		return -EINVAL; /* unknown */
+	}
+	if (con >= 0) {
+		display = fb_display+con;
+		chgvar = ((display->var.xres != var->xres) || 
+		    (display->var.yres != var->yres) || 
+                    (display->var.xres_virtual != var->xres_virtual) ||
+		    (display->var.yres_virtual != var->yres_virtual) || 
+		    (display->var.bits_per_pixel != var->bits_per_pixel) ||
+		    memcmp(&display->var.red, &var->red, sizeof(var->red)) || 
+		    memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
+		    memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
+	} else {
+		display = ACCESS_FBINFO(fbcon.disp);
+		chgvar = 0;
+	}
+	display->var = *var;
+	/* cmap */
+	display->screen_base = ACCESS_FBINFO(video_vbase);
+	display->visual = visual;
+	display->type = FB_TYPE_PACKED_PIXELS;
+	display->type_aux = 0;
+	display->ypanstep = 1;
+	display->ywrapstep = 0;
+	display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+	display->can_soft_blank = 1;
+	display->inverse = ACCESS_FBINFO(devflags.inverse);
+	/* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
+	/* next_plane, fontdata, _font*, userfont */
+	initMatrox(PMINFO con, display);	/* dispsw */
+	/* dispsw, scrollmode, yscroll */
+	/* fgshift, bgshift, charmask */
+	if (chgvar && info && info->changevar)
+		info->changevar(con);
+	if (con == ACCESS_FBINFO(currcon)) {
+		unsigned int pos;
+
+		ACCESS_FBINFO(curr.var) = *var;
+		ACCESS_FBINFO(curr.visual) = visual;
+		ACCESS_FBINFO(curr.cmap_len) = cmap_len;
+		ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
+		if (visual == MX_VISUAL_PSEUDOCOLOR) {
+			int i;
+
+			for (i = 0; i < 16; i++) {
+				int j;
+
+				j = color_table[i];
+				ACCESS_FBINFO(palette[i].red)   = default_red[j];
+				ACCESS_FBINFO(palette[i].green) = default_grn[j];
+				ACCESS_FBINFO(palette[i].blue)  = default_blu[j];
+			}
+		}
+
+		{	struct my_timming mt;
+			struct matrox_hw_state* hw;
+			struct matrox_hw_state* ohw;
+
+			var2my(var, &mt);
+			hw = ACCESS_FBINFO(newhw);
+			ohw = ACCESS_FBINFO(currenthw);
+
+			/* MXoptionReg is not set from scratch */
+			hw->MXoptionReg = ohw->MXoptionReg;
+			/* DACclk[3]..[5] are not initialized with DAC1064 */
+			memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk));
+			/* others are initialized by init() */
+
+			ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt));
+			pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+			if (mga_ydstorg(MINFO)) {
+				if (isInterleave(MINFO))
+					pos += mga_ydstorg(MINFO) >> 3;
+				else
+					pos += mga_ydstorg(MINFO) >> 2;
+			}
+
+			hw->CRTC[0x0D] = pos & 0xFF;
+			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+			ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
+			ACCESS_FBINFO(currenthw) = hw;
+			ACCESS_FBINFO(newhw) = ohw;
+			matrox_cfbX_init(MINFO);
+			do_install_cmap(PMINFO con);
+		}
+	}
+	return 0;
+#undef minfo
+}
+
+static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			    unsigned *blue, unsigned *transp,
+			    struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+	/*
+	 *  Read a single color register and split it into colors/transparent.
+	 *  Return != 0 for invalid regno.
+	 */
+
+	if (regno >= ACCESS_FBINFO(curr.cmap_len))
+		return 1;
+
+	*red   = ACCESS_FBINFO(palette[regno].red);
+	*green = ACCESS_FBINFO(palette[regno].green);
+	*blue  = ACCESS_FBINFO(palette[regno].blue);
+	*transp = ACCESS_FBINFO(palette[regno].transp);
+	return 0;
+#undef minfo
+}
+
+static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	struct display* dsp = (con < 0) ? info->disp : fb_display+con;
+
+	if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */
+		return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
+	else if (dsp->cmap.len) /* non default colormap? */
+		fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
+			     cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	int cmap_len;
+	struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
+
+	cmap_len = matroxfb_get_cmap_len(&dsp->var);
+	if (dsp->cmap.len != cmap_len) {
+		int err;
+
+		err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
+		if (err)
+			return err;
+	}
+	if (con == ACCESS_FBINFO2(info, currcon))			/* current console? */
+		return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+	else
+		fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
+	return 0;
+}
+
+static int matroxfb_ioctl(struct inode *inode, struct file *file, 
+			  unsigned int cmd, unsigned long arg, int con,
+			  struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static struct fb_ops matroxfb_ops = {
+	matroxfb_open,
+	matroxfb_release,
+	matroxfb_get_fix,
+	matroxfb_get_var,
+	matroxfb_set_var,
+	matroxfb_get_cmap,
+	matroxfb_set_cmap,
+	matroxfb_pan_display,
+	matroxfb_ioctl,
+	NULL			/* mmap */
+};
+
+static int matroxfb_switch(int con, struct fb_info *info)
+{
+	struct fb_cmap* cmap;
+	if (ACCESS_FBINFO2(info, currcon) >= 0) {
+		/* Do we have to save the colormap? */
+		cmap = &fb_display[ACCESS_FBINFO2(info, currcon)].cmap;
+		dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO2(info, currcon), cmap->len);
+
+		if (cmap->len) {
+			dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+			fb_get_cmap(cmap, 1, matrox_getcolreg, info);
+#ifdef DEBUG
+			if (cmap->red) {
+				dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
+			}
+#endif
+		}
+	}
+	ACCESS_FBINFO2(info, currcon) = con;
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+#ifdef DEBUG
+	cmap = &fb_display[con].cmap;
+	dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
+	dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+	if (fb_display[con].cmap.red) {
+		dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
+	}
+#endif
+	matroxfb_set_var(&fb_display[con].var, con, info);
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
+	dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+	if (fb_display[con].cmap.red) {
+		dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
+	}
+#endif
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+	int seq;
+	int crtc;
+
+	switch (blank) {
+		case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+		case 2:  seq = 0x20; crtc = 0x10; break;
+		case 3:  seq = 0x20; crtc = 0x20; break;
+		case 4:  seq = 0x20; crtc = 0x30; break;
+		default: seq = 0x00; crtc = 0x00; break;
+	}
+	mga_outb(M_SEQ_INDEX, 1);
+	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+	mga_outb(M_EXTVGA_INDEX, 1);
+	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+#undef minfo
+}
+
+#define RSResolution(X)	((X) & 0x0F)
+#define RS640x400	1
+#define RS640x480	2
+#define RS800x600	3
+#define RS1024x768	4
+#define RS1280x1024	5
+#define RS1600x1200	6
+#define RS768x576	7
+#define RS960x720	8
+#define RS1152x864	9
+#define RS1408x1056	10
+/* B-F */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
+	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
+	{  800,  600, 144, 24, 28,  8, 112, 6, 60 },
+	{ 1024,  768, 160, 32, 30,  4, 128, 4, 60 },
+	{ 1280, 1024, 224, 32, 32,  4, 136, 4, 60 },
+	{ 1600, 1200, 272, 48, 32,  5, 152, 5, 60 },
+	{  768,  576, 144, 16, 28,  6, 112, 4, 60 },
+	{  960,  720, 144, 24, 28,  8, 112, 4, 60 },
+	{ 1152,  864, 192, 32, 30,  4, 128, 4, 60 },
+	{ 1408, 1056, 256, 40, 32,  5, 144, 5, 60 }
+};
+
+#define RSDepth(X)	(((X) >> 4) & 0x0F)
+#define RS8bpp		0x1
+#define RS15bpp		0x2
+#define RS16bpp		0x3
+#define RS32bpp		0x4
+#define RS4bpp		0x5
+#define RS24bpp		0x6
+/* 7-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = {
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  8 },
+	{ { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+	{ { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, {  0, 0, 0}, 16 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 }
+};
+
+#define RSCreate(X,Y)	((X) | ((Y) << 4))
+static struct { int vesa; int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+#ifdef FBCON_HAS_CFB8
+	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
+	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
+	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
+	{ 0x103, RSCreate(RS800x600,   RS8bpp ) },
+	{ 0x188, RSCreate(RS960x720,   RS8bpp ) },
+	{ 0x105, RSCreate(RS1024x768,  RS8bpp ) },
+	{ 0x190, RSCreate(RS1152x864,  RS8bpp ) },
+	{ 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB4
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB16
+	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
+	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
+	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
+	{ 0x189, RSCreate(RS960x720,   RS15bpp) },
+	{ 0x116, RSCreate(RS1024x768,  RS15bpp) },
+	{ 0x191, RSCreate(RS1152x864,  RS15bpp) },
+	{ 0x119, RSCreate(RS1280x1024, RS15bpp) },
+	{ 0x199, RSCreate(RS1408x1056, RS15bpp) },
+	{ 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+	{ 0x111, RSCreate(RS640x480,   RS16bpp) },
+	{ 0x182, RSCreate(RS768x576,   RS16bpp) },
+	{ 0x114, RSCreate(RS800x600,   RS16bpp) },
+	{ 0x18A, RSCreate(RS960x720,   RS16bpp) },
+	{ 0x117, RSCreate(RS1024x768,  RS16bpp) },
+	{ 0x192, RSCreate(RS1152x864,  RS16bpp) },
+	{ 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+	{ 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+#endif
+#ifdef FBCON_HAS_CFB24
+	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
+	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
+	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
+	{ 0x18C, RSCreate(RS960x720,   RS24bpp) },
+	{ 0x1B8, RSCreate(RS1024x768,  RS24bpp) },
+	{ 0x194, RSCreate(RS1152x864,  RS24bpp) },
+	{ 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+	{ 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+#endif
+#ifdef FBCON_HAS_CFB32
+	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
+	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
+	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
+	{ 0x18B, RSCreate(RS960x720,   RS32bpp) },
+	{ 0x118, RSCreate(RS1024x768,  RS32bpp) },
+	{ 0x193, RSCreate(RS1152x864,  RS32bpp) },
+	{ 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+	{ 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+#endif
+	{     0, 0                                 }};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem = 0;		/* "matrox:mem:xxxxxM" */
+static int option_precise_width = 1;	/* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24 = 0;			/* "matrox:inv24" */
+static int disabled = 0;		/* "matrox:disabled" */
+static int noaccel = 0;			/* "matrox:noaccel" */
+static int nopan = 0;			/* "matrox:nopan" */
+static int no_pci_retry = 0;		/* "matrox:nopciretry" */
+static int novga = 0;			/* "matrox:novga" */
+static int nobios = 0;			/* "matrox:nobios" */
+static int inverse = 0;			/* "matrox:inverse" */
+static int hwcursor = 0;		/* "matrox:hwcursor" */
+static int dev = -1;			/* "matrox:dev:xxxxx" */
+static unsigned int vesa = 0x101;	/* "matrox:vesa:xxxxx" */
+static unsigned int depth = 0;		/* "matrox:depth:xxxxx" */
+static unsigned int xres = 0;		/* "matrox:xres:xxxxx" */
+static unsigned int yres = 0;		/* "matrox:yres:xxxxx" */
+static unsigned int upper = 0;		/* "matrox:upper:xxxxx" */
+static unsigned int lower = 0;		/* "matrox:lower:xxxxx" */
+static unsigned int vslen = 0;		/* "matrox:vslen:xxxxx" */
+static unsigned int left = 0;		/* "matrox:left:xxxxx" */
+static unsigned int right = 0;		/* "matrox:right:xxxxx" */
+static unsigned int hslen = 0;		/* "matrox:hslen:xxxxx" */
+static unsigned int pixclock = 0;	/* "matrox:pixclock:xxxxx" */
+static int sync = -1;			/* "matrox:sync:xxxxx" */
+static int fv = 0;			/* "matrox:fv:xxxxx" */
+static int fh = 0;			/* "matrox:fh:xxxxxk" */
+static int maxclk = 0;			/* "matrox:maxclk:xxxxM" */
+static char fontname[64];		/* "matrox:font:xxxxx" */
+
+#ifndef MODULE
+__initfunc(void matroxfb_setup(char *options, int *ints)) {
+	char *this_opt;
+	
+	fontname[0] = '\0';
+	
+	if (!options || !*options)
+		return;
+	
+	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+		if (!*this_opt) continue;
+		
+		dprintk("matroxfb_setup: option %s\n", this_opt);
+		
+		if (! strcmp(this_opt, "inverse"))
+			inverse = 1;
+		else if (!strcmp(this_opt, "disabled"))
+			disabled = 1;
+		else if (!strcmp(this_opt, "noaccel"))
+			noaccel = 1;
+		else if (!strcmp(this_opt, "nopan"))
+			nopan = 1;
+		else if (!strcmp(this_opt, "nopciretry"))
+			no_pci_retry = 1;
+		else if (!strcmp(this_opt, "novga"))
+			novga = 1;
+		else if (!strcmp(this_opt, "nobios"))
+			nobios = 1;
+		else if (!strcmp(this_opt, "inv24"))
+			inv24 = 1;
+		else if (!strcmp(this_opt, "hwcursor"))
+			hwcursor = 1;
+		else if (!strncmp(this_opt, "dev:", 4))
+			dev = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "depth:", 6)) {
+			switch (simple_strtoul(this_opt+6, NULL, 0)) {
+				case 4: depth = RS4bpp; break;
+				case 8: depth = RS8bpp; break;
+				case 15:depth = RS15bpp; break;
+				case 16:depth = RS16bpp; break;
+				case 24:depth = RS24bpp; break;
+				case 32:depth = RS32bpp; break;
+				default:
+					printk(KERN_ERR "matroxfb: unsupported color depth\n");
+			}
+		} else if (!strncmp(this_opt, "xres:", 5))
+			xres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "yres:", 5))
+			yres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vslen:", 6))
+			vslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "hslen:", 6))
+			hslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "left:", 5))
+			left = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "right:", 6))
+			right = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "upper:", 6))
+			upper = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "lower:", 6))
+			lower = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "pixclock:", 9))
+			pixclock = simple_strtoul(this_opt+9, NULL, 0);
+		else if (!strncmp(this_opt, "sync:", 5))
+			sync = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vesa:", 5)) 
+			vesa = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "font:", 5))
+			strcpy(fontname, this_opt+5);
+		else if (!strncmp(this_opt, "maxclk:", 7))
+			maxclk = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "fh:", 3))
+			fh = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "fv:", 3)) 
+			fv = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "mem:", 4)) 
+			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else {
+			printk(KERN_ERR "matroxfb: unknown parameter %s\n", this_opt);
+		}
+	}
+}
+#endif
+
+__initfunc(static int matroxfb_getmemory(WPMINFO int maxSize, unsigned int* realOffset, int *realSize)) {
+	volatile unsigned char* vm;
+	int offs;
+	int offs2;
+	unsigned char store;
+	unsigned char bytes[16];
+	unsigned char* tmp;
+	unsigned long cbase;
+	unsigned long mbase;
+	unsigned int clen;
+	unsigned int mlen;
+
+	vm = ACCESS_FBINFO(video_vbase);
+	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
+	/* at least 2MB */
+	if (maxSize < 0x0200000) return 0;
+	if (maxSize > 0x1000000) maxSize = 0x1000000;
+	
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+
+	store = vm[0x1234];
+	tmp = bytes;
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		*tmp++ = vm[offs];			
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		vm[offs] = 0x02;
+	if (ACCESS_FBINFO(features.accel.has_cacheflush))
+		mga_outb(M_CACHEFLUSH, 0x00);
+	else
+		vm[0x1234] = 0x99;
+	cbase = mbase = 0;
+	clen = mlen = 0;
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+		if (vm[offs] != 0x02) 
+			continue;
+		vm[offs] -= 0x02;
+		if (vm[offs]) 
+			continue;
+		if (offs - 0x100000 == cbase + clen) {
+			clen += 0x200000;
+		} else {
+			cbase = offs - 0x100000;
+			clen = 0x200000;
+		}
+		if ((clen > mlen)
+#ifndef MATROX_2MB_WITH_4MB_ADDON
+		    && (cbase == 0)
+#endif
+		   ) {
+			mbase = cbase;
+			mlen = clen;
+		}
+	}
+	tmp = bytes;
+	for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+		vm[offs2] = *tmp++;
+	vm[0x1234] = store;
+
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+
+	*realOffset = mbase;
+	*realSize = mlen;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF));
+#endif
+	return 1;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960, 
+					  1024, 1152, 1280,      1600, 1664, 1920, 
+					  2048, 0};
+	static const int vxres_mill1[] = {             640, 768,  800,        960, 
+					  1024, 1152, 1280,      1600,       1920, 
+					  2048, 0};
+	ACCESS_FBINFO(millenium) = 1;
+	ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
+	ACCESS_FBINFO(capable.cfb4) = 1;
+	ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
+	/* preserve VGA I/O, BIOS and PPC */
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x002C0000;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	return 0;
+}
+
+__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+	ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
+
+	outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+	outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+	outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+	
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+	outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	mga_outb(M_MISC_REG, 0x67);
+
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+	ti3026_ramdac_init(PMINFO hw);
+
+	dprintk(KERN_INFO "matroxfb: PCI OPTION = %08X\n", hw->MXoptionReg);
+
+	mga_outl(M_RESET, 1);
+	udelay(250);
+	mga_outl(M_RESET, 0);
+	udelay(250);
+	/* wait for retrace, draw black square and so on... */
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct matrox_switch matrox_millenium = { 
+	Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore 
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct matrox_switch matrox_mystique = {
+	MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static struct matrox_switch matrox_G100 = {
+	MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore
+};
+#endif
+
+struct video_board {
+	int maxvram;
+	int accelID;
+	struct matrox_switch* lowlevel;
+		 };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillenium __initdata	= {0x0800000,	FB_ACCEL_MATROX_MGA2064W,	&matrox_millenium};
+static struct video_board vbMillenium2 __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W,	&matrox_millenium};
+static struct video_board vbMillenium2A __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W_AGP,	&matrox_millenium};
+#endif	/* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGA1064SG,	&matrox_mystique};
+#endif	/* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G100
+static struct video_board vbG100 __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGAG100,	&matrox_G100};
+static struct video_board vbG200 __initdata		= {0x1000000,	FB_ACCEL_MATROX_MGAG200,	&matrox_G100};
+#endif
+
+#define DEVF_VIDEO64BIT	0x01
+#define	DEVF_SWAPS	0x02
+#define DEVF_MILLENIUM	0x04
+#define	DEVF_MILLENIUM2	0x08
+static struct board {
+	unsigned short vendor, device, rev, svid, sid;
+	unsigned flags;
+	struct video_board* base;
+	const char* name;
+		} dev_list[] __initdata = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,	0xFF,
+		0,			0,
+		DEVF_MILLENIUM,
+		&vbMillenium,
+		"Millenium (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,	0xFF,
+		0,			0,
+		DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+		&vbMillenium2,
+		"Millenium II (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,	0xFF,
+		0,			0,
+		DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+		&vbMillenium2A,
+		"Millenium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0x02,
+		0,			0,
+		DEVF_VIDEO64BIT,
+		&vbMystique,
+		"Mystique (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbMystique,
+		"Mystique 220 (PCI)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G100
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_PCI,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"MGA-G100 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"unknown G100 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_UNSPECIFIED,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"MGA-G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"MGA-G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G100_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"MGA-G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"Productiva G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG100,
+		"unknown G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_UNSPECIFIED,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"Mystique G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"Millenium G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"Marvel G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS,
+		&vbG200,
+		"unknown G200 (AGP)"},
+#endif
+	{0,			0,				0xFF,
+		0,			0,
+		0,
+		NULL,
+		NULL}};
+	
+__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+	unsigned long ctrlptr_phys = 0;
+	unsigned long video_base_phys = 0;
+	int memsize;
+	struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
+
+	/* set default values... */
+	vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+	ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
+	ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
+
+	printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+	ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
+	if (b->flags & DEVF_SWAPS) {
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF;
+		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF;	/* aligned at 8MB (or 16 for Mill 2) */
+	} else {
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF;
+		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF;	/* aligned at 8MB */
+	}
+	if (!ctrlptr_phys) {
+		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+		return -EINVAL;
+	}
+	if (!video_base_phys) {
+		printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+		return -EINVAL;
+	}
+	ACCESS_FBINFO(mmio) = ioremap_nocache(ctrlptr_phys, 16384); /* do we really need ioremap_nocache? */
+	if (!ACCESS_FBINFO(mmio)) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+		return -ENOMEM;
+	}
+	ACCESS_FBINFO(mmio_base) = ctrlptr_phys;
+	ACCESS_FBINFO(mmio_len) = 16384;
+	memsize = b->base->maxvram;
+/* convert mem (autodetect k, M) */
+	if (mem < 1024) mem *= 1024;
+	if (mem < 0x00100000) mem *= 1024;
+
+	if (mem && (mem < memsize))
+		memsize = mem;
+	ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, memsize);
+	ACCESS_FBINFO(video_base) = video_base_phys;
+	if (!ACCESS_FBINFO(video_vbase)) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 
+			video_base_phys, memsize);
+		iounmap(ACCESS_FBINFO(mmio));
+		return -ENOMEM;
+	}
+	{
+		u_int32_t cmd;
+		u_int32_t mga_option;
+
+		/* Matrox MilleniumII is deactivated on bootup, but address
+		   regions are assigned to board. So we have to enable it */
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
+		mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+		if ((cmd & PCI_COMMAND_MEMORY) !=
+			   PCI_COMMAND_MEMORY) {
+			/* But if we have to enable it, we have probably to
+                           disable VGA I/O and BIOS... Sure? */
+			dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n");
+			cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE;
+			mga_option &=  0xBFFFFEFF; 
+			ACCESS_FBINFO(devflags.novga) = 1;
+			ACCESS_FBINFO(devflags.nobios) = 1;
+		}
+		mga_option |= MX_OPTION_BSWAP;
+		if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
+			if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
+				printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+			}
+			mga_option |= 0x20000000;
+			ACCESS_FBINFO(devflags.nopciretry) = 1;
+		}
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
+		hw->MXoptionReg = mga_option;
+
+		/* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+		/* maybe preinit() candidate, but it is same... for all devices... at this time... */
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
+	}
+
+	if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
+		iounmap(ACCESS_FBINFO(video_vbase));
+		iounmap(ACCESS_FBINFO(mmio));
+		return -ENXIO;
+	}
+
+	{
+		unsigned int offs;
+
+		if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video_len)) || !ACCESS_FBINFO(video_len)) {
+			printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+			iounmap(ACCESS_FBINFO(video_vbase));
+			iounmap(ACCESS_FBINFO(mmio));
+			return -ENOMEM;
+		}
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#ifdef FBCON_HAS_CFB24
+		{
+			unsigned int end = offs + ACCESS_FBINFO(video_len);
+
+			if (offs)
+				offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3;
+			ACCESS_FBINFO(video_len) = end - offs;
+		}
+#endif
+		mga_ydstorg(MINFO) = offs;
+		video_base_phys += offs;
+#endif
+	}
+	ACCESS_FBINFO(curr.video_type) = FB_TYPE_PACKED_PIXELS;
+	ACCESS_FBINFO(currcon) = -1;
+	iounmap(ACCESS_FBINFO(video_vbase));
+	ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, ACCESS_FBINFO(video_len));
+	ACCESS_FBINFO(video_base) = video_base_phys;
+	if (!ACCESS_FBINFO(video_vbase)) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 
+			video_base_phys, ACCESS_FBINFO(video_len));
+		iounmap(ACCESS_FBINFO(mmio));
+		return -ENOMEM;
+	}
+#ifdef CONFIG_MTRR
+	ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video_len), MTRR_TYPE_WRCOMB, 1);
+	ACCESS_FBINFO(mtrr.vram_valid) = 1;
+	printk(KERN_INFO "matroxfb: MTRR's turned on\n");
+#endif	/* CONFIG_MTRR */
+
+/* validate params, autodetect k, M */
+	if (fh < 1000) fh *= 1000;	/* 1kHz minimum */
+	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
+	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
+	vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+
+	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
+	ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
+	ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
+	ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
+	ACCESS_FBINFO(fbcon.monspecs.dpms) = 0;	/* TBD */
+
+/* static settings */
+	for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+		if (RSptr->vesa == vesa) break;
+	}
+	if (!RSptr->vesa) {
+		printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+		RSptr = vesamap;
+	}
+	{
+		int res = RSResolution(RSptr->info)-1;
+		if (!left)
+			left = timmings[res].left;
+		if (!xres)
+			xres = timmings[res].xres;
+		if (!right)
+			right = timmings[res].right;
+		if (!hslen)
+			hslen = timmings[res].hslen;
+		if (!upper)
+			upper = timmings[res].upper;
+		if (!yres)
+			yres = timmings[res].yres;
+		if (!lower)
+			lower = timmings[res].lower;
+		if (!vslen)
+			vslen = timmings[res].vslen;
+		if (!(fv||fh||maxclk||pixclock))
+			fv = timmings[res].vfreq;
+		if (!depth)
+			depth = RSDepth(RSptr->info);
+	}
+	if (sync == -1) {
+		sync = 0;
+		if (yres < 480)
+			sync |= FB_SYNC_VERT_HIGH_ACT;
+	}
+	if (xres < 320)
+		xres = 320;
+	if (xres > 2048)
+		xres = 2048;
+	if (yres < 200)
+		yres = 200;
+	if (yres > 2048)
+		yres = 2048;
+	{
+		int tmp;
+
+		if (fv) {
+			tmp = fv * (upper + yres + lower + vslen);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (left + xres + right + hslen);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		maxclk = (maxclk + 499) / 500;
+		if (maxclk) {
+			tmp = (2000000000 + maxclk) / maxclk;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	vesafb_defined.red = colors[depth-1].red;
+	vesafb_defined.green = colors[depth-1].green;
+	vesafb_defined.blue = colors[depth-1].blue;
+	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+	if (pixclock < 2000)		/* > 500MHz */
+		pixclock = 4000;	/* 250MHz */
+	if (pixclock > 1000000)
+		pixclock = 1000000;	/* 1MHz */
+	vesafb_defined.xres = xres;
+	vesafb_defined.yres = yres;
+	{
+		int pixel_size = vesafb_defined.bits_per_pixel;
+		int avamem = ACCESS_FBINFO(video_len);
+
+		/* displaying is possible only in first 8MB */
+		if (avamem > 0x8000000)
+			avamem = 0x8000000;
+
+		vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO xres, pixel_size);
+		if (nopan) {
+			vesafb_defined.yres_virtual = yres;
+		} else {
+			vesafb_defined.yres_virtual = (avamem * 8 / (pixel_size * vesafb_defined.xres_virtual)) & ~0x1F;
+			if (vesafb_defined.yres_virtual < vesafb_defined.yres)
+				vesafb_defined.yres_virtual = yres;
+		}
+	}
+	vesafb_defined.xoffset = 0;
+	vesafb_defined.yoffset = 0;
+	vesafb_defined.grayscale = 0;
+	vesafb_defined.pixclock = pixclock;
+	vesafb_defined.left_margin = left;
+	vesafb_defined.right_margin = right;
+	vesafb_defined.hsync_len = hslen;
+	vesafb_defined.upper_margin = upper;
+	vesafb_defined.lower_margin = lower;
+	vesafb_defined.vsync_len = vslen;
+	vesafb_defined.sync = sync;
+	vesafb_defined.vmode = 0;
+
+	if (!ACCESS_FBINFO(devflags.novga))
+		request_region(0x3C0, 32, "matrox");
+	if (noaccel)
+		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+	strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
+	ACCESS_FBINFO(fbcon.changevar) = NULL;
+	ACCESS_FBINFO(fbcon.node) = -1;
+	ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
+	ACCESS_FBINFO(fbcon.disp) = d;
+	ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
+	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
+	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+	ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
+	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
+	if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
+		printk(KERN_ERR "matroxfb: cannot set required parameters\n");
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+		vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+		vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+	printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+		ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_vbase), ACCESS_FBINFO(video_len));
+	
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+		return -EINVAL;
+	printk("fb%d: %s frame buffer device\n",
+	       GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
+	if (ACCESS_FBINFO(currcon) < 0) {
+		/* there is no console on this fb... but we have to initialize hardware 
+		 * until someone tells me what is proper thing to do */
+		printk(KERN_INFO "fb%d: initializing hardware\n",
+			GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
+		matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
+	}
+	return 0;
+}
+
+static struct matrox_fb_info* fb_list = NULL;
+
+__initfunc(static int matrox_init(void)) {
+	struct pci_dev* pdev = NULL;
+
+	if (disabled)
+		return -ENXIO; 
+	while ((pdev = pci_find(pdev)) != NULL) {
+		struct board* b;
+		u_int8_t rev;
+		u_int16_t svid;
+		u_int16_t sid;
+
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+		pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+		pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
+		for (b = dev_list; b->vendor; b++) {
+			if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+			if (b->svid)
+				if ((b->svid != svid) || (b->sid != sid)) continue;
+			if (dev <= 0) {
+				struct matrox_fb_info* minfo;
+				struct display* d;
+				int err;
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+				minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+				if (minfo) {
+					d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
+					if (d) {
+#else
+				minfo = &global_mxinfo;
+				d = &global_disp;
+#endif
+				memset(MINFO, 0, sizeof(*MINFO));
+				memset(d, 0, sizeof(*d));
+
+				ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
+				ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
+				ACCESS_FBINFO(pcidev) = pdev;
+				/* CMDLINE */
+				memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
+				/* DEVFLAGS */
+				ACCESS_FBINFO(devflags.inverse) = inverse;
+				ACCESS_FBINFO(devflags.novga) = novga;
+				ACCESS_FBINFO(devflags.nobios) = nobios;
+				ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
+				ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
+				ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
+				ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
+
+        			err = initMatrox2(PMINFO d, b);
+				if (!err) {
+					ACCESS_FBINFO(next_fb) = fb_list;
+					fb_list = MINFO;
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+					goto leave;
+#else
+					return 0;
+#endif
+				}
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+						kfree(d);
+					}
+					kfree(minfo);
+				}
+#endif
+			}
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+leave:;
+#endif
+			if (dev == 0) return 0;
+			if (dev > 0) dev--;
+			break;
+		}
+	}
+	return 0;
+}
+
+#ifndef MODULE
+__initfunc(void matroxfb_init(void))
+{
+	matrox_init();
+}
+
+#else
+
+MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millenium/Mystique");
+MODULE_PARM(mem, "i");
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+MODULE_PARM(nopan, "i");
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+MODULE_PARM(no_pci_retry, "i");
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(novga, "i");
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(nobios, "i");
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); 
+MODULE_PARM(inv24, "i");
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+#else
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
+#endif
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa, "Startup videomode (0x100-0x1FF) (default=0x101)");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+MODULE_PARM(upper, "i");
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+MODULE_PARM(lower, "i");
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(vslen, "i");
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(left, "i");
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+MODULE_PARM(right, "i");
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+MODULE_PARM(hslen, "i");
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+MODULE_PARM(pixclock, "i");
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+MODULE_PARM(depth, "i");
+MODULE_PARM_DESC(depth, "Color depth (8,15,16,24,32) (default=vesa)");
+MODULE_PARM(maxclk, "i");
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+MODULE_PARM(fh, "i");
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+MODULE_PARM(fv, "i");
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
+
+
+__initfunc(int init_module(void)) {
+	if (depth == 0)
+		depth = 0;	/* default */
+	else if (depth == 4)
+		depth = RS4bpp;
+	else if (depth == 8)
+		depth = RS8bpp;
+	else if (depth == 15)
+		depth = RS15bpp;
+	else if (depth == 16)
+		depth = RS16bpp;
+	else if (depth == 24)
+		depth = RS24bpp;
+	else if (depth == 32)
+		depth = RS32bpp;
+	else {
+		printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+		depth = 0;
+	}
+	matrox_init();
+	if (!fb_list) return -ENXIO;
+	return 0;
+}
+
+void cleanup_module(void) {
+	while (fb_list) {
+		struct matrox_fb_info* minfo;
+
+		minfo = fb_list;
+		fb_list = fb_list->next_fb;
+		unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+#ifdef CONFIG_MTRR
+		if (ACCESS_FBINFO(mtrr.vram_valid))
+			mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_len));
+#endif
+		iounmap(ACCESS_FBINFO(mmio));
+		iounmap(ACCESS_FBINFO(video_vbase));
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+		kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
+		kfree_s(minfo, sizeof(struct matrox_fb_info));
+#endif
+	}
+}
+#endif	/* MODULE */
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.128/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.1.128/linux/drivers/video/retz3fb.c	Mon Oct  5 13:13:42 1998
+++ linux/drivers/video/retz3fb.c	Fri Nov 13 10:10:12 1998
@@ -36,6 +36,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -98,38 +99,26 @@
 	long v_dispend;		/* Horizontal Display End */
 };
 
-static struct retz3fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp;
-static struct fb_info fb_info;
-
-
-/*
- *    Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
-   /* Initialisation */
+struct retz3_fb_info {
+	struct fb_info info;
+	unsigned long base;
+	unsigned long fbmem;
+	unsigned long fbsize;
+	volatile unsigned char *regs;
+	unsigned long physfbmem;
+	unsigned long physregs;
+	int currcon;
+	int current_par_valid; /* set to 0 by memset */
+	struct display disp;
+	struct retz3fb_par current_par;
+	unsigned char color_table [256][3];
+};
 
-   int (*init)(void);
 
-   /* Display Control */
+static char fontname[40] __initdata = { 0 };
 
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
-   int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
-		    int *green, unsigned int *blue, unsigned int *transp,
-			struct fb_info *info);
-   int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
-		    green, unsigned int blue, unsigned int transp,
-			struct fb_info *info);
-   void (*blank)(int blank);
-} *fbhw;
+#define retz3info(info) ((struct retz3_fb_info *)(info))
+#define fbinfo(info) ((struct fb_info *)(info))
 
 
 /*
@@ -139,13 +128,6 @@
 static char retz3fb_name[16] = "RetinaZ3";
 
 
-static unsigned char retz3_color_table [256][3];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-
 /*
  * A small info on how to convert XFree86 timing values into fb
  * timings - by Frank Neumann:
@@ -197,7 +179,7 @@
 	    640, 480, 640, 480, 0, 0, 8, 0,
 	    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 	    0, 0, -1, -1, FB_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
-	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
 	}
     },
     /*
@@ -228,14 +210,14 @@
 	    640, 480, 640, 480, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
 	    0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
-	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
 	}
     }, {
 	"640x480-24", {		/* 640x480, 24 bpp */
 	    640, 480, 640, 480, 0, 0, 24, 0,
 	    {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
 	    0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
-	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
 	}
     },
 };
@@ -297,7 +279,7 @@
  *    Accelerated Functions used by the low level console driver
  */
 
-static void retz3_bitblt(struct fb_var_screeninfo *scr,
+static void retz3_bitblt(struct display *p,
 			 unsigned short curx, unsigned short cury, unsigned
 			 short destx, unsigned short desty, unsigned short
 			 width, unsigned short height, unsigned short cmd,
@@ -307,29 +289,28 @@
  *   Hardware Specific Routines
  */
 
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3fb_par *par);
+static int retz3_encode_fix(struct fb_info *info,
+			    struct fb_fix_screeninfo *fix,
+			    struct retz3fb_par *par);
 static int retz3_decode_var(struct fb_var_screeninfo *var,
-                          struct retz3fb_par *par);
+			    struct retz3fb_par *par);
 static int retz3_encode_var(struct fb_var_screeninfo *var,
-                          struct retz3fb_par *par);
+			    struct retz3fb_par *par);
 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
 			   unsigned int *green, unsigned int *blue,
 			   unsigned int *transp, struct fb_info *info);
 static int retz3_setcolreg(unsigned int regno, unsigned int red,
 			   unsigned int green, unsigned int blue,
 			   unsigned int transp, struct fb_info *info);
-static void retz3_blank(int blank);
-
 
 /*
  *    Internal routines
  */
 
-static void retz3fb_get_par(struct retz3fb_par *par);
-static void retz3fb_set_par(struct retz3fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
+static int do_fb_set_var(struct fb_info *info,
+			 struct fb_var_screeninfo *var, int isactive);
 static void do_install_cmap(int con, struct fb_info *info);
 static void retz3fb_set_disp(int con, struct fb_info *info);
 static int get_video_mode(const char *name);
@@ -381,12 +362,11 @@
 }
 
 
-static int retz3_set_video(struct fb_var_screeninfo *var,
+static int retz3_set_video(struct fb_info *info,
+			   struct fb_var_screeninfo *var,
 			   struct retz3fb_par *par)
 {
-#if 0
-	float freq_f;
-#endif
+	volatile unsigned char *regs = retz3info(info)->regs;
 	unsigned int freq;
 
 	int xres, hfront, hsync, hback;
@@ -482,11 +462,11 @@
 	if (data.v_total >= 1024)
 		printk("MAYDAY: v_total >= 1024; bailing out!\n");
 
-	reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
-	reg_w(GREG_FEATURE_CONTROL_W, 0x00);
+	reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
+	reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
 
-	seq_w(SEQ_RESET, 0x00);
-	seq_w(SEQ_RESET, 0x03);	/* reset sequencer logic */
+	seq_w(regs, SEQ_RESET, 0x00);
+	seq_w(regs, SEQ_RESET, 0x03);	/* reset sequencer logic */
 
 	/*
 	 * CLOCKING_MODE bits:
@@ -495,32 +475,32 @@
 	 * (The CL drivers sets it to 0x21 with the comment:
 	 *  FullBandwidth (video off) and 8/9 dot clock)
 	 */
-	seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
+	seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
 
-	seq_w(SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
-	seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
-	seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
-	seq_w(SEQ_RESET, 0x01);
-	seq_w(SEQ_RESET, 0x03);
-
-	seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
-	seq_w(SEQ_CURSOR_CONTROL, 0x00);	/* disable cursor */
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_LINEAR_0, 0x4a);
-	seq_w(SEQ_LINEAR_1, 0x00);
-
-	seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
-	seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
+	seq_w(regs, SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
+	seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
+	seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
+	seq_w(regs, SEQ_RESET, 0x01);
+	seq_w(regs, SEQ_RESET, 0x03);
+
+	seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
+
+	seq_w(regs, SEQ_CURSOR_CONTROL, 0x00);	/* disable cursor */
+	seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_LINEAR_0, 0x4a);
+	seq_w(regs, SEQ_LINEAR_1, 0x00);
+
+	seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
+	seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
 
 	/*
 	 * The lower 4 bits (0-3) are used to set the font-width for
 	 * text-mode - DON'T try to set this for gfx-mode.
 	 */
-	seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
-	seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
+	seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
+	seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
 
 	/*
 	 * Extended Pixel Control:
@@ -528,52 +508,52 @@
 	 * bit 1: (Packed/Nibble Pixel Format ?)
 	 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
 	 */
-	seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
+	seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
 
-	seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
-	seq_w(SEQ_COLOR_EXP_WFG, 0x01);
-	seq_w(SEQ_COLOR_EXP_WBG, 0x00);
-	seq_w(SEQ_EXT_RW_CONTROL, 0x00);
-	seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
-	seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
-	seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
-	seq_w(SEQ_CRC_CONTROL, 0x00);
-	seq_w(SEQ_PERF_SELECT, 0x10);
-	seq_w(SEQ_ACM_APERTURE_1, 0x00);
-	seq_w(SEQ_ACM_APERTURE_2, 0x30);
-	seq_w(SEQ_ACM_APERTURE_3, 0x00);
-	seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
+	seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
+	seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
+	seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
+	seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
+	seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
+	seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
+	seq_w(regs, SEQ_CRC_CONTROL, 0x00);
+	seq_w(regs, SEQ_PERF_SELECT, 0x10);
+	seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
+	seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
+	seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
+	seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
 
 
 	/* unlock register CRT0..CRT7 */
-	crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
+	crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
 
 	/* Zuerst zu schreibende Werte nur per printk ausgeben */
 	DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
-	crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
+	crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
 
 	DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
-	crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
+	crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
 
 	DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
-	crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
+	crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
 
 	DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
-	crt_w(CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
+	crt_w(regs, CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
 
 	DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
-	crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
+	crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
 
 	tmp = (data.h_sstop & 0x1f);
 	if (data.h_bstop & 0x20)
 		tmp |= 0x80;
 	DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
-	crt_w(CRT_END_HOR_RETR, tmp);
+	crt_w(regs, CRT_END_HOR_RETR, tmp);
 
 	DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
-	crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
+	crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
 
 	tmp = 0x10;  /* LineCompare bit #9 */
 	if (data.v_total & 256)
@@ -591,9 +571,9 @@
 	if (data.v_sstart & 512)
 		tmp |= 0x80;
 	DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
-	crt_w(CRT_OVERFLOW, tmp);
+	crt_w(regs, CRT_OVERFLOW, tmp);
 
-	crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
+	crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
 
 	tmp = 0x40; /* LineCompare bit #8 */
 	if (data.v_bstart & 512)
@@ -601,47 +581,47 @@
 	if (var->vmode & FB_VMODE_DOUBLE)
 		tmp |= 0x80;
  	DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
-	crt_w(CRT_MAX_SCAN_LINE, tmp);
+	crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
 
-	crt_w(CRT_CURSOR_START, 0x00);
-	crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
+	crt_w(regs, CRT_CURSOR_START, 0x00);
+	crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
 
-	crt_w(CRT_START_ADDR_HIGH, 0x00);
-	crt_w(CRT_START_ADDR_LOW, 0x00);
+	crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
+	crt_w(regs, CRT_START_ADDR_LOW, 0x00);
 
-	crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
-	crt_w(CRT_CURSOR_LOC_LOW, 0x00);
+	crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
+	crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
 
  	DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
-	crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
+	crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
 
 #if 1
 	/* 5 refresh cycles per scanline */
 	DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
+	crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
 #else
 	DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
+	crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
 #endif
 	DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
-	crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
+	crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
 
 	DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
-	crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
+	crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
 
 	DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
-	crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
+	crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
 
 	DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
-	crt_w(CRT_MODE_CONTROL, 0xe3);
+	crt_w(regs, CRT_MODE_CONTROL, 0xe3);
 
 	DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
-	crt_w(CRT_LINE_COMPARE, 0xff);
+	crt_w(regs, CRT_LINE_COMPARE, 0xff);
 
 	tmp = (var->xres_virtual / 8) * (bpp / 8);
-	crt_w(CRT_OFFSET, tmp);
+	crt_w(regs, CRT_OFFSET, tmp);
 
-	crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
+	crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
 
 	tmp = 0x20;			/* Enable extended end bits */
 	if (data.h_total & 0x100)
@@ -655,12 +635,12 @@
 	if (var->vmode & FB_VMODE_INTERLACED)
 		tmp |= 0x10;
  	DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
-	crt_w(CRT_EXT_HOR_TIMING1, tmp);
+	crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
 
 	tmp = 0x00;
 	if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
 		tmp |= 0x10;
-	crt_w(CRT_EXT_START_ADDR, tmp);
+	crt_w(regs, CRT_EXT_START_ADDR, tmp);
 
 	tmp = 0x00;
 	if (data.h_total & 0x200)
@@ -673,7 +653,7 @@
 		tmp |= 0x08;
 	tmp |= ((data.h_bstop & 0xc0) >> 2);
 	tmp |= ((data.h_sstop & 0x60) << 1);
-	crt_w(CRT_EXT_HOR_TIMING2, tmp);
+	crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
  	DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
 
 	tmp = 0x10;			/* Line compare bit 10 */
@@ -688,138 +668,84 @@
 	tmp |= ((data.v_bstop & 0x300) >> 3);
 	if (data.v_sstop & 0x10)
 		tmp |= 0x80;
-	crt_w(CRT_EXT_VER_TIMING, tmp);
+	crt_w(regs, CRT_EXT_VER_TIMING, tmp);
  	DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
 
-	crt_w(CRT_MONITOR_POWER, 0x00);
+	crt_w(regs, CRT_MONITOR_POWER, 0x00);
 
 	/*
 	 * Convert from ps to Hz.
 	 */
-#if 0
-	freq_f = (1.0/(float)var->pixclock) * 1000000000;
-	freq = ((unsigned int)freq_f) * 1000;
-#else
 	freq = 2000000000 / var->pixclock;
 	freq = freq * 500;
-#endif
 
 	best_freq = find_fq(freq);
-	pll_w(0x02, best_freq);
+	pll_w(regs, 0x02, best_freq);
 	best_freq = find_fq(61000000);
-	pll_w(0x0a, best_freq);
-	pll_w(0x0e, 0x22);
+	pll_w(regs, 0x0a, best_freq);
+	pll_w(regs, 0x0e, 0x22);
 
-	gfx_w(GFX_SET_RESET, 0x00);
-	gfx_w(GFX_ENABLE_SET_RESET, 0x00);
-	gfx_w(GFX_COLOR_COMPARE, 0x00);
-	gfx_w(GFX_DATA_ROTATE, 0x00);
-	gfx_w(GFX_READ_MAP_SELECT, 0x00);
-	gfx_w(GFX_GRAPHICS_MODE, 0x00);
-	gfx_w(GFX_MISC, 0x05);
-	gfx_w(GFX_COLOR_XCARE, 0x0f);
-	gfx_w(GFX_BITMASK, 0xff);
-
-	reg_r(ACT_ADDRESS_RESET);
-	attr_w(ACT_PALETTE0 , 0x00);
-	attr_w(ACT_PALETTE1 , 0x01);
-	attr_w(ACT_PALETTE2 , 0x02);
-	attr_w(ACT_PALETTE3 , 0x03);
-	attr_w(ACT_PALETTE4 , 0x04);
-	attr_w(ACT_PALETTE5 , 0x05);
-	attr_w(ACT_PALETTE6 , 0x06);
-	attr_w(ACT_PALETTE7 , 0x07);
-	attr_w(ACT_PALETTE8 , 0x08);
-	attr_w(ACT_PALETTE9 , 0x09);
-	attr_w(ACT_PALETTE10, 0x0a);
-	attr_w(ACT_PALETTE11, 0x0b);
-	attr_w(ACT_PALETTE12, 0x0c);
-	attr_w(ACT_PALETTE13, 0x0d);
-	attr_w(ACT_PALETTE14, 0x0e);
-	attr_w(ACT_PALETTE15, 0x0f);
-	reg_r(ACT_ADDRESS_RESET);
-
-	attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
-	attr_w(ACT_OVERSCAN_COLOR, 0x00);
-	attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
-	attr_w(ACT_HOR_PEL_PANNING, 0x00);
-	attr_w(ACT_COLOR_SELECT, 0x00);
+	gfx_w(regs, GFX_SET_RESET, 0x00);
+	gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
+	gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
+	gfx_w(regs, GFX_DATA_ROTATE, 0x00);
+	gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
+	gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
+	gfx_w(regs, GFX_MISC, 0x05);
+	gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
+	gfx_w(regs, GFX_BITMASK, 0xff);
+
+	reg_r(regs, ACT_ADDRESS_RESET);
+	attr_w(regs, ACT_PALETTE0 , 0x00);
+	attr_w(regs, ACT_PALETTE1 , 0x01);
+	attr_w(regs, ACT_PALETTE2 , 0x02);
+	attr_w(regs, ACT_PALETTE3 , 0x03);
+	attr_w(regs, ACT_PALETTE4 , 0x04);
+	attr_w(regs, ACT_PALETTE5 , 0x05);
+	attr_w(regs, ACT_PALETTE6 , 0x06);
+	attr_w(regs, ACT_PALETTE7 , 0x07);
+	attr_w(regs, ACT_PALETTE8 , 0x08);
+	attr_w(regs, ACT_PALETTE9 , 0x09);
+	attr_w(regs, ACT_PALETTE10, 0x0a);
+	attr_w(regs, ACT_PALETTE11, 0x0b);
+	attr_w(regs, ACT_PALETTE12, 0x0c);
+	attr_w(regs, ACT_PALETTE13, 0x0d);
+	attr_w(regs, ACT_PALETTE14, 0x0e);
+	attr_w(regs, ACT_PALETTE15, 0x0f);
+	reg_r(regs, ACT_ADDRESS_RESET);
+
+	attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
+
+	attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
+	attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
+	attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
+	attr_w(regs, ACT_COLOR_SELECT, 0x00);
 
-	reg_r(ACT_ADDRESS_RESET);
-	reg_w(ACT_DATA, 0x20);
+	reg_r(regs, ACT_ADDRESS_RESET);
+	reg_w(regs, ACT_DATA, 0x20);
 
-	reg_w(VDAC_MASK, 0xff);
+	reg_w(regs, VDAC_MASK, 0xff);
 
 	/*
 	 * Extended palette adressing ???
 	 */
 	switch (bpp){
 	case 8:
-		reg_w(0x83c6, 0x00);
+		reg_w(regs, 0x83c6, 0x00);
 		break;
 	case 16:
-		reg_w(0x83c6, 0x60);
+		reg_w(regs, 0x83c6, 0x60);
 		break;
 	case 24:
-		reg_w(0x83c6, 0xe0);
+		reg_w(regs, 0x83c6, 0xe0);
 		break;
 	default:
 		printk("Illegal color-depth: %i\n", bpp);
 	}
 
-	reg_w(VDAC_ADDRESS, 0x00);
-
-	seq_w(SEQ_MAP_MASK, 0x0f );
-
-	return 0;
-}
-
-/*
- *    Initialization
- *
- *    Set the default video mode for this chipset. If a video mode was
- *    specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
-	short i;
-#if 0
-	volatile unsigned long *CursorBase;
-#endif
-
-	for (i = 0; i < 256; i++){
-		for (i = 0; i < 256; i++){
-			retz3_color_table [i][0] = i;
-			retz3_color_table [i][1] = i;
-			retz3_color_table [i][2] = i;
-		}
-	}
-
-	/* Disable hardware cursor */
+	reg_w(regs, VDAC_ADDRESS, 0x00);
 
-	seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-#if 0
-	/* Initialize hardware cursor */
-	CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
-	for (i=0; i < 8; i++){
-		*(CursorBase  +(i*4)) = 0xffffff00;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-	for (i=8; i < 64; i++){
-		*(CursorBase  +(i*4)) = 0xffff0000;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-#endif
-
-	retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
-	retz3_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
+	seq_w(regs, SEQ_MAP_MASK, 0x0f );
 
 	return 0;
 }
@@ -830,14 +756,17 @@
  *    values in the `par' structure.
  */
 
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
+static int retz3_encode_fix(struct fb_info *info,
+			    struct fb_fix_screeninfo *fix,
 			    struct retz3fb_par *par)
 {
+	struct retz3_fb_info *zinfo = retz3info(info);
+
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, retz3fb_name);
-	fix->smem_start = (char *)z3_fbmem;
-	fix->smem_len = z3_size;
-	fix->mmio_start = (char *)z3_regs;
+	fix->smem_start = (char *)(zinfo->physfbmem);
+	fix->smem_len = zinfo->fbsize;
+	fix->mmio_start = (char *)(zinfo->physregs);
 	fix->mmio_len = 0x00c00000;
 
 	fix->type = FB_TYPE_PACKED_PIXELS;
@@ -950,6 +879,9 @@
 			   unsigned int green, unsigned int blue,
 			   unsigned int transp, struct fb_info *info)
 {
+	struct retz3_fb_info *zinfo = retz3info(info);
+	volatile unsigned char *regs = zinfo->regs;
+
 	/* We'll get to this */
 
 	if (regno > 255)
@@ -959,14 +891,14 @@
 	green >>= 10;
 	blue >>= 10;
 
-	retz3_color_table [regno][0] = red;
-	retz3_color_table [regno][1] = green;
-	retz3_color_table [regno][2] = blue;
-
-	reg_w(VDAC_ADDRESS_W, regno);
-	reg_w(VDAC_DATA, red);
-	reg_w(VDAC_DATA, green);
-	reg_w(VDAC_DATA, blue);
+	zinfo->color_table[regno][0] = red;
+	zinfo->color_table[regno][1] = green;
+	zinfo->color_table[regno][2] = blue;
+
+	reg_w(regs, VDAC_ADDRESS_W, regno);
+	reg_w(regs, VDAC_DATA, red);
+	reg_w(regs, VDAC_DATA, green);
+	reg_w(regs, VDAC_DATA, blue);
 
 	return 0;
 }
@@ -981,55 +913,32 @@
 			   unsigned int *green, unsigned int *blue,
 			   unsigned int *transp, struct fb_info *info)
 {
+	struct retz3_fb_info *zinfo = retz3info(info);
 	int t;
 
 	if (regno > 255)
 		return 1;
-	t       = retz3_color_table [regno][0];
+	t       = zinfo->color_table[regno][0];
 	*red    = (t<<10) | (t<<4) | (t>>2);
-	t       = retz3_color_table [regno][1];
+	t       = zinfo->color_table[regno][1];
 	*green  = (t<<10) | (t<<4) | (t>>2);
-	t       = retz3_color_table [regno][2];
+	t       = zinfo->color_table[regno][2];
 	*blue   = (t<<10) | (t<<4) | (t>>2);
 	*transp = 0;
 	return 0;
 }
 
 
-/*
- *    (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
-	short i;
-
-	if (blank)
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-		}
-	else
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, retz3_color_table [i][0]);
-			reg_w(VDAC_DATA, retz3_color_table [i][1]);
-			reg_w(VDAC_DATA, retz3_color_table [i][2]);
-		}
-}
-
-
-static void retz3_bitblt (struct fb_var_screeninfo *var,
+static void retz3_bitblt (struct display *p,
 			  unsigned short srcx, unsigned short srcy,
 			  unsigned short destx, unsigned short desty,
 			  unsigned short width, unsigned short height,
 			  unsigned short cmd, unsigned short mask)
 {
-
-	volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
-	unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
+	struct fb_var_screeninfo *var = &p->var;
+	struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+	volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
+	unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
 
 	unsigned short mod;
 	unsigned long tmp;
@@ -1132,55 +1041,50 @@
 }
 #endif
 
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
-	retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
-	retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
 
 /*
  *    Fill the hardware's `par' structure.
  */
 
-static void retz3fb_get_par(struct retz3fb_par *par)
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
 {
-	if (current_par_valid)
-		*par = current_par;
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (zinfo->current_par_valid)
+		*par = zinfo->current_par;
 	else
-		fbhw->decode_var(&retz3fb_default, par);
+		retz3_decode_var(&retz3fb_default, par);
 }
 
 
-static void retz3fb_set_par(struct retz3fb_par *par)
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
 {
-	current_par = *par;
-	current_par_valid = 1;
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	zinfo->current_par = *par;
+	zinfo->current_par_valid = 1;
 }
 
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int do_fb_set_var(struct fb_info *info,
+			 struct fb_var_screeninfo *var, int isactive)
 {
 	int err, activate;
 	struct retz3fb_par par;
+	struct retz3_fb_info *zinfo = retz3info(info);
 
-	if ((err = fbhw->decode_var(var, &par)))
+	if ((err = retz3_decode_var(var, &par)))
 		return err;
 	activate = var->activate;
 
 	/* XXX ... what to do about isactive ? */
 
 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-		retz3fb_set_par(&par);
-	fbhw->encode_var(var, &par);
+		retz3fb_set_par(info, &par);
+	retz3_encode_var(var, &par);
 	var->activate = activate;
 
-	retz3_set_video(var, &current_par);
+	retz3_set_video(info, var, &zinfo->current_par);
 
 	return 0;
 }
@@ -1188,13 +1092,15 @@
 
 static void do_install_cmap(int con, struct fb_info *info)
 {
-	if (con != currcon)
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (con != zinfo->currcon)
 		return;
 	if (fb_display[con].cmap.len)
-		fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
+		fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info);
 	else
 		fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-					    1, fbhw->setcolreg, info);
+					    1, retz3_setcolreg, info);
 }
 
 
@@ -1230,10 +1136,10 @@
 	int error = 0;
 
 	if (con == -1)
-		retz3fb_get_par(&par);
+		retz3fb_get_par(info, &par);
 	else
-		error = fbhw->decode_var(&fb_display[con].var, &par);
-	return(error ? error : fbhw->encode_fix(fix, &par));
+		error = retz3_decode_var(&fb_display[con].var, &par);
+	return(error ? error : retz3_encode_fix(info, fix, &par));
 }
 
 
@@ -1248,8 +1154,8 @@
 	int error = 0;
 
 	if (con == -1) {
-		retz3fb_get_par(&par);
-		error = fbhw->encode_var(var, &par);
+		retz3fb_get_par(info, &par);
+		error = retz3_encode_var(var, &par);
 	} else
 		*var = fb_display[con].var;
 	return error;
@@ -1261,18 +1167,19 @@
 {
 	struct fb_fix_screeninfo fix;
 	struct display *display;
+	struct retz3_fb_info *zinfo = retz3info(info);
 
 	if (con >= 0)
 		display = &fb_display[con];
 	else
-		display = &disp;	/* used during initialization */
+		display = &zinfo->disp;	/* used during initialization */
 
 	retz3fb_get_fix(&fix, con, info);
 
 	if (con == -1)
 		con = 0;
 
-	display->screen_base = fix.smem_start;
+	display->screen_base = (char *)zinfo->fbmem;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -1308,6 +1215,7 @@
 }
 #endif
 
+
 /*
  *    Set the User Defined Part of the Display
  */
@@ -1317,18 +1225,14 @@
 {
 	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
 	struct display *display;
+	struct retz3_fb_info *zinfo = retz3info(info);
 
 	if (con >= 0)
 		display = &fb_display[con];
 	else
-		display = &disp;	/* used during initialization */
-
-#if 0
-	if (con == -1)
-		con = 0;
-#endif
+		display = &zinfo->disp;	/* used during initialization */
 
-	if ((err = do_fb_set_var(var, con == currcon)))
+	if ((err = do_fb_set_var(info, var, con == zinfo->currcon)))
 		return err;
 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 		oldxres = display->var.xres;
@@ -1348,7 +1252,7 @@
 			struct fb_fix_screeninfo fix;
 			retz3fb_get_fix(&fix, con, info);
 
-			display->screen_base = fix.smem_start;
+			display->screen_base = (char *)zinfo->fbmem;
 			display->visual = fix.visual;
 			display->type = fix.type;
 			display->type_aux = fix.type_aux;
@@ -1379,8 +1283,8 @@
 /*
 	retz3fb_set_disp(con, info);
 */
-			if (fb_info.changevar)
-				(*fb_info.changevar)(con);
+			if (info->changevar)
+				(*info->changevar)(con);
 		}
 
 		if (oldbpp != var->bits_per_pixel) {
@@ -1400,8 +1304,10 @@
 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			    struct fb_info *info)
 {
-	if (con == currcon) /* current console? */
-		return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (con == zinfo->currcon) /* current console? */
+		return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
 	else if (fb_display[con].cmap.len) /* non default colormap? */
 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
 	else
@@ -1419,6 +1325,7 @@
 			    struct fb_info *info)
 {
 	int err;
+	struct retz3_fb_info *zinfo = retz3info(info);
 
 	if (!fb_display[con].cmap.len) {       /* no colormap allocated? */
 		if ((err = fb_alloc_cmap(&fb_display[con].cmap,
@@ -1426,8 +1333,8 @@
 					 0)))
 			return err;
 	}
-	if (con == currcon)              /* current console? */
-		return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info));
+	if (con == zinfo->currcon)              /* current console? */
+		return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info));
 	else
 		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
 	return 0;
@@ -1470,8 +1377,6 @@
 {
 	char *this_opt;
 
-	fb_info.fontname[0] = '\0';
-
 	if (!options || !*options)
 		return;
 
@@ -1480,9 +1385,10 @@
 		if (!strcmp(this_opt, "inverse")) {
 			z3fb_inverse = 1;
 			fb_invert_cmaps();
-		} else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
-		else
+		} else if (!strncmp(this_opt, "font:", 5)) {
+			strncpy(fontname, this_opt+5, 39);
+			fontname[39] = '\0';
+		}else
 			z3fb_mode = get_video_mode(this_opt);
 	}
 }
@@ -1497,59 +1403,79 @@
 	unsigned long board_addr, board_size;
 	unsigned int key;
 	const struct ConfigDev *cd;
-
+	volatile unsigned char *regs;
 	struct retz3fb_par par;
+	struct retz3_fb_info *zinfo;
+	struct fb_info *fb_info;
+	short i;
 
 	if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
 		return;
 
+	if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL)))
+		return;
+	memset(zinfo, 0, sizeof(struct retz3_fb_info));
+
 	cd = zorro_get_board (key);
 	zorro_config_board (key, 0);
 	board_addr = (unsigned long)cd->cd_BoardAddr;
 	board_size = (unsigned long)cd->cd_BoardSize;
 
-	z3_mem = kernel_map (board_addr, board_size,
-			     KERNELMAP_NOCACHE_SER, NULL);
-
-	z3_regs = (char*) z3_mem;
-	z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
+	zinfo->base = kernel_map (board_addr, board_size,
+				   KERNELMAP_NOCACHE_SER, NULL);
+	zinfo->regs = (unsigned char *)(zinfo->base);
+	zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
 	/* Get memory size - for now we asume its a 4MB board */
+	zinfo->fbsize = 0x00400000; /* 4 MB */
+	zinfo->physregs = board_addr;
+	zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
 
-	z3_size = 0x00400000; /* 4 MB */
+	fb_info = fbinfo(zinfo);
 
-	fbhw = &retz3_switch;
+	for (i = 0; i < 256; i++){
+		for (i = 0; i < 256; i++){
+			zinfo->color_table[i][0] = i;
+			zinfo->color_table[i][1] = i;
+			zinfo->color_table[i][2] = i;
+		}
+	}
+
+	regs = zinfo->regs;
+	/* Disable hardware cursor */
+	seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
 
-	fbhw->init();
+	retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
+	retz3_setcolreg (254, 0, 0, 0, 0, fb_info);
 
-	strcpy(fb_info.modename, retz3fb_name);
-	fb_info.changevar = NULL;
-	fb_info.node = -1;
-	fb_info.fbops = &retz3fb_ops;
-	fb_info.disp = &disp;
-	fb_info.switch_con = &z3fb_switch;
-	fb_info.updatevar = &z3fb_updatevar;
-	fb_info.blank = &z3fb_blank;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	strcpy(fb_info->modename, retz3fb_name);
+	fb_info->changevar = NULL;
+	fb_info->node = -1;
+	fb_info->fbops = &retz3fb_ops;
+	fb_info->disp = &zinfo->disp;
+	fb_info->switch_con = &z3fb_switch;
+	fb_info->updatevar = &z3fb_updatevar;
+	fb_info->blank = &z3fb_blank;
+	fb_info->flags = FBINFO_FLAG_DEFAULT;
+	strncpy(fb_info->fontname, fontname, 40);
 
 	if (z3fb_mode == -1)
 		retz3fb_default = retz3fb_predefined[0].var;
 
-	fbhw->decode_var(&retz3fb_default, &par);
-	fbhw->encode_var(&retz3fb_default, &par);
+	retz3_decode_var(&retz3fb_default, &par);
+	retz3_encode_var(&retz3fb_default, &par);
 
-	do_fb_set_var(&retz3fb_default, 0);
-	retz3fb_get_var(&disp.var, -1, &fb_info);
+	do_fb_set_var(fb_info, &retz3fb_default, 0);
+	retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
 
-	retz3fb_set_disp(-1, &fb_info);
+	retz3fb_set_disp(-1, fb_info);
 
-	do_install_cmap(0, &fb_info);
+	do_install_cmap(0, fb_info);
 
-	if (register_framebuffer(&fb_info) < 0)
+	if (register_framebuffer(fb_info) < 0)
 		return;
 
 	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
-	       GET_FB_IDX(fb_info.node), fb_info.modename, z3_size>>10);
+	       GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10);
 
 	/* TODO: This driver cannot be unloaded yet */
 	MOD_INC_USE_COUNT;
@@ -1558,13 +1484,15 @@
 
 static int z3fb_switch(int con, struct fb_info *info)
 {
+	struct retz3_fb_info *zinfo = retz3info(info);
+
 	/* Do we have to save the colormap? */
-	if (fb_display[currcon].cmap.len)
-		fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
-			    info);
+	if (fb_display[zinfo->currcon].cmap.len)
+		fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1,
+			    retz3_getcolreg, info);
 
-	do_fb_set_var(&fb_display[con].var, 1);
-	currcon = con;
+	do_fb_set_var(info, &fb_display[con].var, 1);
+	zinfo->currcon = con;
 	/* Install new colormap */
 	do_install_cmap(con, info);
 	return 0;
@@ -1590,7 +1518,24 @@
 
 static void z3fb_blank(int blank, struct fb_info *info)
 {
-	fbhw->blank(blank);
+	struct retz3_fb_info *zinfo = retz3info(info);
+	volatile unsigned char *regs = retz3info(info)->regs;
+	short i;
+
+	if (blank)
+		for (i = 0; i < 256; i++){
+			reg_w(regs, VDAC_ADDRESS_W, i);
+			reg_w(regs, VDAC_DATA, 0);
+			reg_w(regs, VDAC_DATA, 0);
+			reg_w(regs, VDAC_DATA, 0);
+		}
+	else
+		for (i = 0; i < 256; i++){
+			reg_w(regs, VDAC_ADDRESS_W, i);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
+		}
 }
 
 
@@ -1635,8 +1580,8 @@
  */
 
 #ifdef FBCON_HAS_CFB8
-static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int dx,
-	                int height, int width)
+static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
+				int dy, int dx, int height, int width)
 {
 	int fontwidth = fontwidth(p);
 
@@ -1644,7 +1589,7 @@
 	dx *= fontwidth;
 	width *= fontwidth;
 
-	retz3_bitblt(&p->var,
+	retz3_bitblt(p,
 		     (unsigned short)sx,
 		     (unsigned short)(sy*fontheight(p)),
 		     (unsigned short)dx,
@@ -1655,8 +1600,8 @@
 		     0xffff);
 }
 
-static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int
-			sy, int sx, int height, int width)
+static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
+				int sy, int sx, int height, int width)
 {
 	unsigned short col;
 	int fontwidth = fontwidth(p);
@@ -1668,7 +1613,7 @@
 	col &= 0xff;
 	col |= (col << 8);
 
-	retz3_bitblt(&p->var,
+	retz3_bitblt(p,
 		     (unsigned short)sx,
 		     (unsigned short)(sy*fontheight(p)),
 		     (unsigned short)sx,
diff -u --recursive --new-file v2.1.128/linux/drivers/video/retz3fb.h linux/drivers/video/retz3fb.h
--- v2.1.128/linux/drivers/video/retz3fb.h	Tue Sep 16 02:30:26 1997
+++ linux/drivers/video/retz3fb.h	Fri Nov 13 10:10:12 1998
@@ -16,40 +16,40 @@
 /*
  * Macros to read and write to registers.
  */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
+#define reg_w(regs, reg,dat) (*(regs + reg) = dat)
+#define reg_r(regs, reg) (*(regs + reg))
 
 /*
  * Macro to access the sequencer.
  */
-#define seq_w(sreg,sdat) \
-	do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
+#define seq_w(regs, sreg, sdat) \
+	do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0)
 
 /*
  * Macro to access the CRT controller.
  */
-#define crt_w(creg,cdat) \
-	do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
+#define crt_w(regs, creg, cdat) \
+	do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0)
 
 /*
  * Macro to access the graphics controller.
  */
-#define gfx_w(greg,gdat) \
-	do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
+#define gfx_w(regs, greg, gdat) \
+	do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0)
 
 /*
  * Macro to access the attribute controller.
  */
-#define attr_w(areg,adat) \
-	do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
+#define attr_w(regs, areg, adat) \
+	do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0)
 
 /*
  * Macro to access the pll.
  */
-#define pll_w(preg,pdat) \
-	do{ reg_w(PLL_IDX, preg); \
-	    reg_w(PLL_DATA, (pdat & 0xff)); \
-	    reg_w(PLL_DATA, (pdat >> 8));\
+#define pll_w(regs, preg, pdat) \
+	do{ reg_w(regs, PLL_IDX, preg); \
+	    reg_w(regs, PLL_DATA, (pdat & 0xff)); \
+	    reg_w(regs, PLL_DATA, (pdat >> 8));\
 	} while(0)
 
 /*
diff -u --recursive --new-file v2.1.128/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.1.128/linux/drivers/video/sbusfb.c	Mon Oct  5 13:13:42 1998
+++ linux/drivers/video/sbusfb.c	Fri Nov 13 10:10:12 1998
@@ -184,7 +184,8 @@
 #ifdef __sparc_v9__
 	/* Align it as much as desirable */
 	{
-		int j, max = -1, alignment, s = 0;
+		unsigned long j, alignment, s = 0;
+		int max = -1;
 		
 		map_offset = vma->vm_offset+size;
 		for (i = 0; fb->mmap_map[i].size; i++) {
diff -u --recursive --new-file v2.1.128/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.1.128/linux/drivers/video/virgefb.c	Mon Oct  5 13:13:42 1998
+++ linux/drivers/video/virgefb.c	Fri Nov 13 10:10:12 1998
@@ -152,6 +152,8 @@
 static unsigned long CyberSize;
 static volatile char *CyberRegs;
 static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
  
 
 /*
@@ -208,6 +210,13 @@
 	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	}
+    }, {
+	"1024x768-16", {         /* Cybervision 16 bpp */
+	    1024, 768, 1024, 768, 0, 0, 16, 0,
+	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+       }
     }
 };
 
@@ -371,9 +380,9 @@
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, virgefb_name);
-	fix->smem_start = (char *)CyberMem;
+	fix->smem_start = (char*) CyberMem_phys;
 	fix->smem_len = CyberSize;
-	fix->mmio_start = (char *)CyberRegs;
+	fix->mmio_start = (char*) CyberRegs_phys;
 	fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
 
 	fix->type = FB_TYPE_PACKED_PIXELS;
@@ -843,7 +852,7 @@
 	virgefb_get_fix(&fix, con, info);
 	if (con == -1)
 		con = 0;
-	display->screen_base = fix.smem_start;
+	display->screen_base = (char*) CyberMem;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -1033,7 +1042,8 @@
 		 * Ok we got the board running in Z2 space.
 		 */
 
-		CyberMem = ZTWO_VADDR(board_addr);
+		CyberMem_phys = board_addr;
+		CyberMem = ZTWO_VADDR(CyberMem_phys);
 		printk("CV3D detected running in Z2 mode ... not yet supported!\n");
 		return;
 	}
@@ -1041,10 +1051,13 @@
 	{
 		CyberVGARegs = kernel_map(board_addr +0x0c000000, 0x00010000,
 					       KERNELMAP_NOCACHE_SER, NULL);
-		CyberRegs = (char *)kernel_map(board_addr +0x05000000,
+
+		CyberRegs_phys = board_addr + 0x05000000;
+		CyberMem_phys  = board_addr + 0x04800000;
+		CyberRegs = (char *)kernel_map(CyberRegs_phys,
 					       0x00010000,
 					       KERNELMAP_NOCACHE_SER, NULL);
-		CyberMem = kernel_map(board_addr + 0x04800000, 0x00400000,
+		CyberMem = kernel_map(CyberMem_phys, 0x00400000,
 				      KERNELMAP_NOCACHE_SER, NULL);
 		printk("CV3D detected running in Z3 mode\n");
 	}
diff -u --recursive --new-file v2.1.128/linux/fs/Config.in linux/fs/Config.in
--- v2.1.128/linux/fs/Config.in	Fri Oct 23 22:01:22 1998
+++ linux/fs/Config.in	Mon Nov 16 13:33:40 1998
@@ -48,7 +48,7 @@
     bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95
   fi
 fi
-if [ "$CONFIG_IPX" != "n" ]; then
+if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
   if [ "$CONFIG_NCP_FS" != "n" ]; then
     source fs/ncpfs/Config.in
diff -u --recursive --new-file v2.1.128/linux/fs/attr.c linux/fs/attr.c
--- v2.1.128/linux/fs/attr.c	Thu May  7 22:51:52 1998
+++ linux/fs/attr.c	Fri Nov 13 10:07:26 1998
@@ -5,12 +5,9 @@
  *  changes by Thomas Schoebel-Theuer
  */
 
-#include <linux/stat.h>
 #include <linux/sched.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/string.h>
-#include <asm/system.h>
 
 /* Taken over from the old code... */
 
diff -u --recursive --new-file v2.1.128/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.1.128/linux/fs/autofs/autofs_i.h	Sun Nov  8 14:03:04 1998
+++ linux/fs/autofs/autofs_i.h	Wed Nov 18 22:49:29 1998
@@ -66,9 +66,9 @@
 };
 
 struct autofs_wait_queue {
-	unsigned long wait_queue_token;
 	struct wait_queue *queue;
 	struct autofs_wait_queue *next;
+	autofs_wqt_t wait_queue_token;
 	/* We use the following to see what we are waiting for */
 	int hash;
 	int len;
@@ -79,8 +79,8 @@
 };
 
 struct autofs_symlink {
-	int len;
 	char *data;
+	int len;
 	time_t mtime;
 };
 
@@ -146,7 +146,7 @@
 /* Queue management functions */
 
 int autofs_wait(struct autofs_sb_info *,struct qstr *);
-int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
+int autofs_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
 void autofs_catatonic_mode(struct autofs_sb_info *);
 
 #ifdef DEBUG
diff -u --recursive --new-file v2.1.128/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.128/linux/fs/autofs/root.c	Sun Nov  8 14:03:05 1998
+++ linux/fs/autofs/root.c	Mon Nov 16 13:33:46 1998
@@ -112,7 +112,8 @@
 	if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
 		do {
 			if ( status && dentry->d_inode ) {
-				printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+				if ( status != -ENOENT )
+					printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
 				return 0; /* Try to get the kernel to invalidate this dentry */
 			}
 
@@ -502,9 +503,9 @@
 	
 	switch(cmd) {
 	case AUTOFS_IOC_READY:	/* Wait queue: go ahead and retry */
-		return autofs_wait_release(sbi,arg,0);
+		return autofs_wait_release(sbi,(autofs_wqt_t)arg,0);
 	case AUTOFS_IOC_FAIL:	/* Wait queue: fail with ENOENT */
-		return autofs_wait_release(sbi,arg,-ENOENT);
+		return autofs_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT);
 	case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
 		autofs_catatonic_mode(sbi);
 		return 0;
diff -u --recursive --new-file v2.1.128/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.128/linux/fs/autofs/waitq.c	Sun Nov  8 14:03:05 1998
+++ linux/fs/autofs/waitq.c	Mon Nov 16 13:33:46 1998
@@ -18,7 +18,7 @@
 
 /* We make this a static variable rather than a part of the superblock; it
    is better if we don't reassign numbers easily even across filesystems */
-static int autofs_next_wait_queue = 1;
+static autofs_wqt_t autofs_next_wait_queue = 1;
 
 /* These are the signals we allow interrupting a pending mount */
 #define SHUTDOWN_SIGS	(sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
@@ -168,7 +168,7 @@
 }
 
 
-int autofs_wait_release(struct autofs_sb_info *sbi, unsigned long wait_queue_token, int status)
+int autofs_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_token, int status)
 {
 	struct autofs_wait_queue *wq, **wql;
 
diff -u --recursive --new-file v2.1.128/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.1.128/linux/fs/block_dev.c	Mon Oct  5 13:13:42 1998
+++ linux/fs/block_dev.c	Fri Nov 13 10:07:26 1998
@@ -4,15 +4,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/locks.h>
 #include <linux/fcntl.h>
-#include <linux/mm.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 extern int *blk_size[];
 extern int *blksize_size[];
diff -u --recursive --new-file v2.1.128/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.128/linux/fs/buffer.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/buffer.c	Fri Nov 13 10:07:26 1998
@@ -24,18 +24,11 @@
  * - RMK
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
+#include <linux/malloc.h>
 #include <linux/locks.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <linux/swapctl.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
@@ -44,7 +37,6 @@
 #include <linux/init.h>
 #include <linux/quotaops.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
diff -u --recursive --new-file v2.1.128/linux/fs/exec.c linux/fs/exec.c
--- v2.1.128/linux/fs/exec.c	Thu Nov 12 16:21:22 1998
+++ linux/fs/exec.c	Sun Nov 15 09:52:27 1998
@@ -22,33 +22,20 @@
  * formats. 
  */
 
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
+#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/mman.h>
 #include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/binfmts.h>
-#include <linux/personality.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
-
-#include <linux/config.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
diff -u --recursive --new-file v2.1.128/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.1.128/linux/fs/fat/inode.c	Thu Sep 17 17:53:37 1998
+++ linux/fs/fat/inode.c	Mon Nov 16 10:54:43 1998
@@ -624,7 +624,8 @@
 	if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
 		printk("dev = %s, ino = %ld\n",
 		       kdevname(inode->i_dev), inode->i_ino);
-		panic("fat_read_inode: unable to read i-node block");
+		fat_fs_panic(sb, "fat_read_inode: unable to read i-node block");
+		return;
 	}
 	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
 	    [inode->i_ino & (MSDOS_DPB-1)];
@@ -713,7 +714,8 @@
 	if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
 		printk("dev = %s, ino = %ld\n",
 		       kdevname(inode->i_dev), inode->i_ino);
-		panic("msdos_write_inode: unable to read i-node block");
+		fat_fs_panic(sb, "msdos_write_inode: unable to read i-node block");
+		return;
 	}
 	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
 	    [inode->i_ino & (MSDOS_DPB-1)];
diff -u --recursive --new-file v2.1.128/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.1.128/linux/fs/fcntl.c	Mon Oct  5 13:13:42 1998
+++ linux/fs/fcntl.c	Fri Nov 13 10:07:26 1998
@@ -4,18 +4,10 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/file.h>
-#include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
+#include <linux/file.h>
 #include <linux/smp_lock.h>
 
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
diff -u --recursive --new-file v2.1.128/linux/fs/fifo.c linux/fs/fifo.c
--- v2.1.128/linux/fs/fifo.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/fifo.c	Fri Nov 13 10:07:26 1998
@@ -4,10 +4,6 @@
  *  written by Paul H. Hargrove
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
 #include <linux/mm.h>
 
 static int fifo_open(struct inode * inode,struct file * filp)
diff -u --recursive --new-file v2.1.128/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.128/linux/fs/file_table.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/file_table.c	Fri Nov 13 10:07:26 1998
@@ -5,13 +5,8 @@
  *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/string.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <linux/init.h>
 
 /* SLAB cache for filp's. */
diff -u --recursive --new-file v2.1.128/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog
--- v2.1.128/linux/fs/hfs/ChangeLog	Sun Nov  8 14:03:05 1998
+++ linux/fs/hfs/ChangeLog	Sun Nov 15 11:11:44 1998
@@ -1,3 +1,9 @@
+1998-11-12  a sun  <asun@hecate.darksunrising.blah>
+
+	* extent.c (shrink_fork): added some lock_bitmap/unlock_bitmap's
+	to protect hfs_clear_vbm_bits. we should no longer have problems
+	with free_ablocks wrapping around.
+
 1998-11-02  a sun  <asun@hecate.darksunrising.blah>
 
 	* mdb.c (hfs_mdb_get): plugged up an mdb failed initialization
diff -u --recursive --new-file v2.1.128/linux/fs/hfs/btree.c linux/fs/hfs/btree.c
--- v2.1.128/linux/fs/hfs/btree.c	Sun Jan  4 10:40:17 1998
+++ linux/fs/hfs/btree.c	Sun Nov 15 11:11:44 1998
@@ -176,6 +176,14 @@
 	bt->wait = NULL;
 	bt->dirt = 0;
 	memset(bt->cache, 0, sizeof(bt->cache));
+
+#if 0   /* this is a fake entry. so we don't need to initialize it. */
+	memset(&bt->entry, 0, sizeof(bt->entry));
+	hfs_init_waitqueue(&bt->entry.wait);
+	INIT_LIST_HEAD(&bt->entry.hash);
+	INIT_LIST_HEAD(&bt->entry.list);
+#endif
+
 	bt->entry.mdb = mdb;
 	bt->entry.cnid = cnid;
 	bt->entry.type = HFS_CDR_FIL;
diff -u --recursive --new-file v2.1.128/linux/fs/hfs/extent.c linux/fs/hfs/extent.c
--- v2.1.128/linux/fs/hfs/extent.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/extent.c	Sun Nov 15 11:11:44 1998
@@ -487,6 +487,7 @@
 
 	if ((count = next + 1 - ablocks) > 0) {
 		for (i=2; (i>=0) && !ext->length[i]; --i) {};
+		lock_bitmap(mdb);
 		while (count && (ext->length[i] <= count)) {
 			ext->end -= ext->length[i];
 			count -= ext->length[i];
@@ -509,6 +510,7 @@
 				       "blocks.\n", error);
 			}
 		}
+		unlock_bitmap(mdb);
 		update_ext(fork, ext);
 	}
 
@@ -612,7 +614,9 @@
 		} else {
 			if (!(ext = new_extent(fork, ext, blocks/ablksz,
 					       start, len, ablksz))) {
+				lock_bitmap(mdb);
 				hfs_clear_vbm_bits(mdb, start, len);
+				unlock_bitmap(mdb);
 				return;
 			}
 		}
diff -u --recursive --new-file v2.1.128/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.1.128/linux/fs/hfs/file_hdr.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/file_hdr.c	Sun Nov 15 11:11:44 1998
@@ -937,7 +937,7 @@
 		if (fork->lsize != descr->length) {
 			fork->lsize = descr->length;
 			hfs_extent_adj(fork);
-			hfs_cat_mark_dirty(HFS_I(inode)->entry);
+			hfs_cat_mark_dirty(entry);
 		}
 	}
 }
diff -u --recursive --new-file v2.1.128/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c
--- v2.1.128/linux/fs/hfs/mdb.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/mdb.c	Sun Nov 15 11:11:44 1998
@@ -260,6 +260,9 @@
 	hfs_put_hl(mdb->file_count,    raw->drFilCnt);
 	hfs_put_hl(mdb->dir_count,     raw->drDirCnt);
 
+	/* write MDB to disk */
+	hfs_buffer_dirty(mdb->buf);
+
        	/* write the backup MDB, not returning until it is written. 
          * we only do this when either the catalog or extents overflow
          * files grow. */
diff -u --recursive --new-file v2.1.128/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.1.128/linux/fs/ioctl.c	Wed Jun 24 22:54:09 1998
+++ linux/fs/ioctl.c	Fri Nov 13 10:07:26 1998
@@ -4,15 +4,8 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/termios.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/fcntl.h> /* for f_flags values */
 #include <linux/file.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.128/linux/fs/locks.c linux/fs/locks.c
--- v2.1.128/linux/fs/locks.c	Fri Oct  9 13:27:14 1998
+++ linux/fs/locks.c	Fri Nov 13 10:07:26 1998
@@ -106,13 +106,7 @@
  */
 
 #include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
 #include <linux/file.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.128/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.128/linux/fs/msdos/namei.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/msdos/namei.c	Sun Nov 15 09:52:27 1998
@@ -5,17 +5,15 @@
  *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
  */
 
-#include <linux/config.h>
 
 #define __NO_VERSION__
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/sched.h>
 #include <linux/msdos_fs.h>
-#include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/stat.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.1.128/linux/fs/namei.c linux/fs/namei.c
--- v2.1.128/linux/fs/namei.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/namei.c	Mon Nov 16 10:38:09 1998
@@ -12,22 +12,14 @@
  * lookup logic.
  */
 
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/semaphore.h>
-#include <asm/spinlock.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
@@ -346,6 +338,7 @@
 		do {
 			name++;
 		} while (*name == '/');
+		__prefix_lookup_dentry(name, lookup_flags);
 		base = dget(current->fs->root);
 	} else if (!base) {
 		base = dget(current->fs->pwd);
diff -u --recursive --new-file v2.1.128/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.128/linux/fs/nfs/dir.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/nfs/dir.c	Fri Nov 13 12:33:49 1998
@@ -488,13 +488,7 @@
 printk("nfs_dentry_iput: pending writes for %s/%s, i_count=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
 #endif
-		while (nfs_find_dentry_request(inode, dentry)) {
-#ifdef NFS_PARANOIA
-printk("nfs_dentry_iput: flushing %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-			nfs_flush_dirty_pages(inode, 0, 0, 0);
-		}
+		nfs_wbinval(inode);
 	}
 	iput(inode);
 }
@@ -940,7 +934,7 @@
 	error = -EBUSY;
 	if (inode) {
 		if (NFS_WRITEBACK(inode)) {
-			nfs_flush_dirty_pages(inode, 0, 0, 0);
+			nfs_wbinval(inode);
 			if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
@@ -1204,7 +1198,7 @@
 printk("nfs_rename: %s/%s has pending writes\n",
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
 #endif
-			nfs_flush_dirty_pages(old_inode, 0, 0, 0);
+			nfs_wbinval(old_inode);
 			if (NFS_WRITEBACK(old_inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: %s/%s has pending writes after flush\n",
diff -u --recursive --new-file v2.1.128/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.1.128/linux/fs/nfs/file.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/nfs/file.c	Fri Nov 13 13:58:44 1998
@@ -95,7 +95,7 @@
 
 	dfprintk(VFS, "nfs: close(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-	status = nfs_flush_dirty_pages(inode, 0, 0, 0);
+	status = nfs_wbinval(inode);
 	error = nfs_write_error(inode);
 	if (!status)
 		status = error;
@@ -162,7 +162,7 @@
 
 	dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-	status = nfs_flush_dirty_pages(inode, current->pid, 0, 0);
+	status = nfs_wbinval_pid(inode, current->pid);
 	error = nfs_write_error(inode);
 	if (!status)
 		status = error;
@@ -246,7 +246,7 @@
 	 * been killed by a signal, that is). */
 	if (cmd == F_SETLK && fl->fl_type == F_UNLCK
 	    && !signal_pending(current)) {
-		status = nfs_flush_dirty_pages(inode, current->pid,
+		status = nfs_wb_area(inode, /* current->pid  ?*/
 			fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 :
 			fl->fl_end - fl->fl_start + 1);
 		if (status < 0)
diff -u --recursive --new-file v2.1.128/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.128/linux/fs/nfs/inode.c	Sun Nov  8 14:03:07 1998
+++ linux/fs/nfs/inode.c	Fri Nov 13 14:48:32 1998
@@ -105,7 +105,7 @@
 #ifdef NFS_DEBUG_VERBOSE
 printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 #endif
-		nfs_invalidate_pages(inode);
+		nfs_inval(inode);
 		while (NFS_WRITEBACK(inode) != NULL &&
 		       time_before(jiffies, timeout)) {
 			current->state = TASK_INTERRUPTIBLE;
@@ -827,7 +827,7 @@
 	if (!S_ISDIR(inode->i_mode)) {
 		/* This sends off all dirty pages off to the server.
 		 * Note that this function must not sleep. */
-		nfs_invalidate_pages(inode);
+		nfs_inval(inode);
 		invalidate_inode_pages(inode);
 	} else
 		nfs_invalidate_dircache(inode);
diff -u --recursive --new-file v2.1.128/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.1.128/linux/fs/nfs/read.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/nfs/read.c	Sun Nov 15 19:56:33 1998
@@ -225,7 +225,7 @@
 {
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	int		error = -1;
+	int		error;
 
 	dprintk("NFS: nfs_readpage (%p %ld@%ld)\n",
 		page, PAGE_SIZE, page->offset);
@@ -235,12 +235,14 @@
 	 * Try to flush any pending writes to the file..
 	 *
 	 * NOTE! Because we own the page lock, there cannot
-	 * be any new pending writes generated at this point.
+	 * be any new pending writes generated at this point
+	 * for this page (other pages can be written to).
 	 */
-	error = nfs_flush_pages(inode, 0, 0, 0);
+	error = nfs_wb_page(inode, page);
 	if (error)
 		return error;
 
+	error = -1;
 	atomic_inc(&page->count);
 	if (!IS_SWAPFILE(inode) && !PageError(page) &&
 	    NFS_SERVER(inode)->rsize >= PAGE_SIZE)
diff -u --recursive --new-file v2.1.128/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.128/linux/fs/nfs/write.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/nfs/write.c	Sun Nov 15 12:13:04 1998
@@ -46,7 +46,6 @@
  * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/swap.h>
@@ -332,8 +331,6 @@
 	wreq->wb_bytes  = bytes;
 	wreq->wb_count	= 2;		/* One for the IO, one for us */
 
-	atomic_inc(&page->count);
-
 	append_write_request(&NFS_WRITEBACK(inode), wreq);
 
 	if (nr_write_requests++ > NFS_WRITEBACK_MAX*3/4)
@@ -480,8 +477,7 @@
 
 	/*
 	 * Ok, there's another user of this page with the new request..
-	 * Increment the usage count, and schedule the request (the
-	 * end of the request will drop the usage count..)
+	 * The IO completion will then free the page.
 	 */
 	atomic_inc(&page->count);
 
@@ -546,65 +542,101 @@
 }
 
 /*
- * Try to flush any dirty pages, returning a success marker..
- *
- * Unlike "nfs_flush_dirty_pages()" this does not invalidate
- * the writes if it is interrupted. The caller will instead
- * look at the error code and gracefully fail to do what it
- * wanted to do. 
+ * If we're waiting on somebody else's request
+ * we need to increment the counter during the
+ * wait so that the request doesn't disappear
+ * from under us during the wait..
  */
-int
-nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+static int FASTCALL(wait_on_other_req(struct nfs_wreq *));
+static int wait_on_other_req(struct nfs_wreq *req)
 {
 	int retval;
+	req->wb_count++;
+	retval = wait_on_write_request(req);
+	free_write_request(req);
+	return retval;
+}
 
-	do {
-		struct nfs_wreq *req = NFS_WRITEBACK(inode);
-		struct nfs_wreq *head = req;
+/*
+ * This writes back a set of requests according to the condition.
+ *
+ * If this ever gets much more convoluted, use a fn pointer for
+ * the condition..
+ */
+#define NFS_WB(inode, cond) { int retval = 0 ; \
+	do { \
+		struct nfs_wreq *req = NFS_WRITEBACK(inode); \
+		struct nfs_wreq *head = req; \
+		if (!req) break; \
+		for (;;) { \
+			if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \
+				if (cond) break; \
+			req = WB_NEXT(req); \
+			if (req == head) goto out; \
+		} \
+		retval = wait_on_other_req(req); \
+	} while (!retval); \
+out:	return retval; \
+}
 
-		if (!req)
-			return 0;
+int
+nfs_wb_all(struct inode *inode)
+{
+	NFS_WB(inode, 1);
+}
 
-		/*
-		 * Iterate over all outstanding write requests,
-		 * looking for any that are ours..
-		 */
-		for (;;) {
-			if (!(req->wb_flags & NFS_WRITE_COMPLETE)) {
-				if (!pid || req->wb_pid == pid)
-					break;
-			}
-			req = WB_NEXT(req);
-			if (req == head)
-				return 0;
-		}
+/*
+ * Write back all requests on one page - we do this before reading it.
+ */
+int
+nfs_wb_page(struct inode *inode, struct page *page)
+{
+	NFS_WB(inode, req->wb_page == page);
+}
 
-		req->wb_count++;
-		retval = wait_on_write_request(req);
-		free_write_request(req);
-	} while (!retval);
-	return retval;
-}	
+/*
+ * Write back all pending writes for one user.. 
+ */
+int
+nfs_wb_pid(struct inode *inode, pid_t pid)
+{
+	NFS_WB(inode, req->wb_pid == pid);
+}
 
 /*
- * Flush out all dirty pages belonging to a certain user process and
- * maybe wait for the RPC calls to complete.
- *
- * Another purpose of this function is sync()ing a file range before a
- * write lock is released. This is what offset and length are for, even if
- * this isn't used by the nlm module yet.
+ * Write back everything in a specific area for locking purposes..
  */
 int
-nfs_flush_dirty_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+nfs_wb_area(struct inode *inode, off_t offset, off_t len)
+{
+	NFS_WB(inode, 1);
+}
+
+/*
+ * Write back and invalidate. Sometimes we can't leave the stuff
+ * hanging if we can't write it out.
+ */
+int
+nfs_wbinval(struct inode *inode)
+{
+	int retval = nfs_wb_all(inode);
+
+	if (retval)
+		nfs_cancel_dirty(inode,0);
+	return retval;
+}
+
+int nfs_wbinval_pid(struct inode *inode, pid_t pid)
 {
-	int retval = nfs_flush_pages(inode, pid, offset, len);
+	int retval = nfs_wb_pid(inode, pid);
+	
 	if (retval)
 		nfs_cancel_dirty(inode,pid);
 	return retval;
 }
 
 void
-nfs_invalidate_pages(struct inode *inode)
+nfs_inval(struct inode *inode)
 {
 	nfs_cancel_dirty(inode,0);
 }
diff -u --recursive --new-file v2.1.128/linux/fs/open.c linux/fs/open.c
--- v2.1.128/linux/fs/open.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/open.c	Fri Nov 13 10:07:26 1998
@@ -4,21 +4,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/vfs.h>
-#include <linux/types.h>
+#include <linux/mm.h>
 #include <linux/utime.h>
-#include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/tty.h>
-#include <linux/time.h>
-#include <linux/mm.h>
 #include <linux/file.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
diff -u --recursive --new-file v2.1.128/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.128/linux/fs/pipe.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/pipe.c	Fri Nov 13 10:07:26 1998
@@ -4,12 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h>
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/poll.h>
diff -u --recursive --new-file v2.1.128/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.1.128/linux/fs/proc/fd.c	Wed Aug 26 11:37:43 1998
+++ linux/fs/proc/fd.c	Sun Nov 15 10:15:31 1998
@@ -119,6 +119,7 @@
 	ino = (pid << 16) + PROC_PID_FD_DIR + fd;
 	inode = proc_get_inode(dir->i_sb, ino, NULL);
 	if (inode) {
+		dentry->d_op = &proc_dentry_operations;
 		d_add(dentry, inode);
 		err = 0;
 	}
diff -u --recursive --new-file v2.1.128/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c
--- v2.1.128/linux/fs/proc/kmsg.c	Wed Aug 26 11:37:43 1998
+++ linux/fs/proc/kmsg.c	Tue Nov 17 10:09:00 1998
@@ -17,23 +17,23 @@
 extern unsigned long log_size;
 extern struct wait_queue * log_wait;
 
-asmlinkage int sys_syslog(int type, char * bug, int count);
+extern int do_syslog(int type, char * bug, int count);
 
 static int kmsg_open(struct inode * inode, struct file * file)
 {
-	return sys_syslog(1,NULL,0);
+	return do_syslog(1,NULL,0);
 }
 
 static int kmsg_release(struct inode * inode, struct file * file)
 {
-	(void) sys_syslog(0,NULL,0);
+	(void) do_syslog(0,NULL,0);
 	return 0;
 }
 
 static ssize_t kmsg_read(struct file * file, char * buf,
 			 size_t count, loff_t *ppos)
 {
-	return sys_syslog(2,buf,count);
+	return do_syslog(2,buf,count);
 }
 
 static unsigned int kmsg_poll(struct file *file, poll_table * wait)
diff -u --recursive --new-file v2.1.128/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.128/linux/fs/proc/openpromfs.c	Mon Oct  5 13:13:42 1998
+++ linux/fs/proc/openpromfs.c	Wed Nov 18 09:06:05 1998
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.31 1998/08/26 10:32:19 davem Exp $
+/* $Id: openpromfs.c,v 1.32 1998/11/18 06:15:20 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1998 Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -822,6 +822,10 @@
 		inode->i_rdev = d->rdev;
 		break;
 	}		
+
+	inode->i_gid = 0;
+	inode->i_uid = 0;
+
 	d_add(dentry, inode);
 	return 0;
 }
diff -u --recursive --new-file v2.1.128/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.128/linux/fs/proc/root.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/proc/root.c	Sun Nov 15 13:11:03 1998
@@ -730,7 +730,7 @@
 	d_drop(dentry);
 }
 
-static struct dentry_operations proc_dentry_operations =
+struct dentry_operations proc_dentry_operations =
 {
 	NULL,			/* revalidate */
 	NULL,			/* d_hash */
diff -u --recursive --new-file v2.1.128/linux/fs/qnx4/symlinks.c linux/fs/qnx4/symlinks.c
--- v2.1.128/linux/fs/qnx4/symlinks.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/qnx4/symlinks.c	Sun Nov 15 09:52:28 1998
@@ -13,7 +13,6 @@
 
 /* THIS FILE HAS TO BE REWRITTEN */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
diff -u --recursive --new-file v2.1.128/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.128/linux/fs/read_write.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/read_write.c	Fri Nov 13 10:07:26 1998
@@ -4,19 +4,12 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/types.h>
-#include <linux/errno.h>
+#include <linux/malloc.h> 
 #include <linux/stat.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
-#include <linux/mm.h>
 #include <linux/uio.h>
-#include <linux/malloc.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/limits.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.1.128/linux/fs/select.c linux/fs/select.c
--- v2.1.128/linux/fs/select.c	Sun Nov  8 14:03:07 1998
+++ linux/fs/select.c	Fri Nov 13 10:07:26 1998
@@ -10,25 +10,12 @@
  *     parameter to reflect time remaining.
  */
 
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/personality.h>
-#include <linux/mm.h>
 #include <linux/malloc.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/file.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
diff -u --recursive --new-file v2.1.128/linux/fs/stat.c linux/fs/stat.c
--- v2.1.128/linux/fs/stat.c	Wed Jun 24 22:54:10 1998
+++ linux/fs/stat.c	Fri Nov 13 10:07:26 1998
@@ -4,15 +4,9 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.128/linux/fs/super.c linux/fs/super.c
--- v2.1.128/linux/fs/super.c	Thu Nov 12 16:21:23 1998
+++ linux/fs/super.c	Sun Nov 15 09:52:28 1998
@@ -18,26 +18,15 @@
  */
 
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mount.h>
 #include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/fd.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/acct.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
diff -u --recursive --new-file v2.1.128/linux/include/asm-alpha/namei.h linux/include/asm-alpha/namei.h
--- v2.1.128/linux/include/asm-alpha/namei.h	Mon Jun 16 16:35:59 1997
+++ linux/include/asm-alpha/namei.h	Mon Nov 16 10:38:09 1998
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1996/12/13 14:48:23 jj Exp $
+/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
  * linux/include/asm-alpha/namei.h
  *
  * Included from linux/fs/namei.c
@@ -12,7 +12,7 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
-		       last_name, last_entry, last_error) 1
+#define __prefix_lookup_dentry(name, lookup_flags) \
+        do {} while (0)
 
 #endif /* __ALPHA_NAMEI_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-arm/namei.h linux/include/asm-arm/namei.h
--- v2.1.128/linux/include/asm-arm/namei.h	Tue Jun 23 10:01:26 1998
+++ linux/include/asm-arm/namei.h	Mon Nov 16 10:38:09 1998
@@ -1,5 +1,5 @@
-/*
- * linux/include/asm-i386/namei.h
+/* 
+ * linux/include/asm-arm/namei.h
  *
  * Included from linux/fs/namei.c
  */
@@ -12,7 +12,7 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
-		       last_name, last_entry, last_error) 1
+#define __prefix_lookup_dentry(name, lookup_flags) \
+        do {} while (0)
 
 #endif /* __ASMARM_NAMEI_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-i386/namei.h linux/include/asm-i386/namei.h
--- v2.1.128/linux/include/asm-i386/namei.h	Mon Jun 16 16:35:59 1997
+++ linux/include/asm-i386/namei.h	Mon Nov 16 10:38:09 1998
@@ -12,7 +12,7 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
-		       last_name, last_entry, last_error) 1
+#define __prefix_lookup_dentry(name, lookup_flags) \
+        do {} while (0)
 
 #endif /* __I386_NAMEI_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-i386/resource.h linux/include/asm-i386/resource.h
--- v2.1.128/linux/include/asm-i386/resource.h	Fri Aug 23 05:29:01 1996
+++ linux/include/asm-i386/resource.h	Wed Nov 18 21:06:56 1998
@@ -25,7 +25,7 @@
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
-	{ _STK_LIM, _STK_LIM },				\
+	{ _STK_LIM, LONG_MAX },				\
 	{        0, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
diff -u --recursive --new-file v2.1.128/linux/include/asm-m68k/namei.h linux/include/asm-m68k/namei.h
--- v2.1.128/linux/include/asm-m68k/namei.h	Thu Sep  4 12:54:49 1997
+++ linux/include/asm-m68k/namei.h	Mon Nov 16 10:38:09 1998
@@ -12,7 +12,7 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, follow_link) \
+#define __prefix_lookup_dentry(name, lookup_flags) \
         do {} while (0)
 
 #endif
diff -u --recursive --new-file v2.1.128/linux/include/asm-mips/namei.h linux/include/asm-mips/namei.h
--- v2.1.128/linux/include/asm-mips/namei.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-mips/namei.h	Mon Nov 16 10:38:09 1998
@@ -3,7 +3,7 @@
  *
  * Included from linux/fs/namei.c
  *
- * $Id: namei.h,v 1.9 1998/05/01 01:35:59 ralf Exp $
+ * $Id: namei.h,v 1.10 1998/10/28 08:13:24 jj Exp $
  */
 #ifndef __ASM_MIPS_NAMEI_H
 #define __ASM_MIPS_NAMEI_H
@@ -14,7 +14,7 @@
 #define IRIX32_EMUL "usr/gnemul/irix/"
 
 static inline struct dentry *
-__mips_lookup_dentry(const char *name, int follow_link)
+__mips_lookup_dentry(const char *name, int lookup_flags)
 {
 	struct dentry *base;
 
@@ -22,11 +22,12 @@
 		return ERR_PTR(-ENOENT);
 
 	base = lookup_dentry (IRIX32_EMUL,
-			dget (current->fs->root), 1);
+			dget (current->fs->root), 
+			(LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
 			
 	if (IS_ERR (base)) return base;
 	
-	base = lookup_dentry (name, base, follow_link);
+	base = lookup_dentry (name, base, lookup_flags);
 
 	if (IS_ERR (base)) return base;
 
@@ -40,13 +41,13 @@
 
 #ifdef CONFIG_BINFMT_IRIX
 
-#define __prefix_lookup_dentry(name, follow_link)				\
-	dentry = __mips_lookup_dentry (name, follow_link);			\
+#define __prefix_lookup_dentry(name, lookup_flags)				\
+	dentry = __mips_lookup_dentry (name, lookup_flags);			\
 	if (!IS_ERR (dentry)) return dentry;
 
 #else /* !defined(CONFIG_BINFMT_IRIX) */
 
-#define __prefix_lookup_dentry(name, follow_link) \
+#define __prefix_lookup_dentry(name, lookup_flags) \
         do {} while (0)
 
 #endif /* !defined(CONFIG_BINFMT_IRIX) */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/adb.h linux/include/asm-ppc/adb.h
--- v2.1.128/linux/include/asm-ppc/adb.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/adb.h	Sun Nov 15 10:51:49 1998
@@ -46,7 +46,7 @@
 } adb_hardware;
 
 extern int (*adb_send_request)(struct adb_request *req, int sync);
-extern int (*adb_autopoll)(int on);
+extern int (*adb_autopoll)(int devs);
 extern int (*adb_reset_bus)(void);
 
 /* Values for adb_request flags */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/amigappc.h linux/include/asm-ppc/amigappc.h
--- v2.1.128/linux/include/asm-ppc/amigappc.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-ppc/amigappc.h	Sun Nov 15 10:51:49 1998
@@ -14,17 +14,33 @@
 #ifndef _M68K_AMIGAPPC_H
 #define _M68K_AMIGAPPC_H
 
+#ifndef __ASSEMBLY__
+
+#ifndef iobarrier /* Don't include io.h - avoid circular dependency */
+#define iobarrier() eieio()
+#endif
+
+#define APUS_WRITE(_a_, _v_)				\
+do {							\
+	(*((volatile unsigned char *)(_a_)) = (_v_));	\
+	iobarrier ();					\
+} while (0)
+
+#define APUS_READ(_a_, _v_) 				\
+do {							\
+	(_v_) = (*((volatile unsigned char *)(_a_)));	\
+	iobarrier ();					\
+} while (0)
+#endif /* ndef __ASSEMBLY__ */
+
 /* Maybe add a [#ifdef WANT_ZTWOBASE] condition to amigahw.h? */
 #define zTwoBase (0x80000000)
 
-/* At CYBERBASEp we'll find the following sum:
+/* At CYBERBASEp we find the following sum:
  * -KERNELBASE+CyberStormMemoryBase
  */
 #define CYBERBASEp (0xfff00000)
 
-#define APUS_WRITE(a,v) (*((volatile unsigned char *)a) = v)
-#define APUS_READ(a) (*((volatile unsigned char *)a))
-
 #define APUS_IPL_BASE   	(zTwoBase + 0x00f60000)
 #define APUS_REG_RESET    	(APUS_IPL_BASE + 0x00)
 #define APUS_REG_WAITSTATE    	(APUS_IPL_BASE + 0x10)
@@ -32,6 +48,7 @@
 #define APUS_REG_LOCK		(APUS_IPL_BASE + 0x20)
 #define APUS_REG_INT    	(APUS_IPL_BASE + 0x28)
 #define APUS_IPL_EMU		(APUS_IPL_BASE + 0x30)
+#define APUS_INT_LVL		(APUS_IPL_BASE + 0x38)
 
 #define REGSHADOW_SETRESET	(0x80)
 #define REGSHADOW_SELFRESET	(0x40)
@@ -65,5 +82,8 @@
 #define IPLEMU_PPCIPL1		(0x02)
 #define IPLEMU_PPCIPL0		(0x01)
 #define IPLEMU_IPLMASK		(IPLEMU_PPCIPL2|IPLEMU_PPCIPL1|IPLEMU_PPCIPL0)
+
+#define INTLVL_SETRESET         (0x80)
+#define INTLVL_MASK             (0x7f)
 
 #endif /* _M68k_AMIGAPPC_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.1.128/linux/include/asm-ppc/dma.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-ppc/dma.h	Sun Nov 15 10:51:49 1998
@@ -8,6 +8,8 @@
 
 #include <linux/config.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
+#include <asm/system.h>
 
 /*
  * Note: Adapted for PowerPC by Gary Thomas
@@ -202,6 +204,20 @@
 #define DMA2_EXT_REG               0x4D6
 
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
 
 /* enable/disable a specific DMA channel */
 static __inline__ void enable_dma(unsigned int dmanr)
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- v2.1.128/linux/include/asm-ppc/feature.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/feature.h	Sun Nov 15 10:51:49 1998
@@ -0,0 +1,65 @@
+/*
+ * Definitions for accessing the Feature Control Register (FCR)
+ * on Power Macintoshes and similar machines.  The FCR lets us
+ * enable/disable, reset, and power up/down various peripherals.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Paul Mackerras.
+ */
+#ifndef __ASM_PPC_FEATURE_H
+#define __ASM_PPC_FEATURE_H
+
+/*
+ * The FCR bits for particular features vary somewhat between
+ * different machines.  So we abstract a list of features here
+ * and let the feature_* routines map them to the actual bits.
+ */
+enum system_feature {
+	FEATURE_null,
+	FEATURE_Serial_reset,
+	FEATURE_Serial_enable,
+	FEATURE_Serial_IO_A,
+	FEATURE_Serial_IO_B,
+	FEATURE_SWIM3_enable,
+	FEATURE_MESH_enable,
+	FEATURE_IDE_enable,
+	FEATURE_VIA_enable,
+	FEATURE_CD_power,
+	FEATURE_Mediabay_reset,
+	FEATURE_Mediabay_enable,
+	FEATURE_Mediabay_PCI_enable,
+	FEATURE_Mediabay_IDE_enable,
+	FEATURE_Mediabay_floppy_enable,
+	FEATURE_BMac_reset,
+	FEATURE_BMac_IO_enable,
+	FEATURE_Modem_PowerOn,
+	FEATURE_Modem_Reset,
+	FEATURE_last,
+};
+
+/* Note about the device parameter: Each device gives it's own entry. If NULL,
+   the feature function will just do nothing and return -EINVAL.
+   The feature management will walk up the device tree until in reaches a recognized
+   chip for which features can be changed and it will then apply the necessary
+   features to that chip. If it's not found, -ENODEV is returned.
+   Note also that feature_test/set/clear are interrupt-safe provided that they are
+   called _after_ feature_init() is completed.
+ */
+
+/* Test whether a particular feature is enabled. May return -ENODEV*/
+extern int	feature_test(struct device_node* device, enum system_feature f);
+
+/* Set a particular feature. Returns 0 or -ENODEV */
+extern int	feature_set(struct device_node* device, enum system_feature f);
+
+/* Clear a particular feature */
+extern int	feature_clear(struct device_node* device, enum system_feature f);
+
+/* Initialize feature stuff */
+extern void	feature_init(void);
+
+
+#endif /* __ASM_PPC_FEATURE_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.1.128/linux/include/asm-ppc/ide.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/ide.h	Sun Nov 15 10:51:49 1998
@@ -42,6 +42,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/hdreg.h>
 #include <linux/ioport.h>
 #include <asm/io.h>		/* so we can redefine insw/outsw */
 
@@ -98,9 +99,11 @@
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
         if (_machine == _MACH_Pmac) {
 		return pmac_ide_regbase[index];
 	}
+#endif	
 	if (_machine == _MACH_mbx) return index;
         if ( _machine == _MACH_chrp ) {
                 if (chrp_ide_ports_known == 0)
@@ -138,13 +141,76 @@
 	release_region(from, extent);
 }
 
-#define ide_fix_driveid(id)	do {			\
-	int nh;						\
-	unsigned short *p = (unsigned short *) id;	\
-	if (( _machine == _MACH_Pmac ) || (_machine == _MACH_chrp)|| (_machine == _MACH_mbx) )	\
-		for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p)	\
-			*p = (*p << 8) + (*p >> 8);	\
-} while (0)
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+   chars are endian independant, of course, but strings need to be flipped.
+   (Despite what it says in drivers/block/ide.h, they come up as little endian...)
+   Changes to linux/hdreg.h may require changes here. */
+static __inline__ void ide_fix_driveid (struct hd_driveid *id) {
+	if (( _machine == _MACH_Pmac ) || (_machine == _MACH_chrp)|| (_machine == _MACH_mbx) ) {
+		int i;
+		unsigned short *stringcast;
+		id->config         = __le16_to_cpu(id->config);
+		id->cyls           = __le16_to_cpu(id->cyls);
+		id->reserved2      = __le16_to_cpu(id->reserved2);
+		id->heads          = __le16_to_cpu(id->heads);
+		id->track_bytes    = __le16_to_cpu(id->track_bytes);
+		id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+		id->sectors        = __le16_to_cpu(id->sectors);
+		id->vendor0        = __le16_to_cpu(id->vendor0);
+		id->vendor1        = __le16_to_cpu(id->vendor1);
+		id->vendor2        = __le16_to_cpu(id->vendor2);
+		stringcast = (unsigned short *)&id->serial_no[0];
+		for (i=0; i<(20/2); i++)
+			stringcast[i] = __le16_to_cpu(stringcast[i]);
+		id->buf_type       = __le16_to_cpu(id->buf_type);
+		id->buf_size       = __le16_to_cpu(id->buf_size);
+		id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+		stringcast = (unsigned short *)&id->fw_rev[0];
+		for (i=0; i<(8/2); i++)
+			stringcast[i] = __le16_to_cpu(stringcast[i]);
+		stringcast = (unsigned short *)&id->model[0];
+		for (i=0; i<(40/2); i++)
+			stringcast[i] = __le16_to_cpu(stringcast[i]);
+		id->dword_io       = __le16_to_cpu(id->dword_io);
+		id->reserved50     = __le16_to_cpu(id->reserved50);
+		id->field_valid    = __le16_to_cpu(id->field_valid);
+		id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+		id->cur_heads      = __le16_to_cpu(id->cur_heads);
+		id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+		id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+		id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+		id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+		id->dma_1word      = __le16_to_cpu(id->dma_1word);
+		id->dma_mword      = __le16_to_cpu(id->dma_mword);
+		id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+		id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+		id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+		id->eide_pio       = __le16_to_cpu(id->eide_pio);
+		id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+		id->word69         = __le16_to_cpu(id->word69);
+		id->word70         = __le16_to_cpu(id->word70);
+		id->word71         = __le16_to_cpu(id->word71);
+		id->word72         = __le16_to_cpu(id->word72);
+		id->word73         = __le16_to_cpu(id->word73);
+		id->word74         = __le16_to_cpu(id->word74);
+		id->word75         = __le16_to_cpu(id->word75);
+		id->word76         = __le16_to_cpu(id->word76);
+		id->word77         = __le16_to_cpu(id->word77);
+		id->word78         = __le16_to_cpu(id->word78);
+		id->word79         = __le16_to_cpu(id->word79);
+		id->word80         = __le16_to_cpu(id->word80);
+		id->word81         = __le16_to_cpu(id->word81);
+		id->word82         = __le16_to_cpu(id->word82);
+		id->word83         = __le16_to_cpu(id->word83);
+		id->word84         = __le16_to_cpu(id->word84);
+		id->word85         = __le16_to_cpu(id->word85);
+		id->word86         = __le16_to_cpu(id->word86);
+		id->word87         = __le16_to_cpu(id->word87);
+		id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+		for (i=0; i<167; i++)
+			id->reserved[i] = __le16_to_cpu(id->reserved[i]);
+	}
+}
 
 
 #undef insw
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.1.128/linux/include/asm-ppc/io.h	Fri Oct  9 13:27:15 1998
+++ linux/include/asm-ppc/io.h	Sun Nov 15 10:51:49 1998
@@ -49,18 +49,18 @@
 #endif /* CONFIG_APUS */
 #endif /* CONFIG_MBX8xx */
 
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define readb(addr) in_8((volatile unsigned char *)(addr))
+#define writeb(b,addr) out_8((volatile unsigned char *)(addr), (b))
 #if defined(CONFIG_APUS)
 #define readw(addr) (*(volatile unsigned short *) (addr))
 #define readl(addr) (*(volatile unsigned int *) (addr))
 #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
 #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
 #else
-#define readw(addr) ld_le16((volatile unsigned short *)(addr))
-#define readl(addr) ld_le32((volatile unsigned *)addr)
-#define writew(b,addr) st_le16((volatile unsigned short *)(addr),(b))
-#define writel(b,addr) st_le32((volatile unsigned *)(addr),(b))
+#define readw(addr) in_le16((volatile unsigned short *)(addr))
+#define readl(addr) in_le32((volatile unsigned *)addr)
+#define writew(b,addr) out_le16((volatile unsigned short *)(addr),(b))
+#define writel(b,addr) out_le32((volatile unsigned *)(addr),(b))
 #endif
 
 #define insb(port, buf, ns)	_insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
@@ -123,6 +123,7 @@
 extern void *__ioremap(unsigned long address, unsigned long size,
 		       unsigned long flags);
 extern void *ioremap(unsigned long address, unsigned long size);
+#define ioremap_nocache(addr, size)	ioremap((addr), (size))
 extern void iounmap(void *addr);
 extern unsigned long iopa(unsigned long addr);
 #ifdef CONFIG_APUS
@@ -180,22 +181,6 @@
 #endif
 }
 
-static inline int check_signature(unsigned long io_addr,
-	const unsigned char *signature, int length)
-{
-	int retval = 0;
-	do {
-		if (readb(io_addr) != *signature)
-			goto out;
-		io_addr++;
-		signature++;
-		length--;
-	} while (length);
-	retval = 1;
-out:
-	return retval;
-}
-
 #endif /* __KERNEL__ */
 
 /*
@@ -207,6 +192,7 @@
 {
 	__asm__ __volatile__ ("eieio" : : : "memory");
 }
+#define iobarrier() eieio()
 
 /*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
@@ -279,5 +265,23 @@
 {
 	__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
 }
+
+#ifdef __KERNEL__
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
+#endif /* __KERNEL__ */
 
 #endif
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.1.128/linux/include/asm-ppc/irq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/irq.h	Sun Nov 15 10:51:50 1998
@@ -20,7 +20,8 @@
  * so it is the max of them all - which happens to be powermac
  * at present (G3 powermacs have 64).
  */
-#define NR_IRQS			64
+#define NR_IRQS			128
+
 #endif /* CONFIG_APUS */
 
 #define NUM_8259_INTERRUPTS	16
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/mediabay.h linux/include/asm-ppc/mediabay.h
--- v2.1.128/linux/include/asm-ppc/mediabay.h	Thu Apr 23 20:21:37 1998
+++ linux/include/asm-ppc/mediabay.h	Sun Nov 15 10:51:50 1998
@@ -14,20 +14,15 @@
 #ifdef __KERNEL__
 
 void media_bay_init(void);
-int check_media_bay(int what);
-int media_bay_task(void *);
+int check_media_bay(struct device_node *which_bay, int what);
+int check_media_bay_by_base(unsigned long base, int what);
 
-extern int media_bay_present;	/* 1 if this machine has a media bay */
+/* Number of bays in the machine or 0 */
+extern int media_bay_count;
 
-/*
- * The following give information about the IDE interface
- * of the media bay: the base virtual address and IRQ number,
- * and the index that the IDE driver has assigned to it
- * (or -1 if it is not currently registered with the driver).
- */
-extern unsigned long mb_cd_base;
-extern int mb_cd_irq;
-extern int mb_cd_index;
+/* called by pmac-ide.c to register IDE controller for media bay */
+extern int media_bay_set_ide_infos(struct device_node* which_bay,
+			unsigned long base, int irq, int index);
 
 #endif /* __KERNEL__ */
 #endif /* _PPC_MEDIABAY_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/namei.h linux/include/asm-ppc/namei.h
--- v2.1.128/linux/include/asm-ppc/namei.h	Thu Sep  4 12:54:49 1997
+++ linux/include/asm-ppc/namei.h	Sun Nov 15 10:51:50 1998
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.3 1997/08/29 15:52:22 jj Exp $
+/* $Id: namei.h,v 1.4 1998/10/28 08:13:33 jj Exp $
  * linux/include/asm-ppc/namei.h
  * Adapted from linux/include/asm-alpha/namei.h
  *
@@ -13,7 +13,7 @@
  * Look at asm-sparc/namei.h for details.
  */
 
-#define __prefix_lookup_dentry(name, follow_link) \
+#define __prefix_lookup_dentry(name, lookup_flags) \
 	do {} while (0)
 
 #endif /* __PPC_NAMEI_H */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.1.128/linux/include/asm-ppc/pgtable.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/pgtable.h	Sun Nov 15 10:51:50 1998
@@ -618,8 +618,6 @@
 extern int mm_end_of_chunk (unsigned long addr, int len);
 extern unsigned long iopa(unsigned long addr);
 extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const));
-#define VTOP(addr)  (iopa((unsigned long)(addr)))
-#define PTOV(addr)  (mm_ptov((unsigned long)(addr)))
 
 /* Values for nocacheflag and cmode */
 /* These are not used by the APUS kernel_map, but prevents
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- v2.1.128/linux/include/asm-ppc/pmu.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-ppc/pmu.h	Sun Nov 15 10:51:50 1998
@@ -54,6 +54,9 @@
 
 void pmu_enable_backlight(int on);
 
+void pmu_restart(void);
+void pmu_shutdown(void);
+
 /*
  * Stuff for putting the powerbook to sleep and waking it again.
  */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h
--- v2.1.128/linux/include/asm-ppc/prom.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/prom.h	Sun Nov 15 10:51:50 1998
@@ -72,6 +72,7 @@
 extern struct device_node *find_compatible_devices(const char *type,
 						   const char *compat);
 extern struct device_node *find_phandle(phandle);
+extern int device_is_compatible(struct device_node *device, const char* compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
 				   int *lenp);
 extern void print_properties(struct device_node *node);
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.1.128/linux/include/asm-ppc/smp.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/smp.h	Sun Nov 15 10:51:50 1998
@@ -13,8 +13,22 @@
 
 #ifndef __ASSEMBLY__
 
-extern unsigned long cpu_present_map;
 extern int first_cpu_booted;
+extern unsigned long smp_proc_in_lock[NR_CPUS];
+
+extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
+extern void smp_store_cpu_info(int id);
+
+#define NO_PROC_ID		0xFF            /* No processor magic marker */
+#define PROC_CHANGE_PENALTY	2000
+
+/* 1 to 1 mapping on PPC -- Cort */
+#define cpu_logical_map(cpu) (cpu)
+extern int cpu_number_map[NR_CPUS];
+extern volatile unsigned long cpu_callin_map[NR_CPUS];
+
+#define hard_smp_processor_id() (0)
+#define smp_processor_id() (current->processor)
 
 /* per processor PPC parameters we need. */
 struct cpuinfo_PPC {
@@ -33,40 +47,13 @@
 };
 
 extern struct klock_info_struct klock_info;
-
 #define KLOCK_HELD       0xffffffff
 #define KLOCK_CLEAR      0x0
 
-#define PROC_CHANGE_PENALTY     20
-
-extern __volatile__ int cpu_number_map[NR_CPUS];
-extern __volatile__ int __cpu_logical_map[NR_CPUS];
-extern unsigned long smp_proc_in_lock[NR_CPUS];
-
-extern __inline__ int cpu_logical_map(int cpu)
-{
-	return __cpu_logical_map[cpu];
-}
-
-extern __inline__ int hard_smp_processor_id(void)
-{
-	int cpuid = 0;
-	/* assume cpu # 0 for now */
-	return cpuid;
-}
-
-#define smp_processor_id() (current->processor)
-
-extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
-
 #endif /* __ASSEMBLY__ */
 
 #else /* !(__SMP__) */
 
 #endif /* !(__SMP__) */
-
-#define NO_PROC_ID               0xFF            /* No processor magic marker */
-
-extern void smp_store_cpu_info(int id);
 
 #endif /* !(_PPC_SMP_H) */
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h
--- v2.1.128/linux/include/asm-ppc/unistd.h	Fri Oct  9 13:27:15 1998
+++ linux/include/asm-ppc/unistd.h	Sun Nov 15 10:51:50 1998
@@ -5,7 +5,6 @@
  * This file contains the system call numbers.
  */
 
-#define __NR_setup		  0	/* used only by init, to get system going */
 #define __NR_exit		  1
 #define __NR_fork		  2
 #define __NR_read		  3
@@ -57,7 +56,7 @@
 #define __NR_geteuid		 49
 #define __NR_getegid		 50
 #define __NR_acct		 51
-#define __NR_phys		 52
+#define __NR_umount2		 52
 #define __NR_lock		 53
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
@@ -195,7 +194,6 @@
 #define __NR_getpmsg		187	/* some people actually want streams */
 #define __NR_putpmsg		188	/* some people actually want streams */
 
-
 #define __NR(n)	#n
 
 
@@ -394,7 +392,6 @@
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
 static inline _syscall0(int,pause)
-static inline _syscall1(int,setup,int,magic)
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
diff -u --recursive --new-file v2.1.128/linux/include/asm-ppc/vga.h linux/include/asm-ppc/vga.h
--- v2.1.128/linux/include/asm-ppc/vga.h	Thu Jul 16 18:09:29 1998
+++ linux/include/asm-ppc/vga.h	Sun Nov 15 10:51:51 1998
@@ -21,8 +21,11 @@
 	return ld_le16(addr);
 }
 
-#define VGA_MAP_MEM(x) (x + _ISA_MEM_BASE)
+#define VT_BUF_HAVE_MEMCPYF
+#define scr_memcpyw_from memcpy
+#define scr_memcpyw_to memcpy
 
+#define VGA_MAP_MEM(x) (x + _ISA_MEM_BASE)
 #define vga_readb(x) (*(x))
 #define vga_writeb(x,y) (*(y) = (x))
 
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.1.128/linux/include/asm-sparc/asm_offsets.h	Sun Nov  8 14:03:08 1998
+++ linux/include/asm-sparc/asm_offsets.h	Mon Nov 16 10:37:28 1998
@@ -74,93 +74,91 @@
 #define ASIZ_task_tarray_ptr	0x00000004
 #define AOFF_task_wait_chldexit	0x0000008c
 #define ASIZ_task_wait_chldexit	0x00000004
-#define AOFF_task_timeout	0x00000090
-#define ASIZ_task_timeout	0x00000004
-#define AOFF_task_policy	0x00000094
+#define AOFF_task_policy	0x00000090
 #define ASIZ_task_policy	0x00000004
-#define AOFF_task_rt_priority	0x00000098
+#define AOFF_task_rt_priority	0x00000094
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x0000009c
+#define AOFF_task_it_real_value	0x00000098
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000a0
+#define AOFF_task_it_prof_value	0x0000009c
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x000000a4
+#define AOFF_task_it_virt_value	0x000000a0
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x000000a8
+#define AOFF_task_it_real_incr	0x000000a4
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x000000ac
+#define AOFF_task_it_prof_incr	0x000000a8
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x000000b0
+#define AOFF_task_it_virt_incr	0x000000ac
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x000000b4
+#define AOFF_task_real_timer	0x000000b0
 #define ASIZ_task_real_timer	0x00000014
-#define AOFF_task_times	0x000000c8
+#define AOFF_task_times	0x000000c4
 #define ASIZ_task_times	0x00000010
-#define AOFF_task_start_time	0x000000d8
+#define AOFF_task_start_time	0x000000d4
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_per_cpu_utime	0x000000dc
+#define AOFF_task_per_cpu_utime	0x000000d8
 #define ASIZ_task_per_cpu_utime	0x00000004
-#define AOFF_task_min_flt	0x000000e4
+#define AOFF_task_min_flt	0x000000e0
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x000000e8
+#define AOFF_task_maj_flt	0x000000e4
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x000000ec
+#define AOFF_task_nswap	0x000000e8
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x000000f0
+#define AOFF_task_cmin_flt	0x000000ec
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x000000f4
+#define AOFF_task_cmaj_flt	0x000000f0
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x000000f8
+#define AOFF_task_cnswap	0x000000f4
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_swap_address	0x00000100
+#define AOFF_task_swap_address	0x000000fc
 #define ASIZ_task_swap_address	0x00000004
-#define AOFF_task_old_maj_flt	0x00000104
+#define AOFF_task_old_maj_flt	0x00000100
 #define ASIZ_task_old_maj_flt	0x00000004
-#define AOFF_task_dec_flt	0x00000108
+#define AOFF_task_dec_flt	0x00000104
 #define ASIZ_task_dec_flt	0x00000004
-#define AOFF_task_swap_cnt	0x0000010c
+#define AOFF_task_swap_cnt	0x00000108
 #define ASIZ_task_swap_cnt	0x00000004
-#define AOFF_task_uid	0x00000110
+#define AOFF_task_uid	0x0000010c
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x00000112
+#define AOFF_task_euid	0x0000010e
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x00000114
+#define AOFF_task_suid	0x00000110
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x00000116
+#define AOFF_task_fsuid	0x00000112
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x00000118
+#define AOFF_task_gid	0x00000114
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x0000011a
+#define AOFF_task_egid	0x00000116
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x0000011c
+#define AOFF_task_sgid	0x00000118
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x0000011e
+#define AOFF_task_fsgid	0x0000011a
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_ngroups	0x00000120
+#define AOFF_task_ngroups	0x0000011c
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000124
+#define AOFF_task_groups	0x00000120
 #define ASIZ_task_groups	0x00000040
-#define AOFF_task_cap_effective	0x00000164
+#define AOFF_task_cap_effective	0x00000160
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000168
+#define AOFF_task_cap_inheritable	0x00000164
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x0000016c
+#define AOFF_task_cap_permitted	0x00000168
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000170
+#define AOFF_task_user	0x0000016c
 #define ASIZ_task_user	0x00000004
-#define AOFF_task_rlim	0x00000174
+#define AOFF_task_rlim	0x00000170
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000001c4
+#define AOFF_task_used_math	0x000001c0
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000001c6
+#define AOFF_task_comm	0x000001c2
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000001d8
+#define AOFF_task_link_count	0x000001d4
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000001dc
+#define AOFF_task_tty	0x000001d8
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000001e0
+#define AOFF_task_semundo	0x000001dc
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000001e4
+#define AOFF_task_semsleeping	0x000001e0
 #define ASIZ_task_semsleeping	0x00000004
 #define AOFF_task_tss	0x000001e8
 #define ASIZ_task_tss	0x00000388
@@ -349,93 +347,91 @@
 #define ASIZ_task_tarray_ptr	0x00000004
 #define AOFF_task_wait_chldexit	0x0000008c
 #define ASIZ_task_wait_chldexit	0x00000004
-#define AOFF_task_timeout	0x00000090
-#define ASIZ_task_timeout	0x00000004
-#define AOFF_task_policy	0x00000094
+#define AOFF_task_policy	0x00000090
 #define ASIZ_task_policy	0x00000004
-#define AOFF_task_rt_priority	0x00000098
+#define AOFF_task_rt_priority	0x00000094
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x0000009c
+#define AOFF_task_it_real_value	0x00000098
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000a0
+#define AOFF_task_it_prof_value	0x0000009c
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x000000a4
+#define AOFF_task_it_virt_value	0x000000a0
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x000000a8
+#define AOFF_task_it_real_incr	0x000000a4
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x000000ac
+#define AOFF_task_it_prof_incr	0x000000a8
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x000000b0
+#define AOFF_task_it_virt_incr	0x000000ac
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x000000b4
+#define AOFF_task_real_timer	0x000000b0
 #define ASIZ_task_real_timer	0x00000014
-#define AOFF_task_times	0x000000c8
+#define AOFF_task_times	0x000000c4
 #define ASIZ_task_times	0x00000010
-#define AOFF_task_start_time	0x000000d8
+#define AOFF_task_start_time	0x000000d4
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_per_cpu_utime	0x000000dc
+#define AOFF_task_per_cpu_utime	0x000000d8
 #define ASIZ_task_per_cpu_utime	0x00000080
-#define AOFF_task_min_flt	0x000001dc
+#define AOFF_task_min_flt	0x000001d8
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x000001e0
+#define AOFF_task_maj_flt	0x000001dc
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x000001e4
+#define AOFF_task_nswap	0x000001e0
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x000001e8
+#define AOFF_task_cmin_flt	0x000001e4
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x000001ec
+#define AOFF_task_cmaj_flt	0x000001e8
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x000001f0
+#define AOFF_task_cnswap	0x000001ec
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_swap_address	0x000001f8
+#define AOFF_task_swap_address	0x000001f4
 #define ASIZ_task_swap_address	0x00000004
-#define AOFF_task_old_maj_flt	0x000001fc
+#define AOFF_task_old_maj_flt	0x000001f8
 #define ASIZ_task_old_maj_flt	0x00000004
-#define AOFF_task_dec_flt	0x00000200
+#define AOFF_task_dec_flt	0x000001fc
 #define ASIZ_task_dec_flt	0x00000004
-#define AOFF_task_swap_cnt	0x00000204
+#define AOFF_task_swap_cnt	0x00000200
 #define ASIZ_task_swap_cnt	0x00000004
-#define AOFF_task_uid	0x00000208
+#define AOFF_task_uid	0x00000204
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x0000020a
+#define AOFF_task_euid	0x00000206
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x0000020c
+#define AOFF_task_suid	0x00000208
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x0000020e
+#define AOFF_task_fsuid	0x0000020a
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x00000210
+#define AOFF_task_gid	0x0000020c
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x00000212
+#define AOFF_task_egid	0x0000020e
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x00000214
+#define AOFF_task_sgid	0x00000210
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x00000216
+#define AOFF_task_fsgid	0x00000212
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_ngroups	0x00000218
+#define AOFF_task_ngroups	0x00000214
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x0000021c
+#define AOFF_task_groups	0x00000218
 #define ASIZ_task_groups	0x00000040
-#define AOFF_task_cap_effective	0x0000025c
+#define AOFF_task_cap_effective	0x00000258
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000260
+#define AOFF_task_cap_inheritable	0x0000025c
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000264
+#define AOFF_task_cap_permitted	0x00000260
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000268
+#define AOFF_task_user	0x00000264
 #define ASIZ_task_user	0x00000004
-#define AOFF_task_rlim	0x0000026c
+#define AOFF_task_rlim	0x00000268
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000002bc
+#define AOFF_task_used_math	0x000002b8
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000002be
+#define AOFF_task_comm	0x000002ba
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000002d0
+#define AOFF_task_link_count	0x000002cc
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000002d4
+#define AOFF_task_tty	0x000002d0
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000002d8
+#define AOFF_task_semundo	0x000002d4
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000002dc
+#define AOFF_task_semsleeping	0x000002d8
 #define ASIZ_task_semsleeping	0x00000004
 #define AOFF_task_tss	0x000002e0
 #define ASIZ_task_tss	0x00000388
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h
--- v2.1.128/linux/include/asm-sparc/audioio.h	Thu Aug  6 14:06:34 1998
+++ linux/include/asm-sparc/audioio.h	Wed Nov 18 09:06:05 1998
@@ -88,6 +88,7 @@
 #define	AUDIO_ENCODING_ULAW	(1)	/* u-law encoding	  */
 #define	AUDIO_ENCODING_ALAW	(2)	/* A-law encoding	  */
 #define	AUDIO_ENCODING_LINEAR	(3)	/* Linear PCM encoding	  */
+#define AUDIO_ENCODING_FLOAT    (4)     /* IEEE float (-1. <-> +1.) */
 #define	AUDIO_ENCODING_DVI	(104)	/* DVI ADPCM		  */
 #define	AUDIO_ENCODING_LINEAR8	(105)	/* 8 bit UNSIGNED	  */
 #define	AUDIO_ENCODING_LINEARLE	(106)	/* Linear PCM LE encoding */
@@ -139,8 +140,7 @@
 #define	AUDIO_LINE_IN		0x02	/* input from line in	 */
 #define	AUDIO_CD		0x04	/* input from on-board CD inputs */
 #define	AUDIO_INTERNAL_CD_IN	AUDIO_CD	/* input from internal CDROM */
-/* Supposedly an undocumented feature of the 4231 */
-#define AUDIO_ANALOG_LOOPBACK   0x40
+#define AUDIO_ANALOG_LOOPBACK   0x40    /* input from output */
 
 
 /*
@@ -227,22 +227,10 @@
  * if the hardware supports this.  The argument is TRUE to set loopback,
  * FALSE to reset to normal operation.  If the hardware does not support
  * internal loopback, the ioctl should fail with EINVAL.
+ * Causes ADC data to be digitally mixed in and sent to the DAC.
  */
 #define	AUDIO_DIAG_LOOPBACK	_IOW('A', 101, int)
 
-#ifdef notneeded
-/*
- * Structure sent up as a M_PROTO message on trace streams
- */
-typedef struct audtrace_hdr audtrace_hdr_t;
-struct audtrace_hdr {
-	unsigned int seq;		/* Sequence number (per-aud_stream) */
-	int type;		/* device-dependent */
-	struct timeval timestamp;
-	char _f[8];		/* filler */
-};
-#endif
-
 /*
  *	Linux kernel internal implementation.
  */
@@ -257,48 +245,72 @@
 #define	SDF_OPEN_WRITE	0x00000001
 #define	SDF_OPEN_READ	0x00000002
 
+struct sparcaudio_ringbuffer
+{
+  __u8 *rb_start, *rb_end;		/* start, end of this memory buffer */
+  __u8 *rb_in, *rb_out;			/* input, output pointers */
+
+  int rb_fragsize;			/* size of an audio frag */
+  int rb_numfrags;			/* number of frags */
+
+  int rb_count, rb_hiwat, rb_lowat;	/* bytes in use, hi/lo wat points */
+
+  int rb_bufsize;			/* total size of buffer */
+};
+
 struct sparcaudio_driver
 {
 	const char * name;
 	struct sparcaudio_operations *ops;
 	void *private;
 	unsigned long flags;
+        struct strevent *sd_siglist;
+        /* duplex: 0=simplex, 1=duplex, 2=loop */
+        int sd_sigflags, duplex;
+
+        /* Which audio device are we? */
+        int index; 
 
         /* This device */
         struct linux_sbus_device *dev;
- 
+
 	/* Processes blocked on open() sit here. */
 	struct wait_queue *open_wait;
 
 	/* Task queue for this driver's bottom half. */
 	struct tq_struct tqueue;
 
+        /* Start of ring buffer support */
+        __u8 *input_buffer, *output_buffer;
+
 	/* Support for a circular queue of output buffers. */
 	__u8 **output_buffers;
-	size_t *output_sizes, output_size;
-	int num_output_buffers, output_front, output_rear;
-	int output_count, output_active, playing_count;
+	size_t *output_sizes, output_size, output_buffer_size;
+	int num_output_buffers, output_front, output_rear, output_offset;
+	int output_count, output_active, playing_count, output_eof;
 	struct wait_queue *output_write_wait, *output_drain_wait;
+        char *output_notify;
 
         /* Support for a circular queue of input buffers. */
         __u8 **input_buffers;
-        int input_offset;
-        int num_input_buffers, input_front, input_rear;
+	size_t *input_sizes, input_size, input_buffer_size;
+        int num_input_buffers, input_front, input_rear, input_offset;
         int input_count, input_active, recording_count;
         struct wait_queue *input_read_wait;
+
+        /* Hack to make it look like we support variable size buffers. */
+        int buffer_size;
 };
 
 struct sparcaudio_operations
 {
 	int (*open)(struct inode *, struct file *, struct sparcaudio_driver *);
-	void (*release)(struct inode *, struct file *, struct 
-			sparcaudio_driver *);
-	int (*ioctl)(struct inode *, struct file *, unsigned int, 
-		     unsigned long, struct sparcaudio_driver *);
+	void (*release)(struct inode *, struct file *, struct sparcaudio_driver *);
+	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long,
+		     struct sparcaudio_driver *);
 
 	/* Ask driver to begin playing a buffer. */
-	void (*start_output)(struct sparcaudio_driver *, __u8 *, 
-			     unsigned long);
+	void (*start_output)(struct sparcaudio_driver *, __u8 *, unsigned long);
 
 	/* Ask driver to stop playing a buffer. */
 	void (*stop_output)(struct sparcaudio_driver *);
@@ -382,35 +394,125 @@
         /* Get and set output mute */
         int (*set_output_muted)(struct sparcaudio_driver *, int);
         int (*get_output_muted)(struct sparcaudio_driver *);
+
+        /* Get and set output pause */
+        int (*set_output_pause)(struct sparcaudio_driver *, int);
+        int (*get_output_pause)(struct sparcaudio_driver *);
+
+        /* Get and set input pause */
+        int (*set_input_pause)(struct sparcaudio_driver *, int);
+        int (*get_input_pause)(struct sparcaudio_driver *);
+
+        /* Get and set output samples */
+        int (*set_output_samples)(struct sparcaudio_driver *, int);
+        int (*get_output_samples)(struct sparcaudio_driver *);
+
+        /* Get and set input samples */
+        int (*set_input_samples)(struct sparcaudio_driver *, int);
+        int (*get_input_samples)(struct sparcaudio_driver *);
+
+        /* Get and set output error */
+        int (*set_output_error)(struct sparcaudio_driver *, int);
+        int (*get_output_error)(struct sparcaudio_driver *);
+
+        /* Get and set input error */
+        int (*set_input_error)(struct sparcaudio_driver *, int);
+        int (*get_input_error)(struct sparcaudio_driver *);
+
+        /* Get supported encodings */
+        int (*get_formats)(struct sparcaudio_driver *);
 };
 
-extern int register_sparcaudio_driver(struct sparcaudio_driver *);
-extern int unregister_sparcaudio_driver(struct sparcaudio_driver *);
+extern int register_sparcaudio_driver(struct sparcaudio_driver *, int);
+extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
 extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
-extern void sparcaudio_input_done(struct sparcaudio_driver *);
+extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
 extern int sparcaudio_init(void);
 extern int amd7930_init(void);
 extern int cs4231_init(void);
 
 #endif
 
+/* Mixer helper ioctls */
+#define right(a) (((a >> 8) & 0xff) % 101)
+#define left(a) ((a & 0xff) % 101)
+
 /* Macros to convert between mixer stereo volumes and gain (mono) */
-#define s_to_m(a) (((((a) >> 8) & 0x7f) + ((a) & 0x7f)) / 2)
-#define m_to_s(a) (((a) << 8) + (a))
+#define s_to_m(a) ((((left(a) + right(a)) * 255) / 200) % 256)
+#define m_to_s(a) ((a * 100 / 255) + ((a * 100 / 255) << 8))
 
 /* convert mixer stereo volume to balance */
-#define s_to_b(a) (AUDIO_RIGHT_BALANCE * ((((a) >> 8) & 0xff) /  (((((a) >> 8) & 0xff) + ((a) & 0xff)) / 2)))
+#define s_to_b(a) (s_to_g(a) == 0) ? 32 : ((left(a) * AUDIO_RIGHT_BALANCE / (left(a) + right(a))))
 
 /* convert mixer stereo volume to audio gain */
-#define s_to_g(a) (((((a) >> 8) & 0xff) + ((a) & 0xff)) / 2)
+#define s_to_g(a) ((((right(a) + left(a)) * 255) / 200) % 256)
 
 /* convert gain a and balance b to mixer volume */
-#define b_to_s(a,b) ((a * (b / AUDIO_RIGHT_BALANCE) << 8) + (a * (1 - (b / AUDIO_RIGHT_BALANCE))))
+#define b_to_s(a,b) (((((b * a * 200) / (AUDIO_RIGHT_BALANCE * 255)) % 100) << 8) + ((((AUDIO_RIGHT_BALANCE - b) * a * 200) / (AUDIO_RIGHT_BALANCE * 255)) % 100))
+
+/* Device minor numbers */
 
 #define SPARCAUDIO_MIXER_MINOR 0
-#define SPARCAUDIO_DSP16_MINOR 1
+/* No sequencer (1) */
+/* No midi (2) */
 #define SPARCAUDIO_DSP_MINOR   3
 #define SPARCAUDIO_AUDIO_MINOR 4
-#define SPARCAUDIO_AUDIOCTL_MINOR 5
+#define SPARCAUDIO_DSP16_MINOR 5
 #define SPARCAUDIO_STATUS_MINOR 6
+#define SPARCAUDIO_AUDIOCTL_MINOR 7
+/* No sequencer l2 (8) */
+/* No sound processor (9) */
+
+/* allocate 2^SPARCAUDIO_DEVICE_SHIFT minors per audio device */
+#define SPARCAUDIO_DEVICE_SHIFT 4
+
+/* With the coming of dummy devices this should perhaps be as high as 5? */
+#define SPARCAUDIO_MAX_DEVICES 3
+
+/* Streams crap for realaudio */
+
+typedef
+struct strevent {
+    struct strevent *se_next;   /* next event for this stream or NULL*/
+    struct strevent *se_prev;   /* previous event for this stream or last
+                                 * event if this is the first one*/
+    pid_t se_pid;               /* process to be signaled */
+    short se_evs;               /* events wanted */
+} strevent_t;
+
+typedef
+struct stdata
+{
+        struct stdata    *sd_next ;     /* all stdatas are linked together */
+        struct stdata    *sd_prev ;
+        struct strevent   *sd_siglist;  /* processes to be sent SIGPOLL */
+        int  sd_sigflags;               /* logical OR of all siglist events */
+} stdata_t;
+
+#define I_NREAD _IOR('S',01, int)
+#define I_NREAD_SOLARIS (('S'<<8)|1)
+
+#define I_FLUSH _IO('S',05)
+#define I_FLUSH_SOLARIS (('S'<<8)|5)
+#define FLUSHR  1                       /* flush read queue */
+#define FLUSHW  2                       /* flush write queue */
+#define FLUSHRW 3                       /* flush both queues */
+
+#define I_SETSIG _IO('S',011)
+#define I_SETSIG_SOLARIS (('S'<<8)|11)
+#define S_INPUT         0x01
+#define S_HIPRI         0x02           
+#define S_OUTPUT        0x04           
+#define S_MSG           0x08           
+#define S_ERROR         0x0010         
+#define S_HANGUP        0x0020         
+#define S_RDNORM        0x0040         
+#define S_WRNORM        S_OUTPUT
+#define S_RDBAND        0x0080         
+#define S_WRBAND        0x0100         
+#define S_BANDURG       0x0200         
+#define S_ALL           0x03FF
+
+#define I_GETSIG _IOR('S',012,int)
+#define I_GETSIG_SOLARIS (('S'<<8)|12)
 #endif
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/io-unit.h linux/include/asm-sparc/io-unit.h
--- v2.1.128/linux/include/asm-sparc/io-unit.h	Thu Apr 23 20:21:38 1998
+++ linux/include/asm-sparc/io-unit.h	Mon Nov 16 10:37:28 1998
@@ -7,6 +7,7 @@
 
 #include <asm/page.h>
 #include <asm/spinlock.h>
+#include <asm/pgtable.h>
 
 /* The io-unit handles all virtual to physical address translations
  * that occur between the SBUS and physical memory.  Access by
@@ -49,5 +50,9 @@
 #define IOUNIT_BMAP2_END	IOUNIT_BMAP2_START + (IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 2))
 #define IOUNIT_BMAPM_START	IOUNIT_BMAP2_END
 #define IOUNIT_BMAPM_END	((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
+
+extern __u32 iounit_map_dma_init(struct linux_sbus *, int);
+#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
+extern __u32 iounit_map_dma_page(__u32, void *, struct linux_sbus *);
 
 #endif /* !(_SPARC_IO_UNIT_H) */
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h
--- v2.1.128/linux/include/asm-sparc/namei.h	Thu Apr 23 20:21:38 1998
+++ linux/include/asm-sparc/namei.h	Mon Nov 16 10:38:09 1998
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.11 1998/01/15 12:58:24 jj Exp $
+/* $Id: namei.h,v 1.12 1998/10/28 08:13:42 jj Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -12,7 +12,7 @@
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
 static inline struct dentry *
-__sparc_lookup_dentry(const char *name, int follow_link)
+__sparc_lookup_dentry(const char *name, int lookup_flags)
 {
 	struct dentry *base;
 	char *emul;
@@ -29,18 +29,20 @@
 		return NULL;
 	}
 
-	base = lookup_dentry (emul, dget (current->fs->root), 1);
+	base = lookup_dentry (emul, 
+			      dget (current->fs->root),
+			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
 			
 	if (IS_ERR (base)) return NULL;
 	
-	base = lookup_dentry (name, base, follow_link);
+	base = lookup_dentry (name, base, lookup_flags);
 	
 	if (IS_ERR (base)) return NULL;
 	
 	if (!base->d_inode) {
 		struct dentry *fromroot;
 		
-		fromroot = lookup_dentry (name, dget (current->fs->root), follow_link);
+		fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
 		
 		if (IS_ERR (fromroot)) return base;
 		
@@ -55,9 +57,9 @@
 	return base;
 }
 
-#define __prefix_lookup_dentry(name, follow_link)				\
+#define __prefix_lookup_dentry(name, lookup_flags)				\
 	if (current->personality) {						\
-		dentry = __sparc_lookup_dentry (name, follow_link);		\
+		dentry = __sparc_lookup_dentry (name, lookup_flags);		\
 		if (dentry) return dentry;					\
 	}
 
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.1.128/linux/include/asm-sparc/smp.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-sparc/smp.h	Mon Nov 16 10:37:28 1998
@@ -150,11 +150,12 @@
 #else
 extern __inline__ int hard_smp_processor_id(void)
 {
-	int cpuid __asm__ ("g2");
+	int cpuid;
 	
 	__asm__ __volatile__("mov %%o7, %%g1\n\t"
 			     "call ___f___smp_processor_id\n\t"
-			     " nop\n\t" : "=r"(cpuid) : : "g1");
+			     " nop\n\t"
+			     "mov %%g2, %0\n\t" : "=r"(cpuid) : : "g1", "g2");
 	return cpuid;
 }
 #endif
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.1.128/linux/include/asm-sparc/spinlock.h	Sun Nov  8 14:03:09 1998
+++ linux/include/asm-sparc/spinlock.h	Mon Nov 16 10:37:28 1998
@@ -34,8 +34,8 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef struct { volatile unsigned int lock; } rwlock_t;
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
@@ -65,7 +65,7 @@
 };
 typedef struct _spinlock_debug spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED	{ 0, 0 }
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0, 0 }
 #define spin_lock_init(lp)	do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0)
 #define spin_unlock_wait(lp)	do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock))
 
@@ -90,7 +90,7 @@
 };
 typedef struct _rwlock_debug rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0, {0} }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} }
 
 extern void _do_read_lock(rwlock_t *rw, char *str);
 extern void _do_read_unlock(rwlock_t *rw, char *str);
@@ -260,7 +260,7 @@
  */
 typedef struct { volatile unsigned int lock; } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 /* Sort of like atomic_t's on Sparc, but even more clever.
  *
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.1.128/linux/include/asm-sparc64/asm_offsets.h	Sun Nov  8 14:03:10 1998
+++ linux/include/asm-sparc64/asm_offsets.h	Mon Nov 16 10:37:28 1998
@@ -74,119 +74,117 @@
 #define ASIZ_task_tarray_ptr	0x00000008
 #define AOFF_task_wait_chldexit	0x000000e8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_timeout	0x000000f0
-#define ASIZ_task_timeout	0x00000008
-#define AOFF_task_policy	0x000000f8
+#define AOFF_task_policy	0x000000f0
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000100
+#define AOFF_task_rt_priority	0x000000f8
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000108
+#define AOFF_task_it_real_value	0x00000100
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000110
+#define AOFF_task_it_prof_value	0x00000108
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000118
+#define AOFF_task_it_virt_value	0x00000110
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000120
+#define AOFF_task_it_real_incr	0x00000118
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000128
+#define AOFF_task_it_prof_incr	0x00000120
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000130
+#define AOFF_task_it_virt_incr	0x00000128
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000138
+#define AOFF_task_real_timer	0x00000130
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000160
+#define AOFF_task_times	0x00000158
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000180
+#define AOFF_task_start_time	0x00000178
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000188
+#define AOFF_task_per_cpu_utime	0x00000180
 #define ASIZ_task_per_cpu_utime	0x00000008
-#define AOFF_task_min_flt	0x00000198
+#define AOFF_task_min_flt	0x00000190
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000001a0
+#define AOFF_task_maj_flt	0x00000198
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000001a8
+#define AOFF_task_nswap	0x000001a0
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000001b0
+#define AOFF_task_cmin_flt	0x000001a8
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000001b8
+#define AOFF_task_cmaj_flt	0x000001b0
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000001c0
+#define AOFF_task_cnswap	0x000001b8
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_swap_address	0x000001d0
+#define AOFF_task_swap_address	0x000001c8
 #define ASIZ_task_swap_address	0x00000008
-#define AOFF_task_old_maj_flt	0x000001d8
+#define AOFF_task_old_maj_flt	0x000001d0
 #define ASIZ_task_old_maj_flt	0x00000008
-#define AOFF_task_dec_flt	0x000001e0
+#define AOFF_task_dec_flt	0x000001d8
 #define ASIZ_task_dec_flt	0x00000008
-#define AOFF_task_swap_cnt	0x000001e8
+#define AOFF_task_swap_cnt	0x000001e0
 #define ASIZ_task_swap_cnt	0x00000008
-#define AOFF_task_uid	0x000001f0
+#define AOFF_task_uid	0x000001e8
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000001f4
+#define AOFF_task_euid	0x000001ec
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000001f8
+#define AOFF_task_suid	0x000001f0
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000001fc
+#define AOFF_task_fsuid	0x000001f4
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x00000200
+#define AOFF_task_gid	0x000001f8
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x00000204
+#define AOFF_task_egid	0x000001fc
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x00000208
+#define AOFF_task_sgid	0x00000200
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x0000020c
+#define AOFF_task_fsgid	0x00000204
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x00000210
+#define AOFF_task_ngroups	0x00000208
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000214
+#define AOFF_task_groups	0x0000020c
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000294
+#define AOFF_task_cap_effective	0x0000028c
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000298
+#define AOFF_task_cap_inheritable	0x00000290
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x0000029c
+#define AOFF_task_cap_permitted	0x00000294
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x000002a0
+#define AOFF_task_user	0x00000298
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x000002a8
+#define AOFF_task_rlim	0x000002a0
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000348
+#define AOFF_task_used_math	0x00000340
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000034a
+#define AOFF_task_comm	0x00000342
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000035c
+#define AOFF_task_link_count	0x00000354
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000360
+#define AOFF_task_tty	0x00000358
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000368
+#define AOFF_task_semundo	0x00000360
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000370
+#define AOFF_task_semsleeping	0x00000368
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000380
+#define AOFF_task_tss	0x00000370
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000007f0
+#define AOFF_task_fs	0x000007e0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000007f8
+#define AOFF_task_files	0x000007e8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x00000800
+#define AOFF_task_mm	0x000007f0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x00000808
+#define AOFF_task_sigmask_lock	0x000007f8
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000810
+#define AOFF_task_sig	0x00000800
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x00000818
+#define AOFF_task_signal	0x00000808
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000820
+#define AOFF_task_blocked	0x00000810
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000828
+#define AOFF_task_sigqueue	0x00000818
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000830
+#define AOFF_task_sigqueue_tail	0x00000820
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000838
+#define AOFF_task_sas_ss_sp	0x00000828
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000840
+#define AOFF_task_sas_ss_size	0x00000830
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000850
+#define ASIZ_task	0x00000840
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_cache	0x00000008
@@ -360,119 +358,117 @@
 #define ASIZ_task_tarray_ptr	0x00000008
 #define AOFF_task_wait_chldexit	0x000000e8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_timeout	0x000000f0
-#define ASIZ_task_timeout	0x00000008
-#define AOFF_task_policy	0x000000f8
+#define AOFF_task_policy	0x000000f0
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000100
+#define AOFF_task_rt_priority	0x000000f8
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000108
+#define AOFF_task_it_real_value	0x00000100
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000110
+#define AOFF_task_it_prof_value	0x00000108
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000118
+#define AOFF_task_it_virt_value	0x00000110
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000120
+#define AOFF_task_it_real_incr	0x00000118
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000128
+#define AOFF_task_it_prof_incr	0x00000120
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000130
+#define AOFF_task_it_virt_incr	0x00000128
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000138
+#define AOFF_task_real_timer	0x00000130
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000160
+#define AOFF_task_times	0x00000158
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000180
+#define AOFF_task_start_time	0x00000178
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000188
+#define AOFF_task_per_cpu_utime	0x00000180
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x00000388
+#define AOFF_task_min_flt	0x00000380
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000390
+#define AOFF_task_maj_flt	0x00000388
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x00000398
+#define AOFF_task_nswap	0x00000390
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003a0
+#define AOFF_task_cmin_flt	0x00000398
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003a8
+#define AOFF_task_cmaj_flt	0x000003a0
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003b0
+#define AOFF_task_cnswap	0x000003a8
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_swap_address	0x000003c0
+#define AOFF_task_swap_address	0x000003b8
 #define ASIZ_task_swap_address	0x00000008
-#define AOFF_task_old_maj_flt	0x000003c8
+#define AOFF_task_old_maj_flt	0x000003c0
 #define ASIZ_task_old_maj_flt	0x00000008
-#define AOFF_task_dec_flt	0x000003d0
+#define AOFF_task_dec_flt	0x000003c8
 #define ASIZ_task_dec_flt	0x00000008
-#define AOFF_task_swap_cnt	0x000003d8
+#define AOFF_task_swap_cnt	0x000003d0
 #define ASIZ_task_swap_cnt	0x00000008
-#define AOFF_task_uid	0x000003e0
+#define AOFF_task_uid	0x000003d8
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003e4
+#define AOFF_task_euid	0x000003dc
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003e8
+#define AOFF_task_suid	0x000003e0
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003ec
+#define AOFF_task_fsuid	0x000003e4
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003f0
+#define AOFF_task_gid	0x000003e8
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003f4
+#define AOFF_task_egid	0x000003ec
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003f8
+#define AOFF_task_sgid	0x000003f0
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000003fc
+#define AOFF_task_fsgid	0x000003f4
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x00000400
+#define AOFF_task_ngroups	0x000003f8
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000404
+#define AOFF_task_groups	0x000003fc
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000484
+#define AOFF_task_cap_effective	0x0000047c
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000488
+#define AOFF_task_cap_inheritable	0x00000480
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x0000048c
+#define AOFF_task_cap_permitted	0x00000484
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000490
+#define AOFF_task_user	0x00000488
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000498
+#define AOFF_task_rlim	0x00000490
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000538
+#define AOFF_task_used_math	0x00000530
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000053a
+#define AOFF_task_comm	0x00000532
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000054c
+#define AOFF_task_link_count	0x00000544
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000550
+#define AOFF_task_tty	0x00000548
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000558
+#define AOFF_task_semundo	0x00000550
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000560
+#define AOFF_task_semsleeping	0x00000558
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000570
+#define AOFF_task_tss	0x00000560
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000009e0
+#define AOFF_task_fs	0x000009d0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009e8
+#define AOFF_task_files	0x000009d8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009f0
+#define AOFF_task_mm	0x000009e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009f8
+#define AOFF_task_sigmask_lock	0x000009e8
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000a00
+#define AOFF_task_sig	0x000009f0
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x00000a08
+#define AOFF_task_signal	0x000009f8
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000a10
+#define AOFF_task_blocked	0x00000a00
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000a18
+#define AOFF_task_sigqueue	0x00000a08
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a20
+#define AOFF_task_sigqueue_tail	0x00000a10
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a28
+#define AOFF_task_sas_ss_sp	0x00000a18
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a30
+#define AOFF_task_sas_ss_size	0x00000a20
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a40
+#define ASIZ_task	0x00000a30
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_cache	0x00000008
@@ -644,119 +640,117 @@
 #define ASIZ_task_tarray_ptr	0x00000008
 #define AOFF_task_wait_chldexit	0x000000e8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_timeout	0x000000f0
-#define ASIZ_task_timeout	0x00000008
-#define AOFF_task_policy	0x000000f8
+#define AOFF_task_policy	0x000000f0
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000100
+#define AOFF_task_rt_priority	0x000000f8
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000108
+#define AOFF_task_it_real_value	0x00000100
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000110
+#define AOFF_task_it_prof_value	0x00000108
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000118
+#define AOFF_task_it_virt_value	0x00000110
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000120
+#define AOFF_task_it_real_incr	0x00000118
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000128
+#define AOFF_task_it_prof_incr	0x00000120
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000130
+#define AOFF_task_it_virt_incr	0x00000128
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000138
+#define AOFF_task_real_timer	0x00000130
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000160
+#define AOFF_task_times	0x00000158
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000180
+#define AOFF_task_start_time	0x00000178
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000188
+#define AOFF_task_per_cpu_utime	0x00000180
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x00000388
+#define AOFF_task_min_flt	0x00000380
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000390
+#define AOFF_task_maj_flt	0x00000388
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x00000398
+#define AOFF_task_nswap	0x00000390
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003a0
+#define AOFF_task_cmin_flt	0x00000398
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003a8
+#define AOFF_task_cmaj_flt	0x000003a0
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003b0
+#define AOFF_task_cnswap	0x000003a8
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_swap_address	0x000003c0
+#define AOFF_task_swap_address	0x000003b8
 #define ASIZ_task_swap_address	0x00000008
-#define AOFF_task_old_maj_flt	0x000003c8
+#define AOFF_task_old_maj_flt	0x000003c0
 #define ASIZ_task_old_maj_flt	0x00000008
-#define AOFF_task_dec_flt	0x000003d0
+#define AOFF_task_dec_flt	0x000003c8
 #define ASIZ_task_dec_flt	0x00000008
-#define AOFF_task_swap_cnt	0x000003d8
+#define AOFF_task_swap_cnt	0x000003d0
 #define ASIZ_task_swap_cnt	0x00000008
-#define AOFF_task_uid	0x000003e0
+#define AOFF_task_uid	0x000003d8
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003e4
+#define AOFF_task_euid	0x000003dc
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003e8
+#define AOFF_task_suid	0x000003e0
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003ec
+#define AOFF_task_fsuid	0x000003e4
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003f0
+#define AOFF_task_gid	0x000003e8
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003f4
+#define AOFF_task_egid	0x000003ec
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003f8
+#define AOFF_task_sgid	0x000003f0
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000003fc
+#define AOFF_task_fsgid	0x000003f4
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x00000400
+#define AOFF_task_ngroups	0x000003f8
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000404
+#define AOFF_task_groups	0x000003fc
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000484
+#define AOFF_task_cap_effective	0x0000047c
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000488
+#define AOFF_task_cap_inheritable	0x00000480
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x0000048c
+#define AOFF_task_cap_permitted	0x00000484
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000490
+#define AOFF_task_user	0x00000488
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000498
+#define AOFF_task_rlim	0x00000490
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000538
+#define AOFF_task_used_math	0x00000530
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000053a
+#define AOFF_task_comm	0x00000532
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000054c
+#define AOFF_task_link_count	0x00000544
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000550
+#define AOFF_task_tty	0x00000548
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000558
+#define AOFF_task_semundo	0x00000550
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000560
+#define AOFF_task_semsleeping	0x00000558
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000570
+#define AOFF_task_tss	0x00000560
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000009e0
+#define AOFF_task_fs	0x000009d0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009e8
+#define AOFF_task_files	0x000009d8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009f0
+#define AOFF_task_mm	0x000009e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009f8
+#define AOFF_task_sigmask_lock	0x000009e8
 #define ASIZ_task_sigmask_lock	0x0000000c
-#define AOFF_task_sig	0x00000a08
+#define AOFF_task_sig	0x000009f8
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x00000a10
+#define AOFF_task_signal	0x00000a00
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000a18
+#define AOFF_task_blocked	0x00000a08
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000a20
+#define AOFF_task_sigqueue	0x00000a10
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a28
+#define AOFF_task_sigqueue_tail	0x00000a18
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a30
+#define AOFF_task_sas_ss_sp	0x00000a20
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a38
+#define AOFF_task_sas_ss_size	0x00000a28
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a40
+#define ASIZ_task	0x00000a30
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_cache	0x00000008
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/audioio.h linux/include/asm-sparc64/audioio.h
--- v2.1.128/linux/include/asm-sparc64/audioio.h	Thu Aug  6 14:06:34 1998
+++ linux/include/asm-sparc64/audioio.h	Wed Nov 18 09:06:05 1998
@@ -88,6 +88,7 @@
 #define	AUDIO_ENCODING_ULAW	(1)	/* u-law encoding	  */
 #define	AUDIO_ENCODING_ALAW	(2)	/* A-law encoding	  */
 #define	AUDIO_ENCODING_LINEAR	(3)	/* Linear PCM encoding	  */
+#define AUDIO_ENCODING_FLOAT    (4)     /* IEEE float (-1. <-> +1.) */
 #define	AUDIO_ENCODING_DVI	(104)	/* DVI ADPCM		  */
 #define	AUDIO_ENCODING_LINEAR8	(105)	/* 8 bit UNSIGNED	  */
 #define	AUDIO_ENCODING_LINEARLE	(106)	/* Linear PCM LE encoding */
@@ -139,8 +140,7 @@
 #define	AUDIO_LINE_IN		0x02	/* input from line in	 */
 #define	AUDIO_CD		0x04	/* input from on-board CD inputs */
 #define	AUDIO_INTERNAL_CD_IN	AUDIO_CD	/* input from internal CDROM */
-/* Supposedly an undocumented feature of the 4231 */
-#define AUDIO_ANALOG_LOOPBACK   0x40
+#define AUDIO_ANALOG_LOOPBACK   0x40    /* input from output */
 
 
 /*
@@ -227,22 +227,10 @@
  * if the hardware supports this.  The argument is TRUE to set loopback,
  * FALSE to reset to normal operation.  If the hardware does not support
  * internal loopback, the ioctl should fail with EINVAL.
+ * Causes ADC data to be digitally mixed in and sent to the DAC.
  */
 #define	AUDIO_DIAG_LOOPBACK	_IOW('A', 101, int)
 
-#ifdef notneeded
-/*
- * Structure sent up as a M_PROTO message on trace streams
- */
-typedef struct audtrace_hdr audtrace_hdr_t;
-struct audtrace_hdr {
-	unsigned int seq;		/* Sequence number (per-aud_stream) */
-	int type;		/* device-dependent */
-	struct timeval timestamp;
-	char _f[8];		/* filler */
-};
-#endif
-
 /*
  *	Linux kernel internal implementation.
  */
@@ -257,15 +245,34 @@
 #define	SDF_OPEN_WRITE	0x00000001
 #define	SDF_OPEN_READ	0x00000002
 
+struct sparcaudio_ringbuffer
+{
+  __u8 *rb_start, *rb_end;		/* start, end of this memory buffer */
+  __u8 *rb_in, *rb_out;			/* input, output pointers */
+
+  int rb_fragsize;			/* size of an audio frag */
+  int rb_numfrags;			/* number of frags */
+
+  int rb_count, rb_hiwat, rb_lowat;	/* bytes in use, hi/lo wat points */
+
+  int rb_bufsize;			/* total size of buffer */
+};
+
 struct sparcaudio_driver
 {
 	const char * name;
 	struct sparcaudio_operations *ops;
 	void *private;
 	unsigned long flags;
+        struct strevent *sd_siglist;
+        /* duplex: 0=simplex, 1=duplex, 2=loop */
+        int sd_sigflags, duplex;
 
-	/* This device */
-	struct linux_sbus_device *dev;
+        /* Which audio device are we? */
+        int index; 
+
+        /* This device */
+        struct linux_sbus_device *dev;
 
 	/* Processes blocked on open() sit here. */
 	struct wait_queue *open_wait;
@@ -273,32 +280,37 @@
 	/* Task queue for this driver's bottom half. */
 	struct tq_struct tqueue;
 
+        /* Start of ring buffer support */
+        __u8 *input_buffer, *output_buffer;
+
 	/* Support for a circular queue of output buffers. */
 	__u8 **output_buffers;
-	size_t *output_sizes, output_size;
-	int num_output_buffers, output_front, output_rear;
-	int output_count, output_active, playing_count;
+	size_t *output_sizes, output_size, output_buffer_size;
+	int num_output_buffers, output_front, output_rear, output_offset;
+	int output_count, output_active, playing_count, output_eof;
 	struct wait_queue *output_write_wait, *output_drain_wait;
+        char *output_notify;
 
         /* Support for a circular queue of input buffers. */
         __u8 **input_buffers;
-        int input_offset;
-        int num_input_buffers, input_front, input_rear;
+	size_t *input_sizes, input_size, input_buffer_size;
+        int num_input_buffers, input_front, input_rear, input_offset;
         int input_count, input_active, recording_count;
         struct wait_queue *input_read_wait;
+
+        /* Hack to make it look like we support variable size buffers. */
+        int buffer_size;
 };
 
 struct sparcaudio_operations
 {
 	int (*open)(struct inode *, struct file *, struct sparcaudio_driver *);
-	void (*release)(struct inode *, struct file *, 
-			struct sparcaudio_driver *);
-	int (*ioctl)(struct inode *, struct file *, unsigned int, 
-		     unsigned long, struct sparcaudio_driver *);
+	void (*release)(struct inode *, struct file *, struct sparcaudio_driver *);
+	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long,
+		     struct sparcaudio_driver *);
 
 	/* Ask driver to begin playing a buffer. */
-	void (*start_output)(struct sparcaudio_driver *, __u8 *, 
-			     unsigned long);
+	void (*start_output)(struct sparcaudio_driver *, __u8 *, unsigned long);
 
 	/* Ask driver to stop playing a buffer. */
 	void (*stop_output)(struct sparcaudio_driver *);
@@ -382,35 +394,125 @@
         /* Get and set output mute */
         int (*set_output_muted)(struct sparcaudio_driver *, int);
         int (*get_output_muted)(struct sparcaudio_driver *);
+
+        /* Get and set output pause */
+        int (*set_output_pause)(struct sparcaudio_driver *, int);
+        int (*get_output_pause)(struct sparcaudio_driver *);
+
+        /* Get and set input pause */
+        int (*set_input_pause)(struct sparcaudio_driver *, int);
+        int (*get_input_pause)(struct sparcaudio_driver *);
+
+        /* Get and set output samples */
+        int (*set_output_samples)(struct sparcaudio_driver *, int);
+        int (*get_output_samples)(struct sparcaudio_driver *);
+
+        /* Get and set input samples */
+        int (*set_input_samples)(struct sparcaudio_driver *, int);
+        int (*get_input_samples)(struct sparcaudio_driver *);
+
+        /* Get and set output error */
+        int (*set_output_error)(struct sparcaudio_driver *, int);
+        int (*get_output_error)(struct sparcaudio_driver *);
+
+        /* Get and set input error */
+        int (*set_input_error)(struct sparcaudio_driver *, int);
+        int (*get_input_error)(struct sparcaudio_driver *);
+
+        /* Get supported encodings */
+        int (*get_formats)(struct sparcaudio_driver *);
 };
 
-extern int register_sparcaudio_driver(struct sparcaudio_driver *);
-extern int unregister_sparcaudio_driver(struct sparcaudio_driver *);
+extern int register_sparcaudio_driver(struct sparcaudio_driver *, int);
+extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
 extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
-extern void sparcaudio_input_done(struct sparcaudio_driver *);
+extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
 extern int sparcaudio_init(void);
 extern int amd7930_init(void);
 extern int cs4231_init(void);
 
 #endif
 
+/* Mixer helper ioctls */
+#define right(a) (((a >> 8) & 0xff) % 101)
+#define left(a) ((a & 0xff) % 101)
+
 /* Macros to convert between mixer stereo volumes and gain (mono) */
-#define s_to_m(a) (((((a) >> 8) & 0x7f) + ((a) & 0x7f)) / 2)
-#define m_to_s(a) (((a) << 8) + (a))
+#define s_to_m(a) ((((left(a) + right(a)) * 255) / 200) % 256)
+#define m_to_s(a) ((a * 100 / 255) + ((a * 100 / 255) << 8))
 
 /* convert mixer stereo volume to balance */
-#define s_to_b(a) (AUDIO_RIGHT_BALANCE * ((((a) >> 8) & 0xff) /  (((((a) >> 8) & 0xff) + ((a) & 0xff)) / 2)))
+#define s_to_b(a) (s_to_g(a) == 0) ? 32 : ((left(a) * AUDIO_RIGHT_BALANCE / (left(a) + right(a))))
 
 /* convert mixer stereo volume to audio gain */
-#define s_to_g(a) (((((a) >> 8) & 0xff) + ((a) & 0xff)) / 2)
+#define s_to_g(a) ((((right(a) + left(a)) * 255) / 200) % 256)
 
 /* convert gain a and balance b to mixer volume */
-#define b_to_s(a,b) ((a * (b / AUDIO_RIGHT_BALANCE) << 8) + (a * (1 - (b / AUDIO_RIGHT_BALANCE))))
+#define b_to_s(a,b) (((((b * a * 200) / (AUDIO_RIGHT_BALANCE * 255)) % 100) << 8) + ((((AUDIO_RIGHT_BALANCE - b) * a * 200) / (AUDIO_RIGHT_BALANCE * 255)) % 100))
+
+/* Device minor numbers */
 
 #define SPARCAUDIO_MIXER_MINOR 0
-#define SPARCAUDIO_DSP16_MINOR 1
+/* No sequencer (1) */
+/* No midi (2) */
 #define SPARCAUDIO_DSP_MINOR   3
 #define SPARCAUDIO_AUDIO_MINOR 4
-#define SPARCAUDIO_AUDIOCTL_MINOR 5
+#define SPARCAUDIO_DSP16_MINOR 5
 #define SPARCAUDIO_STATUS_MINOR 6
+#define SPARCAUDIO_AUDIOCTL_MINOR 7
+/* No sequencer l2 (8) */
+/* No sound processor (9) */
+
+/* allocate 2^SPARCAUDIO_DEVICE_SHIFT minors per audio device */
+#define SPARCAUDIO_DEVICE_SHIFT 4
+
+/* With the coming of dummy devices this should perhaps be as high as 5? */
+#define SPARCAUDIO_MAX_DEVICES 3
+
+/* Streams crap for realaudio */
+
+typedef
+struct strevent {
+    struct strevent *se_next;   /* next event for this stream or NULL*/
+    struct strevent *se_prev;   /* previous event for this stream or last
+                                 * event if this is the first one*/
+    pid_t se_pid;               /* process to be signaled */
+    short se_evs;               /* events wanted */
+} strevent_t;
+
+typedef
+struct stdata
+{
+        struct stdata    *sd_next ;     /* all stdatas are linked together */
+        struct stdata    *sd_prev ;
+        struct strevent   *sd_siglist;  /* processes to be sent SIGPOLL */
+        int  sd_sigflags;               /* logical OR of all siglist events */
+} stdata_t;
+
+#define I_NREAD _IOR('S',01, int)
+#define I_NREAD_SOLARIS (('S'<<8)|1)
+
+#define I_FLUSH _IO('S',05)
+#define I_FLUSH_SOLARIS (('S'<<8)|5)
+#define FLUSHR  1                       /* flush read queue */
+#define FLUSHW  2                       /* flush write queue */
+#define FLUSHRW 3                       /* flush both queues */
+
+#define I_SETSIG _IO('S',011)
+#define I_SETSIG_SOLARIS (('S'<<8)|11)
+#define S_INPUT         0x01
+#define S_HIPRI         0x02           
+#define S_OUTPUT        0x04           
+#define S_MSG           0x08           
+#define S_ERROR         0x0010         
+#define S_HANGUP        0x0020         
+#define S_RDNORM        0x0040         
+#define S_WRNORM        S_OUTPUT
+#define S_RDBAND        0x0080         
+#define S_WRBAND        0x0100         
+#define S_BANDURG       0x0200         
+#define S_ALL           0x03FF
+
+#define I_GETSIG _IOR('S',012,int)
+#define I_GETSIG_SOLARIS (('S'<<8)|12)
 #endif
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.1.128/linux/include/asm-sparc64/dma.h	Sun Nov  8 14:03:10 1998
+++ linux/include/asm-sparc64/dma.h	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.9 1998/10/26 20:03:15 davem Exp $
+/* $Id: dma.h,v 1.10 1998/10/27 23:28:50 davem Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -17,17 +17,14 @@
 
 extern spinlock_t  dma_spin_lock;
 
-static __inline__ unsigned long claim_dma_lock(void)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&dma_spin_lock, flags);
-	return flags;
-}
-
-static __inline__ void release_dma_lock(unsigned long flags)
-{
-	spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
+#define claim_dma_lock() \
+({	unsigned long flags; \
+	spin_lock_irqsave(&dma_spin_lock, flags); \
+	flags; \
+})
+
+#define release_dma_lock(__flags) \
+	spin_unlock_irqrestore(&dma_spin_lock, __flags);
 
 /* These are irrelevant for Sparc DMA, but we leave it in so that
  * things can compile.
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.1.128/linux/include/asm-sparc64/namei.h	Sun Nov  8 14:03:10 1998
+++ linux/include/asm-sparc64/namei.h	Mon Nov 16 10:38:09 1998
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.12 1998/03/13 17:38:13 jj Exp $
+/* $Id: namei.h,v 1.13 1998/10/28 08:13:49 jj Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -29,7 +29,9 @@
 		return NULL;
 	}
 
-	base = lookup_dentry (emul, dget (current->fs->root), (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
+	base = lookup_dentry (emul, 
+			      dget (current->fs->root), 
+			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
 			
 	if (IS_ERR (base)) return NULL;
 	
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.128/linux/include/asm-sparc64/pgtable.h	Sun Nov  8 14:03:10 1998
+++ linux/include/asm-sparc64/pgtable.h	Mon Nov 16 10:37:28 1998
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.95 1998/10/22 03:05:57 davem Exp $
+/* $Id: pgtable.h,v 1.96 1998/10/27 23:28:42 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -602,7 +602,12 @@
 { pte_t pte; pte_val(pte) = (type<<PAGE_SHIFT)|(offset<<(PAGE_SHIFT+8)); return pte; }
 
 extern inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
-{ pte_t pte; pte_val(pte) = ((page) | pgprot_val(prot) | _PAGE_E) & ~(unsigned long)_PAGE_CACHE; return pte; }
+{
+	pte_t pte;
+	pte_val(pte) = ((page) | pgprot_val(prot) | _PAGE_E) & ~(unsigned long)_PAGE_CACHE;
+	pte_val(pte) |= (((unsigned long)space) << 32);
+	return pte;
+}
 
 #define SWP_TYPE(entry)		(((entry>>PAGE_SHIFT) & 0xff))
 #define SWP_OFFSET(entry)	((entry) >> (PAGE_SHIFT+8))
diff -u --recursive --new-file v2.1.128/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.128/linux/include/asm-sparc64/spinlock.h	Sun Nov  8 14:03:10 1998
+++ linux/include/asm-sparc64/spinlock.h	Mon Nov 16 10:37:28 1998
@@ -34,8 +34,8 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef unsigned long rwlock_t;
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
@@ -186,7 +186,7 @@
 	unsigned char lock;
 	unsigned int owner_pc, owner_cpu;
 } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0, 0, NO_PROC_ID }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, NO_PROC_ID }
 #define spin_lock_init(__lock)	\
 do {	(__lock)->lock = 0; \
 	(__lock)->owner_pc = 0; \
@@ -322,7 +322,7 @@
 	unsigned int writer_pc, writer_cpu;
 	unsigned int reader_pc[4];
 } rwlock_t;
-#define RW_LOCK_UNLOCKED	{ 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } }
+#define RW_LOCK_UNLOCKED	(rwlock_t) { 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } }
 
 extern void _do_read_lock(rwlock_t *rw, char *str);
 extern void _do_read_unlock(rwlock_t *rw, char *str);
diff -u --recursive --new-file v2.1.128/linux/include/linux/auto_fs.h linux/include/linux/auto_fs.h
--- v2.1.128/linux/include/linux/auto_fs.h	Fri Jul 31 17:10:33 1998
+++ linux/include/linux/auto_fs.h	Wed Nov 18 22:49:29 1998
@@ -22,6 +22,27 @@
 
 #define AUTOFS_PROTO_VERSION 3
 
+/*
+ * Architectures where both 32- and 64-bit binaries can be executed
+ * on 64-bit kernels need this.  This keeps the structure format
+ * uniform, and makes sure the wait_queue_token isn't too big to be
+ * passed back down to the kernel.
+ *
+ * This assumes that on these architectures:
+ * mode     32 bit    64 bit
+ * -------------------------
+ * int      32 bit    32 bit
+ * long     32 bit    64 bit
+ *
+ * If so, 32-bit user-space code should be backwards compatible.
+ */
+
+#if defined(__sparc__) || defined(__mips__)
+typedef unsigned int autofs_wqt_t;
+#else
+typedef unsigned long autofs_wqt_t;
+#endif
+
 enum autofs_packet_type {
 	autofs_ptype_missing,	/* Missing entry (mount request) */
 	autofs_ptype_expire,	/* Expire entry (umount request) */
@@ -34,7 +55,7 @@
 
 struct autofs_packet_missing {
 	struct autofs_packet_hdr hdr;
-        unsigned long wait_queue_token;
+        autofs_wqt_t wait_queue_token;
 	int len;
 	char name[NAME_MAX+1];
 };	
diff -u --recursive --new-file v2.1.128/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.1.128/linux/include/linux/fb.h	Mon Oct  5 13:13:44 1998
+++ linux/include/linux/fb.h	Fri Nov 13 10:10:12 1998
@@ -58,6 +58,13 @@
 #define FB_ACCEL_SUN_CGSIX	12	/* Sun cg6			*/
 #define FB_ACCEL_SUN_LEO	13	/* Sun leo/zx			*/
 #define FB_ACCEL_IMS_TWINTURBO	14	/* IMS Twin Turbo		*/
+#define FB_ACCEL_3DLABS_PERMEDIA2 15	/* 3Dlabs Permedia 2		*/
+#define FB_ACCEL_MATROX_MGA2064W 16	/* Matrox MGA2064W (Millenium)	*/
+#define FB_ACCEL_MATROX_MGA1064SG 17	/* Matrox MGA1064SG (Mystique)	*/
+#define FB_ACCEL_MATROX_MGA2164W 18	/* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGA2164W_AGP 19	/* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGAG100	20	/* Matrox G100 (Productiva G100) */
+#define FB_ACCEL_MATROX_MGAG200	21	/* Matrox G200 (Myst, Mill, ...) */
 
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
@@ -100,6 +107,7 @@
 					/* values			*/
 #define FB_ACTIVATE_VBL	       16	/* activate values on next vbl  */
 #define FB_CHANGE_CMAP_VBL     32	/* change colormap on vbl	*/
+#define FB_ACTIVATE_ALL	       64	/* change all VCs on this fb	*/
 
 #define FB_ACCELF_TEXT		1	/* text mode acceleration */
 
diff -u --recursive --new-file v2.1.128/linux/include/linux/lp.h linux/include/linux/lp.h
--- v2.1.128/linux/include/linux/lp.h	Fri Oct 23 22:01:26 1998
+++ linux/include/linux/lp.h	Mon Nov 16 10:37:49 1998
@@ -117,7 +117,7 @@
 
 struct lp_struct {
 	struct pardevice *dev;
-	int flags;
+	unsigned long flags;
 	unsigned int chars;
 	unsigned int time;
 	unsigned int wait;
diff -u --recursive --new-file v2.1.128/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.128/linux/include/linux/mm.h	Sun Nov  8 14:03:11 1998
+++ linux/include/linux/mm.h	Wed Nov 18 22:33:12 1998
@@ -3,7 +3,6 @@
 
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
 
 #ifdef __KERNEL__
 
@@ -118,7 +117,7 @@
 	unsigned long offset;
 	struct page *next_hash;
 	atomic_t count;
-	unsigned int age;
+	unsigned int unused;
 	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
 	struct wait_queue *wait;
 	struct page **pprev_hash;
@@ -227,8 +226,6 @@
  * For choosing which pages to swap out, inode pages carry a
  * page->referenced bit, which is set any time the system accesses
  * that page through the (inode,offset) hash table.
- * There is also the page->age counter, which implements a linear
- * decay (why not an exponential decay?), see swapctl.h.
  */
 
 extern mem_map_t * mem_map;
diff -u --recursive --new-file v2.1.128/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.1.128/linux/include/linux/nfs_fs.h	Thu Nov 12 16:21:24 1998
+++ linux/include/linux/nfs_fs.h	Wed Nov 18 22:48:48 1998
@@ -215,10 +215,25 @@
 extern int  nfs_find_dentry_request(struct inode *, struct dentry *);
 extern int  nfs_check_failed_request(struct inode *);
 extern int  nfs_check_error(struct inode *);
-extern int  nfs_flush_pages(struct inode *, pid_t, off_t, off_t);
-extern int  nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
+
+/*
+ * Try to write back everything synchronously (but check the
+ * return value!)
+ */
+extern int  nfs_wb_all(struct inode *);
+extern int  nfs_wb_page(struct inode *, struct page *);
+extern int  nfs_wb_pid(struct inode *, pid_t);
+extern int  nfs_wb_area(struct inode *, off_t, off_t);
+
+/*
+ * Invalidate write-backs, possibly trying to write them
+ * back first..
+ */
+extern void nfs_inval(struct inode *);
+extern int  nfs_wbinval(struct inode *);
+extern int  nfs_wbinval_pid(struct inode *, pid_t);
+
 extern int  nfs_truncate_dirty_pages(struct inode *, unsigned long);
-extern void nfs_invalidate_pages(struct inode *);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int);
 
 /*
diff -u --recursive --new-file v2.1.128/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.1.128/linux/include/linux/pagemap.h	Sun Nov  8 14:03:11 1998
+++ linux/include/linux/pagemap.h	Wed Nov 18 22:33:13 1998
@@ -83,7 +83,6 @@
 static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
 {
 	page_cache_size++;
-	page->age = PAGE_AGE_VALUE;
 	if((page->next_hash = *p) != NULL)
 		(*p)->pprev_hash = &page->next_hash;
 	*p = page;
diff -u --recursive --new-file v2.1.128/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.128/linux/include/linux/proc_fs.h	Thu Sep 17 17:53:38 1998
+++ linux/include/linux/proc_fs.h	Wed Nov 18 22:33:13 1998
@@ -143,6 +143,7 @@
 	PROC_NET_NETSTAT,
 	PROC_NET_IPFW_CHAINS,
 	PROC_NET_IPFW_CHAIN_NAMES,
+	PROC_NET_AT_AARP,
 	PROC_NET_LAST
 };
 
@@ -174,6 +175,7 @@
 	PROC_SCSI_ULTRASTOR,
 	PROC_SCSI_7000FASST,
 	PROC_SCSI_IBMMCA,
+	PROC_SCSI_FD_MCS,
 	PROC_SCSI_EATA2X,
 	PROC_SCSI_DC390T,
 	PROC_SCSI_AM53C974,
@@ -332,7 +334,7 @@
 {
     extern void scsi_init_free(char *ptr, unsigned int size);
 
-    if(x <= PROC_SCSI_FILE)
+    if(x < PROC_SCSI_FILE)
 	return(proc_unregister(proc_scsi, x));
     else {
 	struct proc_dir_entry **p = &driver->subdir, *dp;
@@ -349,6 +351,7 @@
     }
 }
 
+extern struct dentry_operations proc_dentry_operations;
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
 extern int init_proc_fs(void);
 extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
diff -u --recursive --new-file v2.1.128/linux/include/linux/swapctl.h linux/include/linux/swapctl.h
--- v2.1.128/linux/include/linux/swapctl.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/swapctl.h	Wed Nov 18 22:48:44 1998
@@ -94,32 +94,6 @@
 		return n;
 }
 
-static inline void touch_page(struct page *page)
-{
-	if (page->age < (MAX_PAGE_AGE - PAGE_ADVANCE))
-		page->age += PAGE_ADVANCE;
-	else
-		page->age = MAX_PAGE_AGE;
-}
-
-static inline void age_page(struct page *page)
-{
-	if (page->age > PAGE_DECLINE)
-		page->age -= PAGE_DECLINE;
-	else
-		page->age = 0;
-}
-
-static inline int age_of(unsigned long addr)
-{
-	return mem_map[MAP_NR(addr)].age;
-}
-
-static inline void set_page_new(unsigned long addr)
-{
-	mem_map[MAP_NR(addr)].age = PAGE_INITIAL_AGE;
-}
-
 #endif /* __KERNEL */
 
 #endif /* _LINUX_SWAPCTL_H */
diff -u --recursive --new-file v2.1.128/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.1.128/linux/include/linux/tty.h	Sun Nov  8 14:03:12 1998
+++ linux/include/linux/tty.h	Wed Nov 18 22:33:12 1998
@@ -351,6 +351,7 @@
 extern int riscom8_init(void);
 extern int specialix_init(void);
 extern int espserial_init(void);
+extern int macserial_init(void);
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine);
diff -u --recursive --new-file v2.1.128/linux/include/video/fbcon.h linux/include/video/fbcon.h
--- v2.1.128/linux/include/video/fbcon.h	Fri Oct 23 22:01:27 1998
+++ linux/include/video/fbcon.h	Fri Nov 13 10:10:12 1998
@@ -125,7 +125,7 @@
 /* ================================================================= */
 
 
-#ifdef __mc68000__
+#if defined(__mc68000__)
 
 /* ====================================================================== */
 
@@ -363,31 +363,7 @@
        : "d0", "d1", "a0", "a1", "memory");
 }
 
-#else /* !m68k */
-
-    /*
-     *  Anyone who'd like to write asm functions for other CPUs?
-     *   (Why are these functions better than those from include/asm/string.h?)
-     */
-
-#ifndef CONFIG_SUN4
-
-static __inline__ void *mymemclear_small(void *s, size_t count)
-{
-    return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemclear(void *s, size_t count)
-{
-    return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemset(void *s, size_t count)
-{
-    return(memset(s, 255, count));
-}
-
-#else
+#elif defined(CONFIG_SUN4)
 
 /* You may think that I'm crazy and that I should use generic
    routines.  No, I'm not: sun4's framebuffer crashes if we std
@@ -415,9 +391,44 @@
 {
     return sun4_memset(s, 0, count);
 }
-#endif
 
-#ifdef __i386__
+/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
+static __inline__ void fast_memmove(void *d, const void *s, size_t count)
+{
+    int i;
+    if (d<s) {
+	for (i=0; i<count; i++)
+	    ((char *) d)[i] = ((char *) s)[i];
+    } else
+	for (i=0; i<count; i++)
+	    ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
+}
+
+static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+{
+    fast_memmove(dst, src, size);
+    return dst;
+}
+
+#else
+
+static __inline__ void *mymemclear_small(void *s, size_t count)
+{
+    return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemclear(void *s, size_t count)
+{
+    return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemset(void *s, size_t count)
+{
+    return(memset(s, 255, count));
+}
+
+#if defined(__i386__)
+
 static __inline__ void fast_memmove(void *d, const void *s, size_t count)
 {
     if (d < s) {
@@ -466,28 +477,12 @@
     return dst;
 }
 
-#else
+#else /* !i386 */
 
-#ifdef CONFIG_SUN4
-/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
-static __inline__ void fast_memmove(void *d, const void *s, size_t count)
-{
-    int i;
-    if (d<s) {
-	for (i=0; i<count; i++)
-	    ((char *) d)[i] = ((char *) s)[i];
-    } else
-	for (i=0; i<count; i++)
-	    ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
-}
-
-static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
-{
-    fast_memmove(dst, src, size);
-    return dst;
-}
-
-#else
+    /*
+     *  Anyone who'd like to write asm functions for other CPUs?
+     *   (Why are these functions better than those from include/asm/string.h?)
+     */
 
 static __inline__ void *mymemmove(void *d, const void *s, size_t count)
 {
@@ -499,10 +494,8 @@
     memmove(dst, src, size);
 }
 
-#endif /* !sun4 */
-
 #endif /* !i386 */
 
-#endif /* !m68k */
+#endif
 
 #endif /* _VIDEO_FBCON_H */
diff -u --recursive --new-file v2.1.128/linux/init/main.c linux/init/main.c
--- v2.1.128/linux/init/main.c	Thu Nov 12 16:21:24 1998
+++ linux/init/main.c	Mon Nov 16 10:32:58 1998
@@ -324,6 +324,9 @@
 #ifdef CONFIG_MDA_CONSOLE
 extern void mdacon_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_LTPC
+extern void ltpc_setup(char *str, int *ints);
+#endif
 
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
@@ -370,7 +373,7 @@
 	char *cur = str;
 	int i=1;
 
-	while (cur && isdigit(*cur) && i <= 10) {
+	while (cur && (*cur=='-' || isdigit(*cur)) && i <= 10) {
 		ints[i++] = simple_strtol(cur,NULL,0);
 		if ((cur = strchr(cur,',')) != NULL)
 			cur++;
@@ -835,9 +838,12 @@
 #ifdef CONFIG_MD_BOOT
 	{ "md=", md_setup},
 #endif
-#ifdef CONFIG_MACMOUSE
+#ifdef CONFIG_ADBMOUSE
 	{ "adb_buttons=", adb_mouse_setup },
 #endif
+#ifdef CONFIG_LTPC
+	{ "ltpc=", ltpc_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -1240,7 +1246,7 @@
 #ifdef CONFIG_SBUS
 	sbus_init();
 #endif
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
 	powermac_init();
 #endif
 #ifdef CONFIG_MCA
diff -u --recursive --new-file v2.1.128/linux/kernel/acct.c linux/kernel/acct.c
--- v2.1.128/linux/kernel/acct.c	Thu Nov 12 16:21:24 1998
+++ linux/kernel/acct.c	Wed Nov 18 13:09:17 1998
@@ -273,6 +273,7 @@
 	struct acct ac;
 	mm_segment_t fs;
 	unsigned long vsize;
+	struct inode *inode;
 
 	/*
 	 * First check to see if there is enough free_space to continue
@@ -336,8 +337,11 @@
          */
 	fs = get_fs();
 	set_fs(KERNEL_DS);
+	inode = file->f_dentry->d_inode;
+	down(&inode->i_sem);
 	file->f_op->write(file, (char *)&ac,
 			       sizeof(struct acct), &file->f_pos);
+	up(&inode->i_sem);
 	set_fs(fs);
 	fput(file);
 	return 0;
diff -u --recursive --new-file v2.1.128/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.128/linux/kernel/printk.c	Thu Nov 12 16:21:25 1998
+++ linux/kernel/printk.c	Tue Nov 17 10:09:00 1998
@@ -105,7 +105,7 @@
 
 
 /*
- * Commands to sys_syslog:
+ * Commands to do_syslog:
  *
  * 	0 -- Close the log.  Currently a NOP.
  * 	1 -- Open the log. Currently a NOP.
@@ -117,7 +117,7 @@
  * 	7 -- Enable printk's to console
  *	8 -- Set level of messages printed to console
  */
-asmlinkage int sys_syslog(int type, char * buf, int len)
+int do_syslog(int type, char * buf, int len)
 {
 	unsigned long i, j, count, flags;
 	int do_clear = 0;
@@ -125,8 +125,6 @@
 	int error = -EPERM;
 
 	lock_kernel();
-	if ((type != 3) && !capable(CAP_SYS_ADMIN))
-		goto out;
 	error = 0;
 	switch (type) {
 	case 0:		/* Close log */
@@ -227,6 +225,14 @@
 	unlock_kernel();
 	return error;
 }
+
+asmlinkage int sys_syslog(int type, char * buf, int len)
+{
+	if ((type != 3) && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	return do_syslog(type, buf, len);
+}
+
 
 spinlock_t console_lock;
 
diff -u --recursive --new-file v2.1.128/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.128/linux/kernel/signal.c	Thu Nov 12 16:21:25 1998
+++ linux/kernel/signal.c	Wed Nov 18 16:31:54 1998
@@ -273,9 +273,9 @@
 		goto out_nolock;
 
 	/* The null signal is a permissions and process existance probe.
-	   No signal is actually delivered.  */
+	   No signal is actually delivered.  Same goes for zombies. */
 	ret = 0;
-	if (!sig)
+	if (!sig || !t->sig)
 		goto out_nolock;
 
 	spin_lock_irqsave(&t->sigmask_lock, flags);
diff -u --recursive --new-file v2.1.128/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.1.128/linux/lib/vsprintf.c	Thu Nov 12 16:21:25 1998
+++ linux/lib/vsprintf.c	Wed Nov 18 16:44:20 1998
@@ -290,10 +290,9 @@
 		if (qualifier == 'l')
 			num = va_arg(args, unsigned long);
 		else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
 			if (flags & SIGN)
-				num = va_arg(args, short);
-			else
-				num = va_arg(args, unsigned short);
+				num = (short) num;
 		} else if (flags & SIGN)
 			num = va_arg(args, int);
 		else
diff -u --recursive --new-file v2.1.128/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.128/linux/mm/filemap.c	Thu Nov 12 16:21:25 1998
+++ linux/mm/filemap.c	Wed Nov 18 22:20:40 1998
@@ -172,12 +172,7 @@
 				delete_from_swap_cache(page);
 				return 1;
 			}
-			if (test_and_clear_bit(PG_referenced, &page->flags)) {
-				touch_page(page);
-				break;
-			}
-			age_page(page);
-			if (page->age)
+			if (test_and_clear_bit(PG_referenced, &page->flags))
 				break;
 			if (pgcache_under_min())
 				break;
@@ -212,8 +207,8 @@
 	struct page * page;
 	int count_max, count_min;
 
-	count_max = (limit<<2) >> (priority>>1);
-	count_min = (limit<<2) >> (priority);
+	count_max = (limit<<1) >> (priority>>1);
+	count_min = (limit<<1) >> (priority);
 
 	page = mem_map + clock;
 	do {
diff -u --recursive --new-file v2.1.128/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.128/linux/mm/page_alloc.c	Sun Nov  8 14:03:13 1998
+++ linux/mm/page_alloc.c	Wed Nov 18 22:28:32 1998
@@ -231,7 +231,6 @@
 		map += size; \
 	} \
 	atomic_set(&map->count, 1); \
-	map->age = PAGE_INITIAL_AGE; \
 } while (0)
 
 unsigned long __get_free_pages(int gfp_mask, unsigned long order)
diff -u --recursive --new-file v2.1.128/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.128/linux/mm/page_io.c	Wed Sep  9 14:51:13 1998
+++ linux/mm/page_io.c	Tue Nov 17 17:36:53 1998
@@ -66,6 +66,11 @@
 		printk("Internal error: bad swap-device\n");
 		return;
 	}
+
+	/* Don't allow too many pending pages in flight.. */
+	if (atomic_read(&nr_async_pages) > SWAP_CLUSTER_MAX)
+		wait = 1;
+
 	p = &swap_info[type];
 	offset = SWP_OFFSET(entry);
 	if (offset >= p->max) {
diff -u --recursive --new-file v2.1.128/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.128/linux/mm/swapfile.c	Sun Nov  8 14:03:13 1998
+++ linux/mm/swapfile.c	Mon Nov 16 10:36:36 1998
@@ -636,7 +636,7 @@
 		p->max	       = swap_header->info.last_page;
 
 		if (p->max >= 0x7fffffffL/PAGE_SIZE ||
-		    (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) {
+		    (void *) &swap_header->info.badpages[(int) swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) {
 			error = -EINVAL;
 			goto bad_swap;
 		}
diff -u --recursive --new-file v2.1.128/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.128/linux/mm/vmscan.c	Thu Nov 12 16:21:25 1998
+++ linux/mm/vmscan.c	Tue Nov 17 17:37:09 1998
@@ -538,7 +538,7 @@
 		do {
 			if (!do_try_to_free_page(0))
 				break;
-			if (nr_free_pages > 2*freepages.high)
+			if (nr_free_pages > freepages.high + SWAP_CLUSTER_MAX)
 				break;
 		} while (time_before_eq(jiffies,end_time));
 	}
@@ -621,8 +621,6 @@
 		 * priority.
 		 */
 		want_wakeup = 0;
-		if (buffer_over_max() || pgcache_over_max())
-			want_wakeup = 1;
 		pages = nr_free_pages;
 		if (pages < freepages.high)
 			want_wakeup = 1;
diff -u --recursive --new-file v2.1.128/linux/net/802/fddi.c linux/net/802/fddi.c
--- v2.1.128/linux/net/802/fddi.c	Thu Nov 12 16:21:25 1998
+++ linux/net/802/fddi.c	Sun Nov 15 09:52:28 1998
@@ -25,6 +25,7 @@
  *		Alan Cox	:	New arp/rebuild header
  */
  
+#include <linux/config.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.1.128/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v2.1.128/linux/net/appletalk/aarp.c	Tue Jul 21 00:15:33 1998
+++ linux/net/appletalk/aarp.c	Fri Nov 13 10:29:43 1998
@@ -23,6 +23,8 @@
  *		Inside AppleTalk (2nd Ed).
  *	Fixes:
  *		Jaume Grau	-	flush caches on AARP_PROBE
+ *		Rob Newberry	-	Added proxy AARP and AARP proc fs, 
+ *					moved probing from DDP module.
  *
  */
 
@@ -53,6 +55,7 @@
 #include <net/psnap.h>
 #include <linux/atalk.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
 
  
 int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
@@ -69,6 +72,7 @@
 	/* These first two are only used for unresolved entries */
 	unsigned long last_sent;		/* Last time we xmitted the aarp request */
 	struct sk_buff_head packet_queue;	/* Queue of frames wait for resolution */
+	int status;				/* Used for proxy AARP */
 	unsigned long expires_at;		/* Entry expiry time */
 	struct at_addr target_addr;		/* DDP Address */
 	struct device *dev;			/* Device to use */
@@ -77,12 +81,11 @@
 	struct aarp_entry *next;		/* Next entry in chain */
 };
 
-
 /*
- *	Hashed list of resolved and unresolved entries
+ *	Hashed list of resolved, unresolved and proxy entries
  */
 
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
 static int unresolved_count=0;
 
 /*
@@ -224,7 +227,7 @@
 }
 
 /*
- *	Send probe frames. Called from atif_probe_device.
+ *	Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
  */
  
 void aarp_send_probe(struct device *dev, struct at_addr *us)
@@ -360,6 +363,7 @@
 		aarp_expire_timer(&resolved[ct]);
 		aarp_kick(&unresolved[ct]);
 		aarp_expire_timer(&unresolved[ct]);
+		aarp_expire_timer(&proxies[ct]);
 	}
 	del_timer(&aarp_timer);
 	if(unresolved_count==0)
@@ -382,6 +386,7 @@
 		{
 			aarp_expire_device(&resolved[ct],ptr);
 			aarp_expire_device(&unresolved[ct],ptr);
+			aarp_expire_device(&proxies[ct],ptr);
 		}
 	}
 	return NOTIFY_DONE;
@@ -420,6 +425,156 @@
 	return list;
 }
 
+void aarp_proxy_remove(struct device *dev, struct at_addr *sa)
+{
+	struct aarp_entry *a;
+	int hash;
+	
+	hash = 	sa->s_node % (AARP_HASH_SIZE-1);
+	a = aarp_find_entry(proxies[hash], dev, sa);
+	if (a)
+	{
+		a->expires_at = 0;
+		
+	}
+}
+
+struct at_addr* aarp_proxy_find(struct device *dev, struct at_addr *sa)
+{
+	struct aarp_entry *a;
+	int hash;
+
+	hash = 	sa->s_node % (AARP_HASH_SIZE-1);
+	a = aarp_find_entry(proxies[hash], dev, sa);
+	if (a != NULL)
+		return sa;
+	
+	return NULL;
+}
+
+	
+/*
+ * Probe a Phase 1 device or a device that requires its Net:Node to
+ * be set via an ioctl.
+ */
+void aarp_send_probe_phase1(struct atalk_iface *iface)
+{
+    struct ifreq atreq;
+    struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
+
+    sa->sat_addr.s_node = iface->address.s_node;
+    sa->sat_addr.s_net  = ntohs(iface->address.s_net);
+
+	/* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+	if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
+    {
+    	(void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+    	if((iface->address.s_net != htons(sa->sat_addr.s_net))
+				|| (iface->address.s_node != sa->sat_addr.s_node))
+			iface->status |= ATIF_PROBE_FAIL;
+
+		iface->address.s_net  = htons(sa->sat_addr.s_net);
+		iface->address.s_node = sa->sat_addr.s_node;
+	}
+
+	return;
+}
+
+
+void aarp_probe_network(struct atalk_iface *atif)
+{
+	if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+		aarp_send_probe_phase1(atif);
+	else
+	{
+		unsigned int count;
+		for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+		{
+			aarp_send_probe(atif->dev, &atif->address);
+
+			/*
+			 * Defer 1/10th
+			 */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ/10);
+							
+			if (atif->status & ATIF_PROBE_FAIL)
+				break;
+		}
+	}
+}
+
+int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
+{
+	struct	aarp_entry	*entry;
+	unsigned int count;
+	int	hash;
+	
+	/*
+	 * we don't currently support LocalTalk or PPP for proxy AARP;
+	 * if someone wants to try and add it, have fun
+	 */
+	if (atif->dev->type == ARPHRD_LOCALTLK)
+		return (-EPROTONOSUPPORT);
+		
+	if (atif->dev->type == ARPHRD_PPP)
+		return (-EPROTONOSUPPORT);
+		
+	/* 
+	 * create a new AARP entry with the flags set to be published -- 
+	 * we need this one to hang around even if it's in use
+	 */
+	entry = aarp_alloc();
+	if (entry == NULL)
+		return (-ENOMEM);
+	
+	entry->expires_at = -1;
+	entry->status = ATIF_PROBE;
+	entry->target_addr.s_node = sa->s_node;
+	entry->target_addr.s_net = sa->s_net;
+	entry->dev = atif->dev;
+
+	hash = sa->s_node % (AARP_HASH_SIZE-1);
+	entry->next = proxies[hash];
+	proxies[hash] = entry;
+	
+	for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+	{
+		aarp_send_probe(atif->dev, sa);
+
+		/*
+		 * Defer 1/10th
+		 */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+						
+		if (entry->status & ATIF_PROBE_FAIL)
+			break;
+	}
+	
+	/*
+	 * FIX ME: I think we need exclusive access to the status flags,
+	 * 		in case some one fails the probe while we're removing
+	 *		the probe flag.
+	 */
+	if (entry->status & ATIF_PROBE_FAIL)
+	{
+		/* free the entry */
+		entry->expires_at = 0;
+		
+		/* return network full */
+		return (-EADDRINUSE);
+	}
+	else
+	{
+		/* clear the probing flag */
+		entry->status &= ~ATIF_PROBE;
+	}
+
+	return 1;	
+}
+
+
 /*
  *	Send a DDP frame
  */
@@ -654,7 +809,7 @@
 {
 	struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
 	struct aarp_entry *a;
-	struct at_addr sa, *ma;
+	struct at_addr sa, *ma, da;
 	unsigned long flags;
 	int hash;
 	struct atalk_iface *ifa;
@@ -736,8 +891,34 @@
 			kfree_skb(skb);
 			return 1;		
 		}
-	}				 
+	}
 	
+	/*
+	 * Check for replies of proxy AARP entries
+	 */
+
+	/*
+	 * FIX ME: do we need a cli() here? 
+	 * aarp_find_entry does one on its own, between saving and restoring flags, so
+	 * I don't think it is necessary, but I could be wrong -- it's happened before
+	 */
+	da.s_node = ea->pa_dst_node;
+	da.s_net = ea->pa_dst_net;
+	a = aarp_find_entry(proxies[hash], dev, &da);
+	if (a != NULL)
+		if (a->status & ATIF_PROBE)
+		{
+			a->status |= ATIF_PROBE_FAIL;
+			
+			/*
+			 * we do not respond to probe or request packets for 
+			 * this address while we are probing this address
+			 */
+			restore_flags(flags);
+			kfree_skb(skb);
+			return 1;
+		}
+
 	switch(ea->function)
 	{
 		case AARP_REPLY:	
@@ -747,7 +928,7 @@
 			 *	Find the entry	
 			 */
 			 
-			cli();
+			cli();	/* FIX ME: is this cli() necessary? aarp_find_entry does one on its own... */
 			if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
 				break;
 			/*
@@ -770,12 +951,32 @@
 			 *	If it is my address set ma to my address and reply. We can treat probe and
 			 *	request the same. Probe simply means we shouldn't cache the querying host, 
 			 *	as in a probe they are proposing an address not using one.
+			 *	
+			 *	Support for proxy-AARP added.  We check if the address is one
+			 *	of our proxies before we toss the packet out.
 			 */
 			 
-			ma=&ifa->address;
 			sa.s_node=ea->pa_dst_node;
 			sa.s_net=ea->pa_dst_net;
-			
+
+			/*
+			 * see if we have a matching proxy
+			 */
+			ma = aarp_proxy_find(dev, &sa);
+			if (!ma)
+			{
+				ma=&ifa->address;
+			}
+			else
+			{
+				/*
+				 * we need to make a copy of the entry
+				 */
+				da.s_node = sa.s_node;
+				da.s_net = da.s_net;
+				ma = &da;
+			}
+
 			if(ea->function==AARP_PROBE)
 			{
 				/* A probe implies someone trying to get an
@@ -845,11 +1046,104 @@
 	{
 		aarp_expire_device(&resolved[ct], dev);
 		aarp_expire_device(&unresolved[ct], dev);
+		aarp_expire_device(&proxies[ct], dev);
 	}
 
 	return;
 }
 
+/*
+ * Called from proc fs
+ */
+int aarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	/* we should dump all our AARP entries */
+	struct aarp_entry	*entry;
+	int			len, ct;
+
+	len = sprintf(buffer,
+		"%-10.10s  ""%-10.10s""%-18.18s""%12.12s""%12.12s"" xmit_count  status\n",
+		"address","device","hw addr","last_sent", "expires");
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = resolved[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+
+			len+=sprintf(buffer+len,"   resolved\n");
+		}
+	}
+
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = unresolved[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+			len+=sprintf(buffer+len," unresolved\n");
+		}
+	}
+
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = proxies[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+			len+=sprintf(buffer+len,"      proxy\n");
+		}
+	}
+
+
+	return len;
+}
+
 #ifdef MODULE
 /*
  * General module cleanup. Called from cleanup_module() in ddp.c.
@@ -862,4 +1156,27 @@
 }
 
 #endif  /* MODULE */
+
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry proc_aarp_entries=
+{
+	PROC_NET_AT_AARP, 4, "aarp",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_net_inode_operations,
+	aarp_get_info
+};
+
+void aarp_register_proc_fs(void)
+{
+	proc_net_register(&proc_aarp_entries);
+}
+
+void aarp_unregister_proc_fs(void)
+{
+	proc_net_unregister(PROC_NET_AT_AARP);
+}
+
+#endif
+
 #endif  /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
diff -u --recursive --new-file v2.1.128/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.128/linux/net/appletalk/ddp.c	Sun Nov  8 14:03:13 1998
+++ linux/net/appletalk/ddp.c	Fri Nov 13 10:29:43 1998
@@ -29,6 +29,8 @@
  *						driver file. (ipddp.c & ipddp.h)
  *		Jay Schulist		:	Made work as module with 
  *						AppleTalk drivers, cleaned it.
+ *		Rob Newberry		:	Added proxy AARP and AARP proc fs, 
+ *						moved probing to AARP module.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -76,6 +78,16 @@
 #include <linux/init.h>
 
 
+#ifdef CONFIG_PROC_FS
+extern void aarp_register_proc_fs(void);
+extern void aarp_unregister_proc_fs(void);
+#endif
+
+extern void aarp_probe_network(struct atalk_iface *atif);
+extern int  aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa);
+extern void aarp_proxy_remove(struct device *dev, struct at_addr *sa);
+
+
 #undef APPLETALK_DEBUG
 
 #ifdef APPLETALK_DEBUG
@@ -301,32 +313,6 @@
 	return (iface);
 }
 
-/*
- * Probe a Phase 1 device or a device that requires its Net:Node to
- * be set via an ioctl.
- */
-void atif_send_probe_phase1(struct atalk_iface *iface)
-{
-        struct ifreq atreq;
-        struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
-
-        sa->sat_addr.s_node = iface->address.s_node;
-        sa->sat_addr.s_net  = ntohs(iface->address.s_net);
-
-         /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
-        if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
-        {
-                (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
-                if((iface->address.s_net != htons(sa->sat_addr.s_net))
-			|| (iface->address.s_node != sa->sat_addr.s_node))
-                        iface->status |= ATIF_PROBE_FAIL;
-
-                iface->address.s_net  = htons(sa->sat_addr.s_net);
-		iface->address.s_node = sa->sat_addr.s_node;
-        }
-
-        return;
-}
 
 /*
  * Perform phase 2 AARP probing on our tentative address.
@@ -336,7 +322,7 @@
 	int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
 	int probe_net=ntohs(atif->address.s_net);
 	int probe_node=atif->address.s_node;
-	int ct, netct, nodect;
+	int netct, nodect;
 
 	/*
 	 * Offset the network we start probing with.
@@ -372,23 +358,8 @@
 				/*
 				 * Probe a proposed address.
 				 */
+				aarp_probe_network(atif);
 
-				if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
-                                        atif_send_probe_phase1(atif);
-                                else
-                                {
-					for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++)
-					{
-						aarp_send_probe(atif->dev, &atif->address);
-						/*
-						 * Defer 1/10th
-						 */
-						current->state = TASK_INTERRUPTIBLE;
-						schedule_timeout(HZ/10);
-						if(atif->status & ATIF_PROBE_FAIL)
-							break;
-					}
-				}
 				if(!(atif->status & ATIF_PROBE_FAIL))
 					return (0);
 			}
@@ -402,6 +373,69 @@
 	return (-EADDRINUSE);	/* Network is full... */
 }
 
+
+/*
+ * Perform AARP probing for a proxy address
+ */
+static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* proxy_addr)
+{
+	int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
+	int probe_net=ntohs(atif->address.s_net);	// we probe the interface's network
+	int probe_node=ATADDR_ANYNODE;				// we'll take anything
+	int netct, nodect;
+
+	/*
+	 * Offset the network we start probing with.
+	 */
+
+	if(probe_net == ATADDR_ANYNET)
+	{
+		if(!netrange)
+			probe_net = ntohs(atif->nets.nr_firstnet);
+		else
+			probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+	}
+
+	if(probe_node == ATADDR_ANYNODE)
+		probe_node = jiffies&0xFF;
+		
+	/*
+	 * Scan the networks.
+	 */
+
+	for(netct = 0; netct <= netrange; netct++)
+	{
+		/*
+		 * Sweep the available nodes from a given start.
+		 */
+
+		proxy_addr->s_net = htons(probe_net);
+		for(nodect = 0; nodect < 256; nodect++)
+		{
+			proxy_addr->s_node = ((nodect+probe_node) & 0xFF);
+			if((proxy_addr->s_node>0) && (proxy_addr->s_node<254))
+			{
+				/*
+				 * Tell AARP to probe a proposed address.
+				 */
+				int probe_result = aarp_proxy_probe_network(atif, proxy_addr);
+
+				if (probe_result == 0)
+					return 0;
+					
+				if (probe_result != -EADDRINUSE)
+					return probe_result;
+			}
+		}
+		probe_net++;
+		if(probe_net > ntohs(atif->nets.nr_lastnet))
+			probe_net = ntohs(atif->nets.nr_firstnet);
+	}
+
+	return (-EADDRINUSE);	/* Network is full... */
+}
+
+
 struct at_addr *atalk_find_dev_addr(struct device *dev)
 {
 	struct atalk_iface *iface=dev->atalk_ptr;
@@ -481,19 +515,46 @@
  */
 static struct atalk_route *atrtr_find(struct at_addr *target)
 {
+	/*
+	 * we must search through all routes unless we find a 
+	 * host route, because some host routes might overlap
+	 * network routes
+	 */
 	struct atalk_route *r;
-
+	struct atalk_route *net_route = NULL;
+	
 	for(r=atalk_router_list; r != NULL; r=r->next)
 	{
 		if(!(r->flags & RTF_UP))
 			continue;
 		if(r->target.s_net == target->s_net)
 		{
-			if(!(r->flags&RTF_HOST) 
-				|| r->target.s_node == target->s_node)
-				return (r);
+			if (r->flags & RTF_HOST)
+			{
+				/*
+				 * if this host route is for the target,
+				 * the we're done
+				 */
+				if (r->target.s_node == target->s_node)
+					return (r);
+			}
+			else
+			{
+				/*
+				 * this route will work if there isn't a
+				 * direct host route, so cache it
+				 */
+				net_route = r;
+			}
 		}
 	}
+	
+	/* 
+	 * if we found a network route but not a direct host
+	 * route, then return it
+	 */
+	if (net_route != NULL)
+		return (net_route);
 
 	if(atrtr_default.dev)
 		return (&atrtr_default);
@@ -705,6 +766,7 @@
 	int ct;
 	int limit;
 	struct rtentry rtdef;
+	int	add_route;
 
 	if(copy_from_user(&atreq,arg,sizeof(atreq)))
 		return (-EFAULT);
@@ -730,6 +792,18 @@
 
 			nr=(struct netrange *)&sa->sat_zero[0];
 
+			add_route = 1;
+
+			/*
+			 * if this is a point-to-point iface, and we already have an 
+			 * iface for this AppleTalk address, then we should not add a route
+			 */
+			if (dev->flags & IFF_POINTOPOINT && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node))
+			{
+				printk(KERN_DEBUG "AppleTalk: point-to-point interface added with existing address\n");
+				add_route = 0;
+			}
+			
 			/*
 			 * Phase 1 is fine on LocalTalk but we don't do
 			 * EtherTalk phase 1. Anyone wanting to add it go ahead.
@@ -764,7 +838,7 @@
 			 * error and atalkd will try another.
 			 */
 
-			if(!(dev->flags & IFF_LOOPBACK) && atif_probe_device(atif) < 0)
+			if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0)
 			{
 				atif_drop_device(dev);
 				return (-EADDRINUSE);
@@ -782,7 +856,7 @@
 			rtdef.rt_flags = RTF_UP;
 			sa->sat_family = AF_APPLETALK;
 			sa->sat_addr.s_node = ATADDR_ANYNODE;
-			if(dev->flags & IFF_LOOPBACK)
+			if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
 				rtdef.rt_flags |= RTF_HOST;
 
 			/*
@@ -803,11 +877,12 @@
 					printk(KERN_WARNING "Too many routes/iface.\n");
 					return (-EINVAL);
 				}
-				for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
-				{
-					sa->sat_addr.s_net = htons(ct);
-					atrtr_create(&rtdef, dev);
-				}
+				if (add_route)
+					for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
+					{
+						sa->sat_addr.s_net = htons(ct);
+						atrtr_create(&rtdef, dev);
+					}
 			}
 			dev_mc_add(dev, aarp_mcast, 6, 1);
 			return (0);
@@ -835,6 +910,68 @@
 				return (-EINVAL);
 			atalk_dev_down(dev);
 			break;			
+
+		case SIOCSARP:
+			if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * for now, we only support proxy AARP on ELAP;
+                         * we should be able to do it for LocalTalk, too.
+                         */
+                        if(dev->type != ARPHRD_ETHER)
+                                return (-EPROTONOSUPPORT);
+
+                        /*
+                         * atif points to the current interface on this network;
+                         * we aren't concerned about its current status (at least for now),
+                         * but it has all the settings about the network we're going
+                         * to probe.  consequently, it must exist.
+                         */
+                        if (!atif)
+                                return (-EADDRNOTAVAIL);
+
+                        nr=(struct netrange *)&(atif->nets);
+                        /*
+                         * Phase 1 is fine on Localtalk but we don't do
+                         * Ethertalk phase 1. Anyone wanting to add it go ahead.
+                         */
+                        if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+                                return (-EPROTONOSUPPORT);
+
+                        if(sa->sat_addr.s_node == ATADDR_BCAST
+                                || sa->sat_addr.s_node == 254)
+                                return (-EINVAL);
+
+                        /*
+                         * Check if the chosen address is used. If so we
+                         * error and ATCP will try another.
+                         */
+                      	if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+                      		return (-EADDRINUSE);
+                      	
+                       /*
+                         * We now have an address on the local network, and the AARP
+                         * code will defend it for us until we take it down.
+                         * We don't set up any routes right now, because ATCP will
+                         * install them manually via SIOCADDRT.
+                         */
+                        break;
+
+                case SIOCDARP:
+                        if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * give to aarp module to remove proxy entry
+                         */
+                        aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+
+                        return (0);
 	}
 
 	if(copy_to_user(arg, &atreq, sizeof(atreq)))
@@ -849,6 +986,7 @@
 static int atrtr_ioctl(unsigned int cmd, void *arg)
 {
 	struct rtentry rt;
+	struct device *dev = NULL;
 
 	if(copy_from_user(&rt, arg, sizeof(rt)))
 		return (-EFAULT);
@@ -861,7 +999,12 @@
 			return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
 
 		case SIOCADDRT:
-			return (atrtr_create(&rt, NULL));
+			/* FIX ME: the name of the device is still in user space, isn't it? */
+			if (rt.rt_dev != NULL)
+				if ((dev = dev_get(rt.rt_dev)) == NULL)
+					return -(ENODEV);
+			
+			return (atrtr_create(&rt, dev));
 
 		default:
 			return (-EINVAL);
@@ -1004,7 +1147,15 @@
 		case SOCK_DGRAM:
 			sock->ops = &atalk_dgram_ops;
 			break;
-
+			
+		case SOCK_STREAM:
+			/*
+			 * TO DO: if you want to implement ADSP, here's the place to start
+			 */
+			/*
+			sock->ops = &atalk_stream_ops;
+			break;
+			*/
 		default:
 			sk_free((void *)sk);
 			return (-ESOCKTNOSUPPORT);
@@ -1330,6 +1481,13 @@
 		 */
 		if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
 		{
+			/*
+			 * FIX ME:
+			 * Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network?
+			 */
+			if (dev->type == ARPHRD_PPP)
+				printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
+			
 			kfree_skb(skb);
 			return (0);
 		}
@@ -1821,6 +1979,8 @@
 		case SIOCGIFBRDADDR:
 		case SIOCATALKDIFADDR:
 		case SIOCDIFADDR:
+		case SIOCSARP:	/* proxy AARP */
+		case SIOCDARP:	/* proxy AARP */
 			return (atif_ioctl(cmd,(void *)arg));
 
 		/*
@@ -1966,6 +2126,8 @@
 	proc_net_register(&proc_appletalk);
 	proc_net_register(&proc_atalk_route);
 	proc_net_register(&proc_atalk_iface);
+
+	aarp_register_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SYSCTL
@@ -2006,6 +2168,8 @@
 	proc_net_unregister(PROC_NET_ATALK);
 	proc_net_unregister(PROC_NET_AT_ROUTE);
 	proc_net_unregister(PROC_NET_ATIF);
+
+	aarp_unregister_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
 	aarp_cleanup_module();	/* General aarp clean-up. */
diff -u --recursive --new-file v2.1.128/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c
--- v2.1.128/linux/net/ax25/ax25_ip.c	Sat Sep  5 16:46:42 1998
+++ linux/net/ax25/ax25_ip.c	Fri Nov 13 10:29:43 1998
@@ -195,6 +195,18 @@
   	return 1;
 }
 
+#else	/* INET */
+
+int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+	return -AX25_HEADER_LEN;
+}
+
+int ax25_rebuild_header(struct sk_buff *skb)
+{
+	return 1;
+}
+
 #endif
 
 #endif
diff -u --recursive --new-file v2.1.128/linux/net/econet/econet.c linux/net/econet/econet.c
--- v2.1.128/linux/net/econet/econet.c	Thu Nov 12 16:21:25 1998
+++ linux/net/econet/econet.c	Mon Nov 16 15:09:36 1998
@@ -706,22 +706,13 @@
 		case SIOCSIFHWBROADCAST:
 			return(dev_ioctl(cmd,(void *) arg));
 
-
 		case SIOCSIFADDR:
 		case SIOCGIFADDR:
 			return ec_dev_ioctl(sock, cmd, (void *)arg);
 			break;
 
 		default:
-			if ((cmd >= SIOCDEVPRIVATE) &&
-			    (cmd <= (SIOCDEVPRIVATE + 15)))
-				return(dev_ioctl(cmd,(void *) arg));
-
-#ifdef CONFIG_NET_RADIO
-			if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST))
-				return(dev_ioctl(cmd,(void *) arg));
-#endif
-			return -EOPNOTSUPP;
+			return(dev_ioctl(cmd,(void *) arg));
 	}
 	/*NOTREACHED*/
 	return 0;
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.128/linux/net/ipv4/af_inet.c	Sun Nov  8 14:03:14 1998
+++ linux/net/ipv4/af_inet.c	Mon Nov 16 10:39:27 1998
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.79 1998/10/04 06:51:08 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.80 1998/11/08 11:17:03 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.128/linux/net/ipv4/arp.c	Sun Nov  8 14:03:14 1998
+++ linux/net/ipv4/arp.c	Wed Nov 18 09:06:05 1998
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.74 1998/11/01 22:15:06 davem Exp $
+ * Version:	$Id: arp.c,v 1.75 1998/11/16 04:51:56 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -163,8 +163,6 @@
 	dev_queue_xmit
 };
 
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) || \
-    defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
 struct neigh_ops arp_broken_ops =
 {
 	AF_INET,
@@ -176,7 +174,6 @@
 	dev_queue_xmit,
 	dev_queue_xmit,
 };
-#endif
 
 struct neigh_table arp_tbl =
 {
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.1.128/linux/net/ipv4/raw.c	Sun Nov  8 14:03:14 1998
+++ linux/net/ipv4/raw.c	Mon Nov 16 10:39:27 1998
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.38 1998/10/03 09:37:45 davem Exp $
+ * Version:	$Id: raw.c,v 1.39 1998/11/08 11:17:04 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.128/linux/net/ipv4/tcp.c	Sun Nov  8 14:03:14 1998
+++ linux/net/ipv4/tcp.c	Mon Nov 16 10:39:27 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.130 1998/11/07 14:36:10 davem Exp $
+ * Version:	$Id: tcp.c,v 1.132 1998/11/08 13:21:14 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -541,17 +541,8 @@
 /*
  *	Compute minimal free write space needed to queue new packets. 
  */
-static inline int tcp_min_write_space(struct sock *sk, struct tcp_opt *tp)
-{
-	int space;
-#if 1 /* This needs benchmarking and real world tests */
-	space = max(tp->mss_cache + 128, MIN_WRITE_SPACE);
-#else /* 2.0 way */
-	/* More than half of the socket queue free? */
-	space = atomic_read(&sk->wmem_alloc) / 2;
-#endif
-	return space;
-}
+#define tcp_min_write_space(__sk) \
+	(atomic_read(&(__sk)->wmem_alloc) / 2)
 
 /*
  *	Wait for a TCP event.
@@ -599,7 +590,7 @@
 			mask |= POLLIN | POLLRDNORM;
 
 		if (!(sk->shutdown & SEND_SHUTDOWN)) {
-			if (sock_wspace(sk) >= tcp_min_write_space(sk, tp)) {
+			if (sock_wspace(sk) >= tcp_min_write_space(sk)) {
 				mask |= POLLOUT | POLLWRNORM;
 			} else {  /* send SIGIO later */
 				sk->socket->flags |= SO_NOSPACE;
@@ -623,7 +614,7 @@
 
 	wake_up_interruptible(sk->sleep);
 	if (sock_wspace(sk) >=
-	    tcp_min_write_space(sk, &(sk->tp_pinfo.af_tcp)))
+	    tcp_min_write_space(sk))
 		sock_wake_async(sk->socket, 2);
 }
 
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.128/linux/net/ipv4/tcp_input.c	Sun Nov  8 14:03:15 1998
+++ linux/net/ipv4/tcp_input.c	Wed Nov 18 09:06:05 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.136 1998/11/07 14:36:18 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.141 1998/11/18 02:12:07 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -262,7 +262,7 @@
 }
 
 /* When we get a reset we do this. */
-static void tcp_reset(struct sock *sk, struct sk_buff *skb)
+static void tcp_reset(struct sock *sk)
 {
 	sk->zapped = 1;
 
@@ -277,7 +277,7 @@
 		default:
 			sk->err = ECONNRESET;
 	};
-	tcp_set_state(sk,TCP_CLOSE);
+	tcp_set_state(sk, TCP_CLOSE);
 	sk->shutdown = SHUTDOWN_MASK;
 	if (!sk->dead) 
 		sk->state_change(sk);
@@ -483,33 +483,36 @@
 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
 			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-                                tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+                                tp->snd_ssthresh =
+					max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
 				tp->high_seq = tp->snd_nxt;
 				if(!tp->fackets_out)
-					tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+					tcp_retransmit_skb(sk,
+							   skb_peek(&sk->write_queue));
 				else
 					tcp_fack_retransmit(sk);
                                 tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 			}
-		}
-
-                /* 2. Each time another duplicate ACK arrives, increment 
-                 * cwnd by the segment size. [...] Transmit a packet...
-                 *
-                 * Packet transmission will be done on normal flow processing
-                 * since we're not in "retransmit mode".  We do not use duplicate
-		 * ACKs to artificially inflate the congestion window when
-		 * doing FACK.
-                 */
-                if (tp->dup_acks > 3) {
+		} else if (++tp->dup_acks > 3) {
+			/* 2. Each time another duplicate ACK arrives, increment 
+			 * cwnd by the segment size. [...] Transmit a packet...
+			 *
+			 * Packet transmission will be done on normal flow processing
+			 * since we're not in "retransmit mode".  We do not use
+			 * duplicate ACKs to artificially inflate the congestion
+			 * window when doing FACK.
+			 */
 			if(!tp->fackets_out) {
 				tp->snd_cwnd++;
 			} else {
-				/* Fill any further holes which may have appeared.
-				 * We may want to change this to run every further
-				 * multiple-of-3 dup ack increments, to be more robust
-				 * against out-of-order packet delivery.  -DaveM
+				/* Fill any further holes which may have
+				 * appeared.
+				 *
+				 * We may want to change this to run every
+				 * further multiple-of-3 dup ack increments,
+				 * to be more robust against out-of-order
+				 * packet delivery.  -DaveM
 				 */
 				tcp_fack_retransmit(sk);
 			}
@@ -552,7 +555,8 @@
 				 * from snd_una is if this was a window update.
 				 */
 				if (ack != tp->snd_una && before(ack, tp->high_seq)) {
-                                	tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+                                	tcp_retransmit_skb(sk,
+							   skb_peek(&sk->write_queue));
                                 	tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 				}
 			} else {
@@ -568,7 +572,7 @@
 /* This is Jacobson's slow start and congestion avoidance. 
  * SIGCOMM '88, p. 328.
  */
-static void tcp_cong_avoid(struct tcp_opt *tp)
+static __inline__ void tcp_cong_avoid(struct tcp_opt *tp)
 {
         if (tp->snd_cwnd <= tp->snd_ssthresh) {
                 /* In "safe" area, increase. */
@@ -656,6 +660,33 @@
 	}
 }
  
+/* Should we open up the congestion window? */
+static __inline__ int should_advance_cwnd(struct tcp_opt *tp, int flag)
+{
+	/* Data must have been acked. */
+	if ((flag & FLAG_DATA_ACKED) == 0)
+		return 0;
+
+	/* Some of the data acked was retransmitted somehow? */
+	if ((flag & FLAG_RETRANS_DATA_ACKED) != 0) {
+		/* We advance in all cases except during
+		 * non-FACK fast retransmit/recovery.
+		 */
+		if (tp->fackets_out != 0 ||
+		    tp->retransmits != 0)
+			return 1;
+
+		/* Non-FACK fast retransmit does it's own
+		 * congestion window management, don't get
+		 * in the way.
+		 */
+		return 0;
+	}
+
+	/* New non-retransmitted data acked, always advance.  */
+	return 1;
+}
+
 /* Read draft-ietf-tcplw-high-performance before mucking
  * with this code. (Superceeds RFC1323)
  */
@@ -691,8 +722,10 @@
 		}
 	} else {
 		tcp_set_rto(tp);
-		tcp_cong_avoid(tp);
 	}
+	if (should_advance_cwnd(tp, flag))
+		tcp_cong_avoid(tp);
+
 	/* NOTE: safe here so long as cong_ctl doesn't use rto */
 	tcp_bound_rto(tp);
 }
@@ -810,9 +843,10 @@
 					tcp_set_rto(tp);
 					tcp_bound_rto(tp);
 				}
-				tcp_cong_avoid(tp);
 			}
 		}
+		if (should_advance_cwnd(tp, flag))
+			tcp_cong_avoid(tp);
 	}
 
 	if (tp->packets_out) {
@@ -1814,12 +1848,12 @@
 	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
 		SOCK_DEBUG(sk, "syn in established state\n");
 		tcp_statistics.TcpInErrs++;
-		tcp_reset(sk, skb);
+		tcp_reset(sk);
 		return 1;
 	}
 	
 	if(th->rst) {
-		tcp_reset(sk,skb);
+		tcp_reset(sk);
 		goto discard;
 	}
 
@@ -1944,8 +1978,27 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	int queued = 0;
 
-	/* state == CLOSED, hash lookup always fails, so no worries. -DaveM */
 	switch (sk->state) {
+	case TCP_CLOSE:
+		/* When state == CLOSED, hash lookup always fails.
+		 *
+		 * But, there is a back door, the backlog queue.
+		 * If we have a sequence of packets in the backlog
+		 * during __release_sock() which have a sequence such
+		 * that:
+		 *	packet X	causes entry to TCP_CLOSE state
+		 *	...
+		 *	packet X + N	has FIN bit set
+		 *
+		 * We report a (luckily) harmless error in this case.
+		 * The issue is that backlog queue processing bypasses
+		 * any hash lookups (we know which socket packets are for).
+		 * The correct behavior here is what 2.0.x did, since
+		 * a TCP_CLOSE socket does not exist.  Drop the frame
+		 * and send a RST back to the other end.
+		 */
+		return 1;
+
 	case TCP_LISTEN:
 		/* These use the socket TOS.. 
 		 * might want to be the received TOS 
@@ -1998,7 +2051,7 @@
 			}
 
 			if(th->rst) {
-				tcp_reset(sk,skb);
+				tcp_reset(sk);
 				goto discard;
 			}
 
@@ -2127,7 +2180,7 @@
 
 	/* step 2: check RST bit */
 	if(th->rst) {
-		tcp_reset(sk,skb);
+		tcp_reset(sk);
 		goto discard;
 	}
 
@@ -2150,7 +2203,7 @@
 	 */
 
 	if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
-		tcp_reset(sk, skb);
+		tcp_reset(sk);
 		return 1;
 	}
 
@@ -2230,7 +2283,7 @@
 		 */
 		if ((sk->shutdown & RCV_SHUTDOWN) && sk->dead) {
 			if (after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
-				tcp_reset(sk, skb);
+				tcp_reset(sk);
 				return 1;
 			}
 		}
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.128/linux/net/ipv4/tcp_output.c	Sun Nov  8 14:03:15 1998
+++ linux/net/ipv4/tcp_output.c	Mon Nov 16 10:39:27 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.96 1998/11/07 10:54:40 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.97 1998/11/08 13:21:27 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -729,9 +729,9 @@
 	struct sk_buff *skb;
 
 	/* NOTE: No TCP options attached and we never retransmit this. */
-	do {
-		skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL);
-	} while(skb == NULL);
+	skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL);
+	if (!skb)
+		return;
 
 	/* Reserve space for headers and prepare control bits. */
 	skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
diff -u --recursive --new-file v2.1.128/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.128/linux/net/ipv4/udp.c	Sun Nov  8 14:03:15 1998
+++ linux/net/ipv4/udp.c	Mon Nov 16 10:39:27 1998
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.63 1998/10/03 09:38:16 davem Exp $
+ * Version:	$Id: udp.c,v 1.64 1998/11/08 11:17:07 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.1.128/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.128/linux/net/ipv6/raw.c	Mon Oct  5 13:13:49 1998
+++ linux/net/ipv6/raw.c	Mon Nov 16 10:39:27 1998
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.22 1998/10/03 09:38:40 davem Exp $
+ *	$Id: raw.c,v 1.23 1998/11/08 11:17:09 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -597,7 +597,7 @@
 }
 
 
-static void rawv6_close(struct sock *sk, unsigned long timeout)
+static void rawv6_close(struct sock *sk, long timeout)
 {
 	/* See for explanation: raw_close in ipv4/raw.c */
 	sk->state = TCP_CLOSE;
diff -u --recursive --new-file v2.1.128/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.128/linux/net/ipv6/udp.c	Mon Oct  5 13:13:49 1998
+++ linux/net/ipv6/udp.c	Mon Nov 16 10:39:27 1998
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.36 1998/10/03 09:38:54 davem Exp $
+ *	$Id: udp.c,v 1.37 1998/11/08 11:17:10 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -308,7 +308,7 @@
 	return(0);
 }
 
-static void udpv6_close(struct sock *sk, unsigned long timeout)
+static void udpv6_close(struct sock *sk, long timeout)
 {
 	/* See for explanation: raw_close in ipv4/raw.c */
 	sk->state = TCP_CLOSE;
diff -u --recursive --new-file v2.1.128/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.128/linux/net/ipx/af_ipx.c	Sat Sep  5 16:46:42 1998
+++ linux/net/ipx/af_ipx.c	Fri Nov 13 10:29:44 1998
@@ -2324,6 +2324,7 @@
 extern void destroy_EII_client(struct datalink_proto *);
 extern void destroy_8023_client(struct datalink_proto *);
 
+#ifdef CONFIG_PROC_FS
 struct proc_dir_entry ipx_procinfo = {
 	PROC_NET_IPX, 3, "ipx", S_IFREG | S_IRUGO,
 	1, 0, 0, 0, &proc_net_inode_operations, ipx_get_info
@@ -2338,6 +2339,7 @@
 	PROC_NET_IPX_ROUTE, 9, "ipx_route", S_IFREG | S_IRUGO,
 	1, 0, 0, 0, &proc_net_inode_operations, ipx_rt_get_info
 };
+#endif
 
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
diff -u --recursive --new-file v2.1.128/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.128/linux/net/netsyms.c	Fri Oct  9 13:27:17 1998
+++ linux/net/netsyms.c	Fri Nov 13 14:45:04 1998
@@ -11,7 +11,13 @@
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/in.h>
+#include <net/sock.h>
+#include <net/dst.h>
+#include <net/checksum.h>
+#include <net/pkt_sched.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
 #include <net/neighbour.h>
@@ -23,8 +29,6 @@
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
-#include <linux/etherdevice.h>
-#include <linux/fddidevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/ip.h>
@@ -34,13 +38,19 @@
 #include <net/route.h>
 #include <net/scm.h>
 #include <net/inet_common.h>
-#include <net/pkt_sched.h>
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
 
 extern struct net_proto_family inet_family_ops;
 
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
+#endif
+
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
 #include <linux/icmpv6.h>
@@ -52,7 +62,6 @@
 extern int tcp_tw_death_row_slot;
 #endif
 
-#endif
 
 #include <linux/rtnetlink.h>
 
@@ -213,9 +222,6 @@
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(ip_options_compile);
 EXPORT_SYMBOL(arp_send);
-#ifdef CONFIG_SHAPER_MODULE
-EXPORT_SYMBOL(arp_broken_ops);
-#endif
 EXPORT_SYMBOL(ip_id_count);
 EXPORT_SYMBOL(ip_send_check);
 EXPORT_SYMBOL(ip_fragment);
@@ -227,6 +233,9 @@
 EXPORT_SYMBOL(inet_dgram_ops);
 EXPORT_SYMBOL(ip_cmsg_recv);
 EXPORT_SYMBOL(__release_sock);
+EXPORT_SYMBOL(arp_find);
+EXPORT_SYMBOL(ip_rcv);
+EXPORT_SYMBOL(arp_rcv);
 
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
@@ -436,12 +445,9 @@
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
-EXPORT_SYMBOL(arp_find);
 EXPORT_SYMBOL(n_tty_ioctl);
 EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(kill_fasync);
-EXPORT_SYMBOL(ip_rcv);
-EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(dev_mc_delete);
 
 EXPORT_SYMBOL(if_port_text);
@@ -451,10 +457,6 @@
 EXPORT_SYMBOL(ltalk_setup);
 #endif
 
-#ifdef CONFIG_DLCI_MODULE
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-EXPORT_SYMBOL(dlci_ioctl_hook);
-#endif
 
 /* Packet scheduler modules want these. */
 EXPORT_SYMBOL(qdisc_destroy);
diff -u --recursive --new-file v2.1.128/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.1.128/linux/net/wanrouter/wanproc.c	Thu Nov 12 16:21:25 1998
+++ linux/net/wanrouter/wanproc.c	Sun Nov 15 09:52:29 1998
@@ -19,6 +19,7 @@
 * Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 *****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
